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

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"
1.1.1.7   root       34: #include "host-utils.h"
                     35: #include "qemu-char.h"
1.1.1.4   root       36: #include "audio.h"
1.1       root       37: 
1.1.1.2   root       38: #define AUDIO_CAP "oss"
                     39: #include "audio_int.h"
1.1       root       40: 
1.1.1.8   root       41: #if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
                     42: #define USE_DSP_POLICY
                     43: #endif
                     44: 
1.1.1.2   root       45: typedef struct OSSVoiceOut {
                     46:     HWVoiceOut hw;
1.1       root       47:     void *pcm_buf;
                     48:     int fd;
1.1.1.7   root       49:     int wpos;
1.1       root       50:     int nfrags;
                     51:     int fragsize;
                     52:     int mmapped;
1.1.1.7   root       53:     int pending;
1.1.1.2   root       54: } OSSVoiceOut;
1.1       root       55: 
1.1.1.2   root       56: typedef struct OSSVoiceIn {
                     57:     HWVoiceIn hw;
                     58:     void *pcm_buf;
                     59:     int fd;
                     60:     int nfrags;
                     61:     int fragsize;
                     62: } OSSVoiceIn;
1.1       root       63: 
                     64: static struct {
                     65:     int try_mmap;
                     66:     int nfrags;
                     67:     int fragsize;
1.1.1.2   root       68:     const char *devpath_out;
                     69:     const char *devpath_in;
1.1.1.3   root       70:     int debug;
1.1.1.7   root       71:     int exclusive;
                     72:     int policy;
1.1       root       73: } conf = {
                     74:     .try_mmap = 0,
                     75:     .nfrags = 4,
                     76:     .fragsize = 4096,
1.1.1.2   root       77:     .devpath_out = "/dev/dsp",
1.1.1.3   root       78:     .devpath_in = "/dev/dsp",
1.1.1.7   root       79:     .debug = 0,
                     80:     .exclusive = 0,
                     81:     .policy = 5
1.1       root       82: };
                     83: 
                     84: struct oss_params {
                     85:     int freq;
                     86:     audfmt_e fmt;
                     87:     int nchannels;
                     88:     int nfrags;
                     89:     int fragsize;
                     90: };
                     91: 
1.1.1.2   root       92: static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
                     93: {
                     94:     va_list ap;
                     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 GCC_FMT_ATTR (3, 4) oss_logerr2 (
                    104:     int err,
                    105:     const char *typ,
                    106:     const char *fmt,
                    107:     ...
                    108:     )
                    109: {
                    110:     va_list ap;
                    111: 
                    112:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
                    113: 
                    114:     va_start (ap, fmt);
                    115:     AUD_vlog (AUDIO_CAP, fmt, ap);
                    116:     va_end (ap);
                    117: 
                    118:     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
                    119: }
                    120: 
                    121: static void oss_anal_close (int *fdp)
                    122: {
1.1.1.7   root      123:     int err;
                    124: 
                    125:     qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
                    126:     err = close (*fdp);
1.1.1.2   root      127:     if (err) {
                    128:         oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
                    129:     }
                    130:     *fdp = -1;
                    131: }
                    132: 
1.1.1.7   root      133: static void oss_helper_poll_out (void *opaque)
                    134: {
                    135:     (void) opaque;
                    136:     audio_run ("oss_poll_out");
                    137: }
                    138: 
                    139: static void oss_helper_poll_in (void *opaque)
                    140: {
                    141:     (void) opaque;
                    142:     audio_run ("oss_poll_in");
                    143: }
                    144: 
                    145: static int oss_poll_out (HWVoiceOut *hw)
                    146: {
                    147:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
                    148: 
                    149:     return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
                    150: }
                    151: 
                    152: static int oss_poll_in (HWVoiceIn *hw)
                    153: {
                    154:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    155: 
                    156:     return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
                    157: }
                    158: 
1.1.1.2   root      159: static int oss_write (SWVoiceOut *sw, void *buf, int len)
1.1       root      160: {
1.1.1.2   root      161:     return audio_pcm_sw_write (sw, buf, len);
1.1       root      162: }
                    163: 
1.1.1.9   root      164: static int aud_to_ossfmt (audfmt_e fmt, int endianness)
1.1       root      165: {
                    166:     switch (fmt) {
1.1.1.2   root      167:     case AUD_FMT_S8:
                    168:         return AFMT_S8;
                    169: 
                    170:     case AUD_FMT_U8:
                    171:         return AFMT_U8;
                    172: 
                    173:     case AUD_FMT_S16:
1.1.1.9   root      174:         if (endianness) {
                    175:             return AFMT_S16_BE;
                    176:         }
                    177:         else {
                    178:             return AFMT_S16_LE;
                    179:         }
1.1.1.2   root      180: 
                    181:     case AUD_FMT_U16:
1.1.1.9   root      182:         if (endianness) {
                    183:             return AFMT_U16_BE;
                    184:         }
                    185:         else {
                    186:             return AFMT_U16_LE;
                    187:         }
1.1.1.2   root      188: 
1.1       root      189:     default:
1.1.1.2   root      190:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
                    191: #ifdef DEBUG_AUDIO
                    192:         abort ();
                    193: #endif
                    194:         return AFMT_U8;
1.1       root      195:     }
                    196: }
                    197: 
1.1.1.2   root      198: static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
1.1       root      199: {
1.1.1.2   root      200:     switch (ossfmt) {
                    201:     case AFMT_S8:
1.1.1.5   root      202:         *endianness = 0;
1.1.1.2   root      203:         *fmt = AUD_FMT_S8;
                    204:         break;
                    205: 
                    206:     case AFMT_U8:
                    207:         *endianness = 0;
                    208:         *fmt = AUD_FMT_U8;
                    209:         break;
                    210: 
                    211:     case AFMT_S16_LE:
                    212:         *endianness = 0;
                    213:         *fmt = AUD_FMT_S16;
                    214:         break;
                    215: 
                    216:     case AFMT_U16_LE:
                    217:         *endianness = 0;
                    218:         *fmt = AUD_FMT_U16;
                    219:         break;
                    220: 
                    221:     case AFMT_S16_BE:
                    222:         *endianness = 1;
                    223:         *fmt = AUD_FMT_S16;
                    224:         break;
                    225: 
                    226:     case AFMT_U16_BE:
                    227:         *endianness = 1;
                    228:         *fmt = AUD_FMT_U16;
                    229:         break;
                    230: 
1.1       root      231:     default:
1.1.1.2   root      232:         dolog ("Unrecognized audio format %d\n", ossfmt);
                    233:         return -1;
1.1       root      234:     }
1.1.1.2   root      235: 
                    236:     return 0;
1.1       root      237: }
                    238: 
1.1.1.2   root      239: #if defined DEBUG_MISMATCHES || defined DEBUG
                    240: static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
1.1       root      241: {
                    242:     dolog ("parameter | requested value | obtained value\n");
                    243:     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
1.1.1.2   root      244:     dolog ("channels  |      %10d |     %10d\n",
                    245:            req->nchannels, obt->nchannels);
1.1       root      246:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
                    247:     dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
1.1.1.2   root      248:     dolog ("fragsize  |      %10d |     %10d\n",
                    249:            req->fragsize, obt->fragsize);
1.1       root      250: }
                    251: #endif
                    252: 
1.1.1.8   root      253: #ifdef USE_DSP_POLICY
                    254: static int oss_get_version (int fd, int *version, const char *typ)
                    255: {
                    256:     if (ioctl (fd, OSS_GETVERSION, &version)) {
                    257: #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
                    258:         /*
                    259:          * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
                    260:          * since 7.x, but currently only on the mixer device (or in
                    261:          * the Linuxolator), and in the native version that part of
                    262:          * the code is in fact never reached so the ioctl fails anyway.
                    263:          * Until this is fixed, just check the errno and if its what
                    264:          * FreeBSD's sound drivers return atm assume they are new enough.
                    265:          */
                    266:         if (errno == EINVAL) {
                    267:             *version = 0x040000;
                    268:             return 0;
                    269:         }
                    270: #endif
                    271:         oss_logerr2 (errno, typ, "Failed to get OSS version\n");
                    272:         return -1;
                    273:     }
                    274:     return 0;
                    275: }
                    276: #endif
                    277: 
1.1.1.2   root      278: static int oss_open (int in, struct oss_params *req,
                    279:                      struct oss_params *obt, int *pfd)
1.1       root      280: {
                    281:     int fd;
1.1.1.7   root      282:     int oflags = conf.exclusive ? O_EXCL : 0;
1.1       root      283:     audio_buf_info abinfo;
                    284:     int fmt, freq, nchannels;
1.1.1.8   root      285:     int setfragment = 1;
1.1.1.2   root      286:     const char *dspname = in ? conf.devpath_in : conf.devpath_out;
                    287:     const char *typ = in ? "ADC" : "DAC";
1.1       root      288: 
1.1.1.7   root      289:     /* Kludge needed to have working mmap on Linux */
                    290:     oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
                    291: 
                    292:     fd = open (dspname, oflags | O_NONBLOCK);
1.1       root      293:     if (-1 == fd) {
1.1.1.2   root      294:         oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
1.1       root      295:         return -1;
                    296:     }
                    297: 
                    298:     freq = req->freq;
                    299:     nchannels = req->nchannels;
                    300:     fmt = req->fmt;
                    301: 
                    302:     if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
1.1.1.2   root      303:         oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
1.1       root      304:         goto err;
                    305:     }
                    306: 
                    307:     if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
1.1.1.2   root      308:         oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
                    309:                      req->nchannels);
1.1       root      310:         goto err;
                    311:     }
                    312: 
                    313:     if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
1.1.1.2   root      314:         oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
1.1       root      315:         goto err;
                    316:     }
                    317: 
1.1.1.5   root      318:     if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
1.1.1.2   root      319:         oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
1.1       root      320:         goto err;
                    321:     }
                    322: 
1.1.1.8   root      323: #ifdef USE_DSP_POLICY
                    324:     if (conf.policy >= 0) {
                    325:         int version;
1.1.1.7   root      326: 
1.1.1.8   root      327:         if (!oss_get_version (fd, &version, typ)) {
                    328:             if (conf.debug) {
                    329:                 dolog ("OSS version = %#x\n", version);
                    330:             }
1.1.1.7   root      331: 
1.1.1.8   root      332:             if (version >= 0x040000) {
                    333:                 int policy = conf.policy;
                    334:                 if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
                    335:                     oss_logerr2 (errno, typ,
                    336:                                  "Failed to set timing policy to %d\n",
                    337:                                  conf.policy);
                    338:                     goto err;
                    339:                 }
                    340:                 setfragment = 0;
                    341:             }
1.1.1.7   root      342:         }
                    343:     }
                    344: #endif
1.1.1.8   root      345: 
                    346:     if (setfragment) {
1.1.1.7   root      347:         int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
                    348:         if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
                    349:             oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
                    350:                          req->nfrags, req->fragsize);
                    351:             goto err;
                    352:         }
1.1       root      353:     }
                    354: 
1.1.1.2   root      355:     if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
                    356:         oss_logerr2 (errno, typ, "Failed to get buffer length\n");
1.1       root      357:         goto err;
                    358:     }
                    359: 
1.1.1.5   root      360:     if (!abinfo.fragstotal || !abinfo.fragsize) {
                    361:         AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
                    362:                  abinfo.fragstotal, abinfo.fragsize, typ);
                    363:         goto err;
                    364:     }
                    365: 
1.1       root      366:     obt->fmt = fmt;
                    367:     obt->nchannels = nchannels;
                    368:     obt->freq = freq;
                    369:     obt->nfrags = abinfo.fragstotal;
                    370:     obt->fragsize = abinfo.fragsize;
                    371:     *pfd = fd;
                    372: 
1.1.1.2   root      373: #ifdef DEBUG_MISMATCHES
1.1       root      374:     if ((req->fmt != obt->fmt) ||
                    375:         (req->nchannels != obt->nchannels) ||
                    376:         (req->freq != obt->freq) ||
                    377:         (req->fragsize != obt->fragsize) ||
                    378:         (req->nfrags != obt->nfrags)) {
                    379:         dolog ("Audio parameters mismatch\n");
1.1.1.2   root      380:         oss_dump_info (req, obt);
1.1       root      381:     }
1.1.1.2   root      382: #endif
1.1       root      383: 
1.1.1.2   root      384: #ifdef DEBUG
                    385:     oss_dump_info (req, obt);
1.1       root      386: #endif
                    387:     return 0;
                    388: 
1.1.1.2   root      389:  err:
                    390:     oss_anal_close (&fd);
1.1       root      391:     return -1;
                    392: }
                    393: 
1.1.1.7   root      394: static void oss_write_pending (OSSVoiceOut *oss)
                    395: {
                    396:     HWVoiceOut *hw = &oss->hw;
                    397: 
                    398:     if (oss->mmapped) {
                    399:         return;
                    400:     }
                    401: 
                    402:     while (oss->pending) {
                    403:         int samples_written;
                    404:         ssize_t bytes_written;
                    405:         int samples_till_end = hw->samples - oss->wpos;
                    406:         int samples_to_write = audio_MIN (oss->pending, samples_till_end);
                    407:         int bytes_to_write = samples_to_write << hw->info.shift;
                    408:         void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
                    409: 
                    410:         bytes_written = write (oss->fd, pcm, bytes_to_write);
                    411:         if (bytes_written < 0) {
                    412:             if (errno != EAGAIN) {
                    413:                 oss_logerr (errno, "failed to write %d bytes\n",
                    414:                             bytes_to_write);
                    415:             }
                    416:             break;
                    417:         }
                    418: 
                    419:         if (bytes_written & hw->info.align) {
                    420:             dolog ("misaligned write asked for %d, but got %zd\n",
                    421:                    bytes_to_write, bytes_written);
                    422:             return;
                    423:         }
                    424: 
                    425:         samples_written = bytes_written >> hw->info.shift;
                    426:         oss->pending -= samples_written;
                    427:         oss->wpos = (oss->wpos + samples_written) % hw->samples;
                    428:         if (bytes_written - bytes_to_write) {
                    429:             break;
                    430:         }
                    431:     }
                    432: }
                    433: 
                    434: static int oss_run_out (HWVoiceOut *hw, int live)
1.1       root      435: {
1.1.1.2   root      436:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1.1.7   root      437:     int err, decr;
1.1       root      438:     struct audio_buf_info abinfo;
                    439:     struct count_info cntinfo;
1.1.1.2   root      440:     int bufsize;
                    441: 
                    442:     bufsize = hw->samples << hw->info.shift;
1.1       root      443: 
                    444:     if (oss->mmapped) {
1.1.1.7   root      445:         int bytes, pos;
1.1       root      446: 
                    447:         err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
                    448:         if (err < 0) {
1.1.1.2   root      449:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
                    450:             return 0;
1.1       root      451:         }
                    452: 
1.1.1.7   root      453:         pos = hw->rpos << hw->info.shift;
                    454:         bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
1.1.1.2   root      455:         decr = audio_MIN (bytes >> hw->info.shift, live);
1.1       root      456:     }
                    457:     else {
                    458:         err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
                    459:         if (err < 0) {
1.1.1.2   root      460:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
                    461:             return 0;
                    462:         }
                    463: 
1.1.1.3   root      464:         if (abinfo.bytes > bufsize) {
                    465:             if (conf.debug) {
                    466:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
1.1.1.7   root      467:                        "please report your OS/audio hw to [email protected]\n",
1.1.1.3   root      468:                        abinfo.bytes, bufsize);
                    469:             }
                    470:             abinfo.bytes = bufsize;
                    471:         }
                    472: 
                    473:         if (abinfo.bytes < 0) {
                    474:             if (conf.debug) {
                    475:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
                    476:                        abinfo.bytes, bufsize);
                    477:             }
1.1.1.2   root      478:             return 0;
1.1       root      479:         }
                    480: 
1.1.1.2   root      481:         decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
                    482:         if (!decr) {
                    483:             return 0;
                    484:         }
1.1       root      485:     }
                    486: 
1.1.1.7   root      487:     decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
                    488:     oss->pending += decr;
                    489:     oss_write_pending (oss);
1.1       root      490: 
1.1.1.2   root      491:     return decr;
1.1       root      492: }
                    493: 
1.1.1.2   root      494: static void oss_fini_out (HWVoiceOut *hw)
1.1       root      495: {
                    496:     int err;
1.1.1.2   root      497:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      498: 
1.1.1.2   root      499:     ldebug ("oss_fini\n");
                    500:     oss_anal_close (&oss->fd);
1.1       root      501: 
                    502:     if (oss->pcm_buf) {
                    503:         if (oss->mmapped) {
1.1.1.2   root      504:             err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      505:             if (err) {
1.1.1.2   root      506:                 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
                    507:                             oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      508:             }
                    509:         }
                    510:         else {
1.1.1.10! root      511:             g_free (oss->pcm_buf);
1.1       root      512:         }
                    513:         oss->pcm_buf = NULL;
                    514:     }
                    515: }
                    516: 
1.1.1.5   root      517: static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1       root      518: {
1.1.1.2   root      519:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      520:     struct oss_params req, obt;
1.1.1.2   root      521:     int endianness;
                    522:     int err;
                    523:     int fd;
                    524:     audfmt_e effective_fmt;
1.1.1.5   root      525:     struct audsettings obt_as;
1.1.1.2   root      526: 
                    527:     oss->fd = -1;
1.1       root      528: 
1.1.1.9   root      529:     req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
1.1.1.2   root      530:     req.freq = as->freq;
                    531:     req.nchannels = as->nchannels;
1.1       root      532:     req.fragsize = conf.fragsize;
                    533:     req.nfrags = conf.nfrags;
                    534: 
1.1.1.2   root      535:     if (oss_open (0, &req, &obt, &fd)) {
1.1       root      536:         return -1;
1.1.1.2   root      537:     }
1.1       root      538: 
1.1.1.2   root      539:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    540:     if (err) {
                    541:         oss_anal_close (&fd);
                    542:         return -1;
                    543:     }
1.1       root      544: 
1.1.1.2   root      545:     obt_as.freq = obt.freq;
                    546:     obt_as.nchannels = obt.nchannels;
                    547:     obt_as.fmt = effective_fmt;
1.1.1.3   root      548:     obt_as.endianness = endianness;
1.1.1.2   root      549: 
1.1.1.3   root      550:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      551:     oss->nfrags = obt.nfrags;
                    552:     oss->fragsize = obt.fragsize;
1.1.1.2   root      553: 
                    554:     if (obt.nfrags * obt.fragsize & hw->info.align) {
                    555:         dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
                    556:                obt.nfrags * obt.fragsize, hw->info.align + 1);
                    557:     }
                    558: 
                    559:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
1.1       root      560: 
                    561:     oss->mmapped = 0;
                    562:     if (conf.try_mmap) {
1.1.1.2   root      563:         oss->pcm_buf = mmap (
1.1.1.6   root      564:             NULL,
1.1.1.2   root      565:             hw->samples << hw->info.shift,
                    566:             PROT_READ | PROT_WRITE,
                    567:             MAP_SHARED,
                    568:             fd,
                    569:             0
                    570:             );
1.1       root      571:         if (oss->pcm_buf == MAP_FAILED) {
1.1.1.2   root      572:             oss_logerr (errno, "Failed to map %d bytes of DAC\n",
                    573:                         hw->samples << hw->info.shift);
1.1.1.7   root      574:         }
                    575:         else {
1.1       root      576:             int err;
                    577:             int trig = 0;
1.1.1.2   root      578:             if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    579:                 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
1.1       root      580:             }
                    581:             else {
                    582:                 trig = PCM_ENABLE_OUTPUT;
1.1.1.2   root      583:                 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    584:                     oss_logerr (
                    585:                         errno,
                    586:                         "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
                    587:                         );
1.1       root      588:                 }
                    589:                 else {
                    590:                     oss->mmapped = 1;
                    591:                 }
                    592:             }
                    593: 
                    594:             if (!oss->mmapped) {
1.1.1.2   root      595:                 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      596:                 if (err) {
1.1.1.2   root      597:                     oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
                    598:                                 oss->pcm_buf, hw->samples << hw->info.shift);
1.1       root      599:                 }
                    600:             }
                    601:         }
                    602:     }
                    603: 
                    604:     if (!oss->mmapped) {
1.1.1.2   root      605:         oss->pcm_buf = audio_calloc (
                    606:             AUDIO_FUNC,
                    607:             hw->samples,
                    608:             1 << hw->info.shift
                    609:             );
1.1       root      610:         if (!oss->pcm_buf) {
1.1.1.2   root      611:             dolog (
                    612:                 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    613:                 hw->samples,
                    614:                 1 << hw->info.shift
                    615:                 );
                    616:             oss_anal_close (&fd);
1.1       root      617:             return -1;
                    618:         }
                    619:     }
                    620: 
1.1.1.2   root      621:     oss->fd = fd;
1.1       root      622:     return 0;
                    623: }
                    624: 
1.1.1.2   root      625: static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
1.1       root      626: {
                    627:     int trig;
1.1.1.2   root      628:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
1.1       root      629: 
                    630:     switch (cmd) {
                    631:     case VOICE_ENABLE:
1.1.1.7   root      632:         {
                    633:             va_list ap;
                    634:             int poll_mode;
                    635: 
                    636:             va_start (ap, cmd);
                    637:             poll_mode = va_arg (ap, int);
                    638:             va_end (ap);
                    639: 
                    640:             ldebug ("enabling voice\n");
                    641:             if (poll_mode && oss_poll_out (hw)) {
                    642:                 poll_mode = 0;
                    643:             }
                    644:             hw->poll_mode = poll_mode;
                    645: 
                    646:             if (!oss->mmapped) {
                    647:                 return 0;
                    648:             }
                    649: 
                    650:             audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
                    651:             trig = PCM_ENABLE_OUTPUT;
                    652:             if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
                    653:                 oss_logerr (
                    654:                     errno,
                    655:                     "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
                    656:                     );
                    657:                 return -1;
                    658:             }
1.1       root      659:         }
                    660:         break;
                    661: 
                    662:     case VOICE_DISABLE:
1.1.1.7   root      663:         if (hw->poll_mode) {
                    664:             qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
                    665:             hw->poll_mode = 0;
                    666:         }
                    667: 
                    668:         if (!oss->mmapped) {
                    669:             return 0;
                    670:         }
                    671: 
1.1       root      672:         ldebug ("disabling voice\n");
                    673:         trig = 0;
                    674:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
1.1.1.2   root      675:             oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
1.1       root      676:             return -1;
                    677:         }
                    678:         break;
                    679:     }
                    680:     return 0;
                    681: }
                    682: 
1.1.1.5   root      683: static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
1.1.1.2   root      684: {
                    685:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    686:     struct oss_params req, obt;
                    687:     int endianness;
                    688:     int err;
                    689:     int fd;
                    690:     audfmt_e effective_fmt;
1.1.1.5   root      691:     struct audsettings obt_as;
1.1.1.2   root      692: 
                    693:     oss->fd = -1;
                    694: 
1.1.1.9   root      695:     req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
1.1.1.2   root      696:     req.freq = as->freq;
                    697:     req.nchannels = as->nchannels;
                    698:     req.fragsize = conf.fragsize;
                    699:     req.nfrags = conf.nfrags;
                    700:     if (oss_open (1, &req, &obt, &fd)) {
                    701:         return -1;
                    702:     }
                    703: 
                    704:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    705:     if (err) {
                    706:         oss_anal_close (&fd);
                    707:         return -1;
                    708:     }
                    709: 
                    710:     obt_as.freq = obt.freq;
                    711:     obt_as.nchannels = obt.nchannels;
                    712:     obt_as.fmt = effective_fmt;
1.1.1.3   root      713:     obt_as.endianness = endianness;
1.1.1.2   root      714: 
1.1.1.3   root      715:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.2   root      716:     oss->nfrags = obt.nfrags;
                    717:     oss->fragsize = obt.fragsize;
                    718: 
                    719:     if (obt.nfrags * obt.fragsize & hw->info.align) {
                    720:         dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
                    721:                obt.nfrags * obt.fragsize, hw->info.align + 1);
                    722:     }
                    723: 
                    724:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
                    725:     oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    726:     if (!oss->pcm_buf) {
                    727:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    728:                hw->samples, 1 << hw->info.shift);
                    729:         oss_anal_close (&fd);
                    730:         return -1;
                    731:     }
                    732: 
                    733:     oss->fd = fd;
                    734:     return 0;
                    735: }
                    736: 
                    737: static void oss_fini_in (HWVoiceIn *hw)
                    738: {
                    739:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    740: 
                    741:     oss_anal_close (&oss->fd);
                    742: 
                    743:     if (oss->pcm_buf) {
1.1.1.10! root      744:         g_free (oss->pcm_buf);
1.1.1.2   root      745:         oss->pcm_buf = NULL;
                    746:     }
                    747: }
                    748: 
                    749: static int oss_run_in (HWVoiceIn *hw)
                    750: {
                    751:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    752:     int hwshift = hw->info.shift;
                    753:     int i;
                    754:     int live = audio_pcm_hw_get_live_in (hw);
                    755:     int dead = hw->samples - live;
                    756:     size_t read_samples = 0;
                    757:     struct {
                    758:         int add;
                    759:         int len;
                    760:     } bufs[2] = {
1.1.1.7   root      761:         { .add = hw->wpos, .len = 0 },
                    762:         { .add = 0,        .len = 0 }
1.1.1.2   root      763:     };
                    764: 
                    765:     if (!dead) {
                    766:         return 0;
                    767:     }
                    768: 
                    769:     if (hw->wpos + dead > hw->samples) {
                    770:         bufs[0].len = (hw->samples - hw->wpos) << hwshift;
                    771:         bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
                    772:     }
                    773:     else {
                    774:         bufs[0].len = dead << hwshift;
                    775:     }
                    776: 
                    777:     for (i = 0; i < 2; ++i) {
                    778:         ssize_t nread;
                    779: 
                    780:         if (bufs[i].len) {
                    781:             void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
                    782:             nread = read (oss->fd, p, bufs[i].len);
                    783: 
                    784:             if (nread > 0) {
                    785:                 if (nread & hw->info.align) {
                    786:                     dolog ("warning: Misaligned read %zd (requested %d), "
                    787:                            "alignment %d\n", nread, bufs[i].add << hwshift,
                    788:                            hw->info.align + 1);
                    789:                 }
                    790:                 read_samples += nread >> hwshift;
1.1.1.9   root      791:                 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
1.1.1.2   root      792:             }
                    793: 
                    794:             if (bufs[i].len - nread) {
                    795:                 if (nread == -1) {
                    796:                     switch (errno) {
                    797:                     case EINTR:
                    798:                     case EAGAIN:
                    799:                         break;
                    800:                     default:
                    801:                         oss_logerr (
                    802:                             errno,
                    803:                             "Failed to read %d bytes of audio (to %p)\n",
                    804:                             bufs[i].len, p
                    805:                             );
                    806:                         break;
                    807:                     }
                    808:                 }
                    809:                 break;
                    810:             }
                    811:         }
                    812:     }
                    813: 
                    814:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                    815:     return read_samples;
                    816: }
                    817: 
                    818: static int oss_read (SWVoiceIn *sw, void *buf, int size)
                    819: {
                    820:     return audio_pcm_sw_read (sw, buf, size);
                    821: }
                    822: 
                    823: static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    824: {
1.1.1.7   root      825:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
                    826: 
                    827:     switch (cmd) {
                    828:     case VOICE_ENABLE:
                    829:         {
                    830:             va_list ap;
                    831:             int poll_mode;
                    832: 
                    833:             va_start (ap, cmd);
                    834:             poll_mode = va_arg (ap, int);
                    835:             va_end (ap);
                    836: 
                    837:             if (poll_mode && oss_poll_in (hw)) {
                    838:                 poll_mode = 0;
                    839:             }
                    840:             hw->poll_mode = poll_mode;
                    841:         }
                    842:         break;
                    843: 
                    844:     case VOICE_DISABLE:
                    845:         if (hw->poll_mode) {
                    846:             hw->poll_mode = 0;
                    847:             qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
                    848:         }
                    849:         break;
                    850:     }
1.1.1.2   root      851:     return 0;
                    852: }
                    853: 
1.1       root      854: static void *oss_audio_init (void)
                    855: {
                    856:     return &conf;
                    857: }
                    858: 
                    859: static void oss_audio_fini (void *opaque)
                    860: {
1.1.1.2   root      861:     (void) opaque;
1.1       root      862: }
                    863: 
1.1.1.2   root      864: static struct audio_option oss_options[] = {
1.1.1.7   root      865:     {
                    866:         .name  = "FRAGSIZE",
                    867:         .tag   = AUD_OPT_INT,
                    868:         .valp  = &conf.fragsize,
                    869:         .descr = "Fragment size in bytes"
                    870:     },
                    871:     {
                    872:         .name  = "NFRAGS",
                    873:         .tag   = AUD_OPT_INT,
                    874:         .valp  = &conf.nfrags,
                    875:         .descr = "Number of fragments"
                    876:     },
                    877:     {
                    878:         .name  = "MMAP",
                    879:         .tag   = AUD_OPT_BOOL,
                    880:         .valp  = &conf.try_mmap,
                    881:         .descr = "Try using memory mapped access"
                    882:     },
                    883:     {
                    884:         .name  = "DAC_DEV",
                    885:         .tag   = AUD_OPT_STR,
                    886:         .valp  = &conf.devpath_out,
                    887:         .descr = "Path to DAC device"
                    888:     },
                    889:     {
                    890:         .name  = "ADC_DEV",
                    891:         .tag   = AUD_OPT_STR,
                    892:         .valp  = &conf.devpath_in,
                    893:         .descr = "Path to ADC device"
                    894:     },
                    895:     {
                    896:         .name  = "EXCLUSIVE",
                    897:         .tag   = AUD_OPT_BOOL,
                    898:         .valp  = &conf.exclusive,
                    899:         .descr = "Open device in exclusive mode (vmix wont work)"
                    900:     },
1.1.1.8   root      901: #ifdef USE_DSP_POLICY
1.1.1.7   root      902:     {
                    903:         .name  = "POLICY",
                    904:         .tag   = AUD_OPT_INT,
                    905:         .valp  = &conf.policy,
                    906:         .descr = "Set the timing policy of the device, -1 to use fragment mode",
                    907:     },
                    908: #endif
                    909:     {
                    910:         .name  = "DEBUG",
                    911:         .tag   = AUD_OPT_BOOL,
                    912:         .valp  = &conf.debug,
                    913:         .descr = "Turn on some debugging messages"
                    914:     },
                    915:     { /* End of list */ }
1.1.1.2   root      916: };
                    917: 
                    918: static struct audio_pcm_ops oss_pcm_ops = {
1.1.1.7   root      919:     .init_out = oss_init_out,
                    920:     .fini_out = oss_fini_out,
                    921:     .run_out  = oss_run_out,
                    922:     .write    = oss_write,
                    923:     .ctl_out  = oss_ctl_out,
                    924: 
                    925:     .init_in  = oss_init_in,
                    926:     .fini_in  = oss_fini_in,
                    927:     .run_in   = oss_run_in,
                    928:     .read     = oss_read,
                    929:     .ctl_in   = oss_ctl_in
1.1       root      930: };
                    931: 
1.1.1.2   root      932: struct audio_driver oss_audio_driver = {
1.1.1.7   root      933:     .name           = "oss",
                    934:     .descr          = "OSS http://www.opensound.com",
                    935:     .options        = oss_options,
                    936:     .init           = oss_audio_init,
                    937:     .fini           = oss_audio_fini,
                    938:     .pcm_ops        = &oss_pcm_ops,
                    939:     .can_be_default = 1,
                    940:     .max_voices_out = INT_MAX,
                    941:     .max_voices_in  = INT_MAX,
                    942:     .voice_size_out = sizeof (OSSVoiceOut),
                    943:     .voice_size_in  = sizeof (OSSVoiceIn)
1.1       root      944: };

unix.superglobalmegacorp.com

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