Annotation of qemu/audio/ossaudio.c, revision 1.1.1.5

1.1       root        1: /*
1.1.1.2   root        2:  * QEMU OSS audio driver
                      3:  *
                      4:  * Copyright (c) 2003-2005 Vassili Karpov (malc)
                      5:  *
1.1       root        6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
1.1.1.4   root       24: #include <stdlib.h>
1.1       root       25: #include <sys/mman.h>
                     26: #include <sys/types.h>
                     27: #include <sys/ioctl.h>
1.1.1.4   root       28: #ifdef __OpenBSD__
                     29: #include <soundcard.h>
                     30: #else
1.1       root       31: #include <sys/soundcard.h>
1.1.1.4   root       32: #endif
                     33: #include "qemu-common.h"
                     34: #include "audio.h"
1.1       root       35: 
1.1.1.2   root       36: #define AUDIO_CAP "oss"
                     37: #include "audio_int.h"
1.1       root       38: 
1.1.1.2   root       39: typedef struct OSSVoiceOut {
                     40:     HWVoiceOut hw;
1.1       root       41:     void *pcm_buf;
                     42:     int fd;
                     43:     int nfrags;
                     44:     int fragsize;
                     45:     int mmapped;
                     46:     int old_optr;
1.1.1.2   root       47: } OSSVoiceOut;
1.1       root       48: 
1.1.1.2   root       49: typedef struct OSSVoiceIn {
                     50:     HWVoiceIn hw;
                     51:     void *pcm_buf;
                     52:     int fd;
                     53:     int nfrags;
                     54:     int fragsize;
                     55:     int old_optr;
                     56: } OSSVoiceIn;
1.1       root       57: 
                     58: static struct {
                     59:     int try_mmap;
                     60:     int nfrags;
                     61:     int fragsize;
1.1.1.2   root       62:     const char *devpath_out;
                     63:     const char *devpath_in;
1.1.1.3   root       64:     int debug;
1.1       root       65: } conf = {
                     66:     .try_mmap = 0,
                     67:     .nfrags = 4,
                     68:     .fragsize = 4096,
1.1.1.2   root       69:     .devpath_out = "/dev/dsp",
1.1.1.3   root       70:     .devpath_in = "/dev/dsp",
                     71:     .debug = 0
1.1       root       72: };
                     73: 
                     74: struct oss_params {
                     75:     int freq;
                     76:     audfmt_e fmt;
                     77:     int nchannels;
                     78:     int nfrags;
                     79:     int fragsize;
                     80: };
                     81: 
1.1.1.2   root       82: static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
                     83: {
                     84:     va_list ap;
                     85: 
                     86:     va_start (ap, fmt);
                     87:     AUD_vlog (AUDIO_CAP, fmt, ap);
                     88:     va_end (ap);
                     89: 
                     90:     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
                     91: }
                     92: 
                     93: static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
                     94:     int err,
                     95:     const char *typ,
                     96:     const char *fmt,
                     97:     ...
                     98:     )
                     99: {
                    100:     va_list ap;
                    101: 
                    102:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
                    103: 
                    104:     va_start (ap, fmt);
                    105:     AUD_vlog (AUDIO_CAP, fmt, ap);
                    106:     va_end (ap);
                    107: 
                    108:     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
                    109: }
                    110: 
                    111: static void oss_anal_close (int *fdp)
                    112: {
                    113:     int err = close (*fdp);
                    114:     if (err) {
                    115:         oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
                    116:     }
                    117:     *fdp = -1;
                    118: }
                    119: 
                    120: static int oss_write (SWVoiceOut *sw, void *buf, int len)
1.1       root      121: {
1.1.1.2   root      122:     return audio_pcm_sw_write (sw, buf, len);
1.1       root      123: }
                    124: 
1.1.1.2   root      125: static int aud_to_ossfmt (audfmt_e fmt)
1.1       root      126: {
                    127:     switch (fmt) {
1.1.1.2   root      128:     case AUD_FMT_S8:
                    129:         return AFMT_S8;
                    130: 
                    131:     case AUD_FMT_U8:
                    132:         return AFMT_U8;
                    133: 
                    134:     case AUD_FMT_S16:
                    135:         return AFMT_S16_LE;
                    136: 
                    137:     case AUD_FMT_U16:
                    138:         return AFMT_U16_LE;
                    139: 
1.1       root      140:     default:
1.1.1.2   root      141:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
                    142: #ifdef DEBUG_AUDIO
                    143:         abort ();
                    144: #endif
                    145:         return AFMT_U8;
1.1       root      146:     }
                    147: }
                    148: 
1.1.1.2   root      149: static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
1.1       root      150: {
1.1.1.2   root      151:     switch (ossfmt) {
                    152:     case AFMT_S8:
1.1.1.5 ! root      153:         *endianness = 0;
1.1.1.2   root      154:         *fmt = AUD_FMT_S8;
                    155:         break;
                    156: 
                    157:     case AFMT_U8:
                    158:         *endianness = 0;
                    159:         *fmt = AUD_FMT_U8;
                    160:         break;
                    161: 
                    162:     case AFMT_S16_LE:
                    163:         *endianness = 0;
                    164:         *fmt = AUD_FMT_S16;
                    165:         break;
                    166: 
                    167:     case AFMT_U16_LE:
                    168:         *endianness = 0;
                    169:         *fmt = AUD_FMT_U16;
                    170:         break;
                    171: 
                    172:     case AFMT_S16_BE:
                    173:         *endianness = 1;
                    174:         *fmt = AUD_FMT_S16;
                    175:         break;
                    176: 
                    177:     case AFMT_U16_BE:
                    178:         *endianness = 1;
                    179:         *fmt = AUD_FMT_U16;
                    180:         break;
                    181: 
1.1       root      182:     default:
1.1.1.2   root      183:         dolog ("Unrecognized audio format %d\n", ossfmt);
                    184:         return -1;
1.1       root      185:     }
1.1.1.2   root      186: 
                    187:     return 0;
1.1       root      188: }
                    189: 
1.1.1.2   root      190: #if defined DEBUG_MISMATCHES || defined DEBUG
                    191: static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
1.1       root      192: {
                    193:     dolog ("parameter | requested value | obtained value\n");
                    194:     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
1.1.1.2   root      195:     dolog ("channels  |      %10d |     %10d\n",
                    196:            req->nchannels, obt->nchannels);
1.1       root      197:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
                    198:     dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
1.1.1.2   root      199:     dolog ("fragsize  |      %10d |     %10d\n",
                    200:            req->fragsize, obt->fragsize);
1.1       root      201: }
                    202: #endif
                    203: 
1.1.1.2   root      204: static int oss_open (int in, struct oss_params *req,
                    205:                      struct oss_params *obt, int *pfd)
1.1       root      206: {
                    207:     int fd;
                    208:     int mmmmssss;
                    209:     audio_buf_info abinfo;
                    210:     int fmt, freq, nchannels;
1.1.1.2   root      211:     const char *dspname = in ? conf.devpath_in : conf.devpath_out;
                    212:     const char *typ = in ? "ADC" : "DAC";
1.1       root      213: 
1.1.1.2   root      214:     fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
1.1       root      215:     if (-1 == fd) {
1.1.1.2   root      216:         oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
1.1       root      217:         return -1;
                    218:     }
                    219: 
                    220:     freq = req->freq;
                    221:     nchannels = req->nchannels;
                    222:     fmt = req->fmt;
                    223: 
                    224:     if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
1.1.1.2   root      225:         oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
1.1       root      226:         goto err;
                    227:     }
                    228: 
                    229:     if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
1.1.1.2   root      230:         oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
                    231:                      req->nchannels);
1.1       root      232:         goto err;
                    233:     }
                    234: 
                    235:     if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
1.1.1.2   root      236:         oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
1.1       root      237:         goto err;
                    238:     }
                    239: 
1.1.1.5 ! root      240:     if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
1.1.1.2   root      241:         oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
1.1       root      242:         goto err;
                    243:     }
                    244: 
                    245:     mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
                    246:     if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
1.1.1.2   root      247:         oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
                    248:                      req->nfrags, req->fragsize);
1.1       root      249:         goto err;
                    250:     }
                    251: 
1.1.1.2   root      252:     if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
                    253:         oss_logerr2 (errno, typ, "Failed to get buffer length\n");
1.1       root      254:         goto err;
                    255:     }
                    256: 
1.1.1.5 ! root      257:     if (!abinfo.fragstotal || !abinfo.fragsize) {
        !           258:         AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
        !           259:                  abinfo.fragstotal, abinfo.fragsize, typ);
        !           260:         goto err;
        !           261:     }
        !           262: 
1.1       root      263:     obt->fmt = fmt;
                    264:     obt->nchannels = nchannels;
                    265:     obt->freq = freq;
                    266:     obt->nfrags = abinfo.fragstotal;
                    267:     obt->fragsize = abinfo.fragsize;
                    268:     *pfd = fd;
                    269: 
1.1.1.2   root      270: #ifdef DEBUG_MISMATCHES
1.1       root      271:     if ((req->fmt != obt->fmt) ||
                    272:         (req->nchannels != obt->nchannels) ||
                    273:         (req->freq != obt->freq) ||
                    274:         (req->fragsize != obt->fragsize) ||
                    275:         (req->nfrags != obt->nfrags)) {
                    276:         dolog ("Audio parameters mismatch\n");
1.1.1.2   root      277:         oss_dump_info (req, obt);
1.1       root      278:     }
1.1.1.2   root      279: #endif
1.1       root      280: 
1.1.1.2   root      281: #ifdef DEBUG
                    282:     oss_dump_info (req, obt);
1.1       root      283: #endif
                    284:     return 0;
                    285: 
1.1.1.2   root      286:  err:
                    287:     oss_anal_close (&fd);
1.1       root      288:     return -1;
                    289: }
                    290: 
1.1.1.2   root      291: static int oss_run_out (HWVoiceOut *hw)
1.1       root      292: {
1.1.1.2   root      293:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      294:     int err, rpos, live, decr;
                    295:     int samples;
                    296:     uint8_t *dst;
1.1.1.5 ! root      297:     struct st_sample *src;
1.1       root      298:     struct audio_buf_info abinfo;
                    299:     struct count_info cntinfo;
1.1.1.2   root      300:     int bufsize;
                    301: 
                    302:     live = audio_pcm_hw_get_live_out (hw);
                    303:     if (!live) {
                    304:         return 0;
                    305:     }
1.1       root      306: 
1.1.1.2   root      307:     bufsize = hw->samples << hw->info.shift;
1.1       root      308: 
                    309:     if (oss->mmapped) {
                    310:         int bytes;
                    311: 
                    312:         err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
                    313:         if (err < 0) {
1.1.1.2   root      314:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
                    315:             return 0;
1.1       root      316:         }
                    317: 
                    318:         if (cntinfo.ptr == oss->old_optr) {
1.1.1.2   root      319:             if (abs (hw->samples - live) < 64) {
                    320:                 dolog ("warning: Overrun\n");
                    321:             }
                    322:             return 0;
1.1       root      323:         }
                    324: 
                    325:         if (cntinfo.ptr > oss->old_optr) {
                    326:             bytes = cntinfo.ptr - oss->old_optr;
                    327:         }
                    328:         else {
1.1.1.2   root      329:             bytes = bufsize + cntinfo.ptr - oss->old_optr;
1.1       root      330:         }
                    331: 
1.1.1.2   root      332:         decr = audio_MIN (bytes >> hw->info.shift, live);
1.1       root      333:     }
                    334:     else {
                    335:         err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
                    336:         if (err < 0) {
1.1.1.2   root      337:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
                    338:             return 0;
                    339:         }
                    340: 
1.1.1.3   root      341:         if (abinfo.bytes > bufsize) {
                    342:             if (conf.debug) {
                    343:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
                    344:                        "please report your OS/audio hw to [email protected]\n",
                    345:                        abinfo.bytes, bufsize);
                    346:             }
                    347:             abinfo.bytes = bufsize;
                    348:         }
                    349: 
                    350:         if (abinfo.bytes < 0) {
                    351:             if (conf.debug) {
                    352:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
                    353:                        abinfo.bytes, bufsize);
                    354:             }
1.1.1.2   root      355:             return 0;
1.1       root      356:         }
                    357: 
1.1.1.2   root      358:         decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
                    359:         if (!decr) {
                    360:             return 0;
                    361:         }
1.1       root      362:     }
                    363: 
                    364:     samples = decr;
                    365:     rpos = hw->rpos;
                    366:     while (samples) {
                    367:         int left_till_end_samples = hw->samples - rpos;
                    368:         int convert_samples = audio_MIN (samples, left_till_end_samples);
                    369: 
1.1.1.2   root      370:         src = hw->mix_buf + rpos;
                    371:         dst = advance (oss->pcm_buf, rpos << hw->info.shift);
1.1       root      372: 
                    373:         hw->clip (dst, src, convert_samples);
                    374:         if (!oss->mmapped) {
                    375:             int written;
                    376: 
1.1.1.2   root      377:             written = write (oss->fd, dst, convert_samples << hw->info.shift);
1.1       root      378:             /* XXX: follow errno recommendations ? */
                    379:             if (written == -1) {
1.1.1.2   root      380:                 oss_logerr (
                    381:                     errno,
                    382:                     "Failed to write %d bytes of audio data from %p\n",
                    383:                     convert_samples << hw->info.shift,
                    384:                     dst
                    385:                     );
1.1       root      386:                 continue;
                    387:             }
                    388: 
1.1.1.2   root      389:             if (written != convert_samples << hw->info.shift) {
                    390:                 int wsamples = written >> hw->info.shift;
                    391:                 int wbytes = wsamples << hw->info.shift;
1.1       root      392:                 if (wbytes != written) {
1.1.1.2   root      393:                     dolog ("warning: Misaligned write %d (requested %d), "
                    394:                            "alignment %d\n",
                    395:                            wbytes, written, hw->info.align + 1);
1.1       root      396:                 }
1.1.1.2   root      397:                 decr -= wsamples;
1.1       root      398:                 rpos = (rpos + wsamples) % hw->samples;
                    399:                 break;
                    400:             }
                    401:         }
1.1.1.2   root      402: 
1.1       root      403:         rpos = (rpos + convert_samples) % hw->samples;
                    404:         samples -= convert_samples;
                    405:     }
                    406:     if (oss->mmapped) {
                    407:         oss->old_optr = cntinfo.ptr;
                    408:     }
                    409: 
                    410:     hw->rpos = rpos;
1.1.1.2   root      411:     return decr;
1.1       root      412: }
                    413: 
1.1.1.2   root      414: static void oss_fini_out (HWVoiceOut *hw)
1.1       root      415: {
                    416:     int err;
1.1.1.2   root      417:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      418: 
1.1.1.2   root      419:     ldebug ("oss_fini\n");
                    420:     oss_anal_close (&oss->fd);
1.1       root      421: 
                    422:     if (oss->pcm_buf) {
                    423:         if (oss->mmapped) {
1.1.1.2   root      424:             err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      425:             if (err) {
1.1.1.2   root      426:                 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
                    427:                             oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      428:             }
                    429:         }
                    430:         else {
                    431:             qemu_free (oss->pcm_buf);
                    432:         }
                    433:         oss->pcm_buf = NULL;
                    434:     }
                    435: }
                    436: 
1.1.1.5 ! root      437: static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1       root      438: {
1.1.1.2   root      439:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      440:     struct oss_params req, obt;
1.1.1.2   root      441:     int endianness;
                    442:     int err;
                    443:     int fd;
                    444:     audfmt_e effective_fmt;
1.1.1.5 ! root      445:     struct audsettings obt_as;
1.1.1.2   root      446: 
                    447:     oss->fd = -1;
1.1       root      448: 
1.1.1.2   root      449:     req.fmt = aud_to_ossfmt (as->fmt);
                    450:     req.freq = as->freq;
                    451:     req.nchannels = as->nchannels;
1.1       root      452:     req.fragsize = conf.fragsize;
                    453:     req.nfrags = conf.nfrags;
                    454: 
1.1.1.2   root      455:     if (oss_open (0, &req, &obt, &fd)) {
1.1       root      456:         return -1;
1.1.1.2   root      457:     }
1.1       root      458: 
1.1.1.2   root      459:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    460:     if (err) {
                    461:         oss_anal_close (&fd);
                    462:         return -1;
                    463:     }
1.1       root      464: 
1.1.1.2   root      465:     obt_as.freq = obt.freq;
                    466:     obt_as.nchannels = obt.nchannels;
                    467:     obt_as.fmt = effective_fmt;
1.1.1.3   root      468:     obt_as.endianness = endianness;
1.1.1.2   root      469: 
1.1.1.3   root      470:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      471:     oss->nfrags = obt.nfrags;
                    472:     oss->fragsize = obt.fragsize;
1.1.1.2   root      473: 
                    474:     if (obt.nfrags * obt.fragsize & hw->info.align) {
                    475:         dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
                    476:                obt.nfrags * obt.fragsize, hw->info.align + 1);
                    477:     }
                    478: 
                    479:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
1.1       root      480: 
                    481:     oss->mmapped = 0;
                    482:     if (conf.try_mmap) {
1.1.1.2   root      483:         oss->pcm_buf = mmap (
                    484:             0,
                    485:             hw->samples << hw->info.shift,
                    486:             PROT_READ | PROT_WRITE,
                    487:             MAP_SHARED,
                    488:             fd,
                    489:             0
                    490:             );
1.1       root      491:         if (oss->pcm_buf == MAP_FAILED) {
1.1.1.2   root      492:             oss_logerr (errno, "Failed to map %d bytes of DAC\n",
                    493:                         hw->samples << hw->info.shift);
1.1       root      494:         } else {
                    495:             int err;
                    496:             int trig = 0;
1.1.1.2   root      497:             if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    498:                 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
1.1       root      499:             }
                    500:             else {
                    501:                 trig = PCM_ENABLE_OUTPUT;
1.1.1.2   root      502:                 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    503:                     oss_logerr (
                    504:                         errno,
                    505:                         "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
                    506:                         );
1.1       root      507:                 }
                    508:                 else {
                    509:                     oss->mmapped = 1;
                    510:                 }
                    511:             }
                    512: 
                    513:             if (!oss->mmapped) {
1.1.1.2   root      514:                 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      515:                 if (err) {
1.1.1.2   root      516:                     oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
                    517:                                 oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      518:                 }
                    519:             }
                    520:         }
                    521:     }
                    522: 
                    523:     if (!oss->mmapped) {
1.1.1.2   root      524:         oss->pcm_buf = audio_calloc (
                    525:             AUDIO_FUNC,
                    526:             hw->samples,
                    527:             1 << hw->info.shift
                    528:             );
1.1       root      529:         if (!oss->pcm_buf) {
1.1.1.2   root      530:             dolog (
                    531:                 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    532:                 hw->samples,
                    533:                 1 << hw->info.shift
                    534:                 );
                    535:             oss_anal_close (&fd);
1.1       root      536:             return -1;
                    537:         }
                    538:     }
                    539: 
1.1.1.2   root      540:     oss->fd = fd;
1.1       root      541:     return 0;
                    542: }
                    543: 
1.1.1.2   root      544: static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1       root      545: {
                    546:     int trig;
1.1.1.2   root      547:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      548: 
1.1.1.2   root      549:     if (!oss->mmapped) {
1.1       root      550:         return 0;
1.1.1.2   root      551:     }
1.1       root      552: 
                    553:     switch (cmd) {
                    554:     case VOICE_ENABLE:
                    555:         ldebug ("enabling voice\n");
1.1.1.2   root      556:         audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
1.1       root      557:         trig = PCM_ENABLE_OUTPUT;
                    558:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
1.1.1.2   root      559:             oss_logerr (
                    560:                 errno,
                    561:                 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
                    562:                 );
1.1       root      563:             return -1;
                    564:         }
                    565:         break;
                    566: 
                    567:     case VOICE_DISABLE:
                    568:         ldebug ("disabling voice\n");
                    569:         trig = 0;
                    570:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
1.1.1.2   root      571:             oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
1.1       root      572:             return -1;
                    573:         }
                    574:         break;
                    575:     }
                    576:     return 0;
                    577: }
                    578: 
1.1.1.5 ! root      579: static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
1.1.1.2   root      580: {
                    581:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    582:     struct oss_params req, obt;
                    583:     int endianness;
                    584:     int err;
                    585:     int fd;
                    586:     audfmt_e effective_fmt;
1.1.1.5 ! root      587:     struct audsettings obt_as;
1.1.1.2   root      588: 
                    589:     oss->fd = -1;
                    590: 
                    591:     req.fmt = aud_to_ossfmt (as->fmt);
                    592:     req.freq = as->freq;
                    593:     req.nchannels = as->nchannels;
                    594:     req.fragsize = conf.fragsize;
                    595:     req.nfrags = conf.nfrags;
                    596:     if (oss_open (1, &req, &obt, &fd)) {
                    597:         return -1;
                    598:     }
                    599: 
                    600:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    601:     if (err) {
                    602:         oss_anal_close (&fd);
                    603:         return -1;
                    604:     }
                    605: 
                    606:     obt_as.freq = obt.freq;
                    607:     obt_as.nchannels = obt.nchannels;
                    608:     obt_as.fmt = effective_fmt;
1.1.1.3   root      609:     obt_as.endianness = endianness;
1.1.1.2   root      610: 
1.1.1.3   root      611:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2   root      612:     oss->nfrags = obt.nfrags;
                    613:     oss->fragsize = obt.fragsize;
                    614: 
                    615:     if (obt.nfrags * obt.fragsize & hw->info.align) {
                    616:         dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
                    617:                obt.nfrags * obt.fragsize, hw->info.align + 1);
                    618:     }
                    619: 
                    620:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
                    621:     oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    622:     if (!oss->pcm_buf) {
                    623:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    624:                hw->samples, 1 << hw->info.shift);
                    625:         oss_anal_close (&fd);
                    626:         return -1;
                    627:     }
                    628: 
                    629:     oss->fd = fd;
                    630:     return 0;
                    631: }
                    632: 
                    633: static void oss_fini_in (HWVoiceIn *hw)
                    634: {
                    635:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    636: 
                    637:     oss_anal_close (&oss->fd);
                    638: 
                    639:     if (oss->pcm_buf) {
                    640:         qemu_free (oss->pcm_buf);
                    641:         oss->pcm_buf = NULL;
                    642:     }
                    643: }
                    644: 
                    645: static int oss_run_in (HWVoiceIn *hw)
                    646: {
                    647:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    648:     int hwshift = hw->info.shift;
                    649:     int i;
                    650:     int live = audio_pcm_hw_get_live_in (hw);
                    651:     int dead = hw->samples - live;
                    652:     size_t read_samples = 0;
                    653:     struct {
                    654:         int add;
                    655:         int len;
                    656:     } bufs[2] = {
                    657:         { hw->wpos, 0 },
                    658:         { 0, 0 }
                    659:     };
                    660: 
                    661:     if (!dead) {
                    662:         return 0;
                    663:     }
                    664: 
                    665:     if (hw->wpos + dead > hw->samples) {
                    666:         bufs[0].len = (hw->samples - hw->wpos) << hwshift;
                    667:         bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
                    668:     }
                    669:     else {
                    670:         bufs[0].len = dead << hwshift;
                    671:     }
                    672: 
                    673: 
                    674:     for (i = 0; i < 2; ++i) {
                    675:         ssize_t nread;
                    676: 
                    677:         if (bufs[i].len) {
                    678:             void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
                    679:             nread = read (oss->fd, p, bufs[i].len);
                    680: 
                    681:             if (nread > 0) {
                    682:                 if (nread & hw->info.align) {
                    683:                     dolog ("warning: Misaligned read %zd (requested %d), "
                    684:                            "alignment %d\n", nread, bufs[i].add << hwshift,
                    685:                            hw->info.align + 1);
                    686:                 }
                    687:                 read_samples += nread >> hwshift;
                    688:                 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
                    689:                           &nominal_volume);
                    690:             }
                    691: 
                    692:             if (bufs[i].len - nread) {
                    693:                 if (nread == -1) {
                    694:                     switch (errno) {
                    695:                     case EINTR:
                    696:                     case EAGAIN:
                    697:                         break;
                    698:                     default:
                    699:                         oss_logerr (
                    700:                             errno,
                    701:                             "Failed to read %d bytes of audio (to %p)\n",
                    702:                             bufs[i].len, p
                    703:                             );
                    704:                         break;
                    705:                     }
                    706:                 }
                    707:                 break;
                    708:             }
                    709:         }
                    710:     }
                    711: 
                    712:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                    713:     return read_samples;
                    714: }
                    715: 
                    716: static int oss_read (SWVoiceIn *sw, void *buf, int size)
                    717: {
                    718:     return audio_pcm_sw_read (sw, buf, size);
                    719: }
                    720: 
                    721: static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    722: {
                    723:     (void) hw;
                    724:     (void) cmd;
                    725:     return 0;
                    726: }
                    727: 
1.1       root      728: static void *oss_audio_init (void)
                    729: {
                    730:     return &conf;
                    731: }
                    732: 
                    733: static void oss_audio_fini (void *opaque)
                    734: {
1.1.1.2   root      735:     (void) opaque;
1.1       root      736: }
                    737: 
1.1.1.2   root      738: static struct audio_option oss_options[] = {
                    739:     {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
                    740:      "Fragment size in bytes", NULL, 0},
                    741:     {"NFRAGS", AUD_OPT_INT, &conf.nfrags,
                    742:      "Number of fragments", NULL, 0},
                    743:     {"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
                    744:      "Try using memory mapped access", NULL, 0},
                    745:     {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
                    746:      "Path to DAC device", NULL, 0},
                    747:     {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
                    748:      "Path to ADC device", NULL, 0},
1.1.1.3   root      749:     {"DEBUG", AUD_OPT_BOOL, &conf.debug,
                    750:      "Turn on some debugging messages", NULL, 0},
1.1.1.2   root      751:     {NULL, 0, NULL, NULL, NULL, 0}
                    752: };
                    753: 
                    754: static struct audio_pcm_ops oss_pcm_ops = {
                    755:     oss_init_out,
                    756:     oss_fini_out,
                    757:     oss_run_out,
                    758:     oss_write,
                    759:     oss_ctl_out,
                    760: 
                    761:     oss_init_in,
                    762:     oss_fini_in,
                    763:     oss_run_in,
                    764:     oss_read,
                    765:     oss_ctl_in
1.1       root      766: };
                    767: 
1.1.1.2   root      768: struct audio_driver oss_audio_driver = {
                    769:     INIT_FIELD (name           = ) "oss",
                    770:     INIT_FIELD (descr          = ) "OSS http://www.opensound.com",
                    771:     INIT_FIELD (options        = ) oss_options,
                    772:     INIT_FIELD (init           = ) oss_audio_init,
                    773:     INIT_FIELD (fini           = ) oss_audio_fini,
                    774:     INIT_FIELD (pcm_ops        = ) &oss_pcm_ops,
                    775:     INIT_FIELD (can_be_default = ) 1,
                    776:     INIT_FIELD (max_voices_out = ) INT_MAX,
                    777:     INIT_FIELD (max_voices_in  = ) INT_MAX,
                    778:     INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
                    779:     INIT_FIELD (voice_size_in  = ) sizeof (OSSVoiceIn)
1.1       root      780: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.