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

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

unix.superglobalmegacorp.com

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