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

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

unix.superglobalmegacorp.com

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