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

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

unix.superglobalmegacorp.com

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