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

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:
                    153:         *endianness =0;
                    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: 
                    240:     if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
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: 
                    257:     obt->fmt = fmt;
                    258:     obt->nchannels = nchannels;
                    259:     obt->freq = freq;
                    260:     obt->nfrags = abinfo.fragstotal;
                    261:     obt->fragsize = abinfo.fragsize;
                    262:     *pfd = fd;
                    263: 
1.1.1.2   root      264: #ifdef DEBUG_MISMATCHES
1.1       root      265:     if ((req->fmt != obt->fmt) ||
                    266:         (req->nchannels != obt->nchannels) ||
                    267:         (req->freq != obt->freq) ||
                    268:         (req->fragsize != obt->fragsize) ||
                    269:         (req->nfrags != obt->nfrags)) {
                    270:         dolog ("Audio parameters mismatch\n");
1.1.1.2   root      271:         oss_dump_info (req, obt);
1.1       root      272:     }
1.1.1.2   root      273: #endif
1.1       root      274: 
1.1.1.2   root      275: #ifdef DEBUG
                    276:     oss_dump_info (req, obt);
1.1       root      277: #endif
                    278:     return 0;
                    279: 
1.1.1.2   root      280:  err:
                    281:     oss_anal_close (&fd);
1.1       root      282:     return -1;
                    283: }
                    284: 
1.1.1.2   root      285: static int oss_run_out (HWVoiceOut *hw)
1.1       root      286: {
1.1.1.2   root      287:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      288:     int err, rpos, live, decr;
                    289:     int samples;
                    290:     uint8_t *dst;
                    291:     st_sample_t *src;
                    292:     struct audio_buf_info abinfo;
                    293:     struct count_info cntinfo;
1.1.1.2   root      294:     int bufsize;
                    295: 
                    296:     live = audio_pcm_hw_get_live_out (hw);
                    297:     if (!live) {
                    298:         return 0;
                    299:     }
1.1       root      300: 
1.1.1.2   root      301:     bufsize = hw->samples << hw->info.shift;
1.1       root      302: 
                    303:     if (oss->mmapped) {
                    304:         int bytes;
                    305: 
                    306:         err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
                    307:         if (err < 0) {
1.1.1.2   root      308:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
                    309:             return 0;
1.1       root      310:         }
                    311: 
                    312:         if (cntinfo.ptr == oss->old_optr) {
1.1.1.2   root      313:             if (abs (hw->samples - live) < 64) {
                    314:                 dolog ("warning: Overrun\n");
                    315:             }
                    316:             return 0;
1.1       root      317:         }
                    318: 
                    319:         if (cntinfo.ptr > oss->old_optr) {
                    320:             bytes = cntinfo.ptr - oss->old_optr;
                    321:         }
                    322:         else {
1.1.1.2   root      323:             bytes = bufsize + cntinfo.ptr - oss->old_optr;
1.1       root      324:         }
                    325: 
1.1.1.2   root      326:         decr = audio_MIN (bytes >> hw->info.shift, live);
1.1       root      327:     }
                    328:     else {
                    329:         err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
                    330:         if (err < 0) {
1.1.1.2   root      331:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
                    332:             return 0;
                    333:         }
                    334: 
1.1.1.3   root      335:         if (abinfo.bytes > bufsize) {
                    336:             if (conf.debug) {
                    337:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
                    338:                        "please report your OS/audio hw to [email protected]\n",
                    339:                        abinfo.bytes, bufsize);
                    340:             }
                    341:             abinfo.bytes = bufsize;
                    342:         }
                    343: 
                    344:         if (abinfo.bytes < 0) {
                    345:             if (conf.debug) {
                    346:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
                    347:                        abinfo.bytes, bufsize);
                    348:             }
1.1.1.2   root      349:             return 0;
1.1       root      350:         }
                    351: 
1.1.1.2   root      352:         decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
                    353:         if (!decr) {
                    354:             return 0;
                    355:         }
1.1       root      356:     }
                    357: 
                    358:     samples = decr;
                    359:     rpos = hw->rpos;
                    360:     while (samples) {
                    361:         int left_till_end_samples = hw->samples - rpos;
                    362:         int convert_samples = audio_MIN (samples, left_till_end_samples);
                    363: 
1.1.1.2   root      364:         src = hw->mix_buf + rpos;
                    365:         dst = advance (oss->pcm_buf, rpos << hw->info.shift);
1.1       root      366: 
                    367:         hw->clip (dst, src, convert_samples);
                    368:         if (!oss->mmapped) {
                    369:             int written;
                    370: 
1.1.1.2   root      371:             written = write (oss->fd, dst, convert_samples << hw->info.shift);
1.1       root      372:             /* XXX: follow errno recommendations ? */
                    373:             if (written == -1) {
1.1.1.2   root      374:                 oss_logerr (
                    375:                     errno,
                    376:                     "Failed to write %d bytes of audio data from %p\n",
                    377:                     convert_samples << hw->info.shift,
                    378:                     dst
                    379:                     );
1.1       root      380:                 continue;
                    381:             }
                    382: 
1.1.1.2   root      383:             if (written != convert_samples << hw->info.shift) {
                    384:                 int wsamples = written >> hw->info.shift;
                    385:                 int wbytes = wsamples << hw->info.shift;
1.1       root      386:                 if (wbytes != written) {
1.1.1.2   root      387:                     dolog ("warning: Misaligned write %d (requested %d), "
                    388:                            "alignment %d\n",
                    389:                            wbytes, written, hw->info.align + 1);
1.1       root      390:                 }
1.1.1.2   root      391:                 decr -= wsamples;
1.1       root      392:                 rpos = (rpos + wsamples) % hw->samples;
                    393:                 break;
                    394:             }
                    395:         }
1.1.1.2   root      396: 
1.1       root      397:         rpos = (rpos + convert_samples) % hw->samples;
                    398:         samples -= convert_samples;
                    399:     }
                    400:     if (oss->mmapped) {
                    401:         oss->old_optr = cntinfo.ptr;
                    402:     }
                    403: 
                    404:     hw->rpos = rpos;
1.1.1.2   root      405:     return decr;
1.1       root      406: }
                    407: 
1.1.1.2   root      408: static void oss_fini_out (HWVoiceOut *hw)
1.1       root      409: {
                    410:     int err;
1.1.1.2   root      411:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      412: 
1.1.1.2   root      413:     ldebug ("oss_fini\n");
                    414:     oss_anal_close (&oss->fd);
1.1       root      415: 
                    416:     if (oss->pcm_buf) {
                    417:         if (oss->mmapped) {
1.1.1.2   root      418:             err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      419:             if (err) {
1.1.1.2   root      420:                 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
                    421:                             oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      422:             }
                    423:         }
                    424:         else {
                    425:             qemu_free (oss->pcm_buf);
                    426:         }
                    427:         oss->pcm_buf = NULL;
                    428:     }
                    429: }
                    430: 
1.1.1.2   root      431: static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
1.1       root      432: {
1.1.1.2   root      433:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      434:     struct oss_params req, obt;
1.1.1.2   root      435:     int endianness;
                    436:     int err;
                    437:     int fd;
                    438:     audfmt_e effective_fmt;
                    439:     audsettings_t obt_as;
                    440: 
                    441:     oss->fd = -1;
1.1       root      442: 
1.1.1.2   root      443:     req.fmt = aud_to_ossfmt (as->fmt);
                    444:     req.freq = as->freq;
                    445:     req.nchannels = as->nchannels;
1.1       root      446:     req.fragsize = conf.fragsize;
                    447:     req.nfrags = conf.nfrags;
                    448: 
1.1.1.2   root      449:     if (oss_open (0, &req, &obt, &fd)) {
1.1       root      450:         return -1;
1.1.1.2   root      451:     }
1.1       root      452: 
1.1.1.2   root      453:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    454:     if (err) {
                    455:         oss_anal_close (&fd);
                    456:         return -1;
                    457:     }
1.1       root      458: 
1.1.1.2   root      459:     obt_as.freq = obt.freq;
                    460:     obt_as.nchannels = obt.nchannels;
                    461:     obt_as.fmt = effective_fmt;
1.1.1.3   root      462:     obt_as.endianness = endianness;
1.1.1.2   root      463: 
1.1.1.3   root      464:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      465:     oss->nfrags = obt.nfrags;
                    466:     oss->fragsize = obt.fragsize;
1.1.1.2   root      467: 
                    468:     if (obt.nfrags * obt.fragsize & hw->info.align) {
                    469:         dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
                    470:                obt.nfrags * obt.fragsize, hw->info.align + 1);
                    471:     }
                    472: 
                    473:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
1.1       root      474: 
                    475:     oss->mmapped = 0;
                    476:     if (conf.try_mmap) {
1.1.1.2   root      477:         oss->pcm_buf = mmap (
                    478:             0,
                    479:             hw->samples << hw->info.shift,
                    480:             PROT_READ | PROT_WRITE,
                    481:             MAP_SHARED,
                    482:             fd,
                    483:             0
                    484:             );
1.1       root      485:         if (oss->pcm_buf == MAP_FAILED) {
1.1.1.2   root      486:             oss_logerr (errno, "Failed to map %d bytes of DAC\n",
                    487:                         hw->samples << hw->info.shift);
1.1       root      488:         } else {
                    489:             int err;
                    490:             int trig = 0;
1.1.1.2   root      491:             if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    492:                 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
1.1       root      493:             }
                    494:             else {
                    495:                 trig = PCM_ENABLE_OUTPUT;
1.1.1.2   root      496:                 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    497:                     oss_logerr (
                    498:                         errno,
                    499:                         "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
                    500:                         );
1.1       root      501:                 }
                    502:                 else {
                    503:                     oss->mmapped = 1;
                    504:                 }
                    505:             }
                    506: 
                    507:             if (!oss->mmapped) {
1.1.1.2   root      508:                 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      509:                 if (err) {
1.1.1.2   root      510:                     oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
                    511:                                 oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      512:                 }
                    513:             }
                    514:         }
                    515:     }
                    516: 
                    517:     if (!oss->mmapped) {
1.1.1.2   root      518:         oss->pcm_buf = audio_calloc (
                    519:             AUDIO_FUNC,
                    520:             hw->samples,
                    521:             1 << hw->info.shift
                    522:             );
1.1       root      523:         if (!oss->pcm_buf) {
1.1.1.2   root      524:             dolog (
                    525:                 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    526:                 hw->samples,
                    527:                 1 << hw->info.shift
                    528:                 );
                    529:             oss_anal_close (&fd);
1.1       root      530:             return -1;
                    531:         }
                    532:     }
                    533: 
1.1.1.2   root      534:     oss->fd = fd;
1.1       root      535:     return 0;
                    536: }
                    537: 
1.1.1.2   root      538: static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1       root      539: {
                    540:     int trig;
1.1.1.2   root      541:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      542: 
1.1.1.2   root      543:     if (!oss->mmapped) {
1.1       root      544:         return 0;
1.1.1.2   root      545:     }
1.1       root      546: 
                    547:     switch (cmd) {
                    548:     case VOICE_ENABLE:
                    549:         ldebug ("enabling voice\n");
1.1.1.2   root      550:         audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
1.1       root      551:         trig = PCM_ENABLE_OUTPUT;
                    552:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
1.1.1.2   root      553:             oss_logerr (
                    554:                 errno,
                    555:                 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
                    556:                 );
1.1       root      557:             return -1;
                    558:         }
                    559:         break;
                    560: 
                    561:     case VOICE_DISABLE:
                    562:         ldebug ("disabling voice\n");
                    563:         trig = 0;
                    564:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
1.1.1.2   root      565:             oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
1.1       root      566:             return -1;
                    567:         }
                    568:         break;
                    569:     }
                    570:     return 0;
                    571: }
                    572: 
1.1.1.2   root      573: static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
                    574: {
                    575:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    576:     struct oss_params req, obt;
                    577:     int endianness;
                    578:     int err;
                    579:     int fd;
                    580:     audfmt_e effective_fmt;
                    581:     audsettings_t obt_as;
                    582: 
                    583:     oss->fd = -1;
                    584: 
                    585:     req.fmt = aud_to_ossfmt (as->fmt);
                    586:     req.freq = as->freq;
                    587:     req.nchannels = as->nchannels;
                    588:     req.fragsize = conf.fragsize;
                    589:     req.nfrags = conf.nfrags;
                    590:     if (oss_open (1, &req, &obt, &fd)) {
                    591:         return -1;
                    592:     }
                    593: 
                    594:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    595:     if (err) {
                    596:         oss_anal_close (&fd);
                    597:         return -1;
                    598:     }
                    599: 
                    600:     obt_as.freq = obt.freq;
                    601:     obt_as.nchannels = obt.nchannels;
                    602:     obt_as.fmt = effective_fmt;
1.1.1.3   root      603:     obt_as.endianness = endianness;
1.1.1.2   root      604: 
1.1.1.3   root      605:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2   root      606:     oss->nfrags = obt.nfrags;
                    607:     oss->fragsize = obt.fragsize;
                    608: 
                    609:     if (obt.nfrags * obt.fragsize & hw->info.align) {
                    610:         dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
                    611:                obt.nfrags * obt.fragsize, hw->info.align + 1);
                    612:     }
                    613: 
                    614:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
                    615:     oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    616:     if (!oss->pcm_buf) {
                    617:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    618:                hw->samples, 1 << hw->info.shift);
                    619:         oss_anal_close (&fd);
                    620:         return -1;
                    621:     }
                    622: 
                    623:     oss->fd = fd;
                    624:     return 0;
                    625: }
                    626: 
                    627: static void oss_fini_in (HWVoiceIn *hw)
                    628: {
                    629:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    630: 
                    631:     oss_anal_close (&oss->fd);
                    632: 
                    633:     if (oss->pcm_buf) {
                    634:         qemu_free (oss->pcm_buf);
                    635:         oss->pcm_buf = NULL;
                    636:     }
                    637: }
                    638: 
                    639: static int oss_run_in (HWVoiceIn *hw)
                    640: {
                    641:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    642:     int hwshift = hw->info.shift;
                    643:     int i;
                    644:     int live = audio_pcm_hw_get_live_in (hw);
                    645:     int dead = hw->samples - live;
                    646:     size_t read_samples = 0;
                    647:     struct {
                    648:         int add;
                    649:         int len;
                    650:     } bufs[2] = {
                    651:         { hw->wpos, 0 },
                    652:         { 0, 0 }
                    653:     };
                    654: 
                    655:     if (!dead) {
                    656:         return 0;
                    657:     }
                    658: 
                    659:     if (hw->wpos + dead > hw->samples) {
                    660:         bufs[0].len = (hw->samples - hw->wpos) << hwshift;
                    661:         bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
                    662:     }
                    663:     else {
                    664:         bufs[0].len = dead << hwshift;
                    665:     }
                    666: 
                    667: 
                    668:     for (i = 0; i < 2; ++i) {
                    669:         ssize_t nread;
                    670: 
                    671:         if (bufs[i].len) {
                    672:             void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
                    673:             nread = read (oss->fd, p, bufs[i].len);
                    674: 
                    675:             if (nread > 0) {
                    676:                 if (nread & hw->info.align) {
                    677:                     dolog ("warning: Misaligned read %zd (requested %d), "
                    678:                            "alignment %d\n", nread, bufs[i].add << hwshift,
                    679:                            hw->info.align + 1);
                    680:                 }
                    681:                 read_samples += nread >> hwshift;
                    682:                 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
                    683:                           &nominal_volume);
                    684:             }
                    685: 
                    686:             if (bufs[i].len - nread) {
                    687:                 if (nread == -1) {
                    688:                     switch (errno) {
                    689:                     case EINTR:
                    690:                     case EAGAIN:
                    691:                         break;
                    692:                     default:
                    693:                         oss_logerr (
                    694:                             errno,
                    695:                             "Failed to read %d bytes of audio (to %p)\n",
                    696:                             bufs[i].len, p
                    697:                             );
                    698:                         break;
                    699:                     }
                    700:                 }
                    701:                 break;
                    702:             }
                    703:         }
                    704:     }
                    705: 
                    706:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                    707:     return read_samples;
                    708: }
                    709: 
                    710: static int oss_read (SWVoiceIn *sw, void *buf, int size)
                    711: {
                    712:     return audio_pcm_sw_read (sw, buf, size);
                    713: }
                    714: 
                    715: static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    716: {
                    717:     (void) hw;
                    718:     (void) cmd;
                    719:     return 0;
                    720: }
                    721: 
1.1       root      722: static void *oss_audio_init (void)
                    723: {
                    724:     return &conf;
                    725: }
                    726: 
                    727: static void oss_audio_fini (void *opaque)
                    728: {
1.1.1.2   root      729:     (void) opaque;
1.1       root      730: }
                    731: 
1.1.1.2   root      732: static struct audio_option oss_options[] = {
                    733:     {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
                    734:      "Fragment size in bytes", NULL, 0},
                    735:     {"NFRAGS", AUD_OPT_INT, &conf.nfrags,
                    736:      "Number of fragments", NULL, 0},
                    737:     {"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
                    738:      "Try using memory mapped access", NULL, 0},
                    739:     {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
                    740:      "Path to DAC device", NULL, 0},
                    741:     {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
                    742:      "Path to ADC device", NULL, 0},
1.1.1.3   root      743:     {"DEBUG", AUD_OPT_BOOL, &conf.debug,
                    744:      "Turn on some debugging messages", NULL, 0},
1.1.1.2   root      745:     {NULL, 0, NULL, NULL, NULL, 0}
                    746: };
                    747: 
                    748: static struct audio_pcm_ops oss_pcm_ops = {
                    749:     oss_init_out,
                    750:     oss_fini_out,
                    751:     oss_run_out,
                    752:     oss_write,
                    753:     oss_ctl_out,
                    754: 
                    755:     oss_init_in,
                    756:     oss_fini_in,
                    757:     oss_run_in,
                    758:     oss_read,
                    759:     oss_ctl_in
1.1       root      760: };
                    761: 
1.1.1.2   root      762: struct audio_driver oss_audio_driver = {
                    763:     INIT_FIELD (name           = ) "oss",
                    764:     INIT_FIELD (descr          = ) "OSS http://www.opensound.com",
                    765:     INIT_FIELD (options        = ) oss_options,
                    766:     INIT_FIELD (init           = ) oss_audio_init,
                    767:     INIT_FIELD (fini           = ) oss_audio_fini,
                    768:     INIT_FIELD (pcm_ops        = ) &oss_pcm_ops,
                    769:     INIT_FIELD (can_be_default = ) 1,
                    770:     INIT_FIELD (max_voices_out = ) INT_MAX,
                    771:     INIT_FIELD (max_voices_in  = ) INT_MAX,
                    772:     INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
                    773:     INIT_FIELD (voice_size_in  = ) sizeof (OSSVoiceIn)
1.1       root      774: };

unix.superglobalmegacorp.com

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