(linenum→info "unix/slp.c:2238")

qemu/0.9.1/audio/ossaudio.c

    1: /*
    2:  * QEMU OSS audio driver
    3:  *
    4:  * Copyright (c) 2003-2005 Vassili Karpov (malc)
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: #include <stdlib.h>
   25: #include <sys/mman.h>
   26: #include <sys/types.h>
   27: #include <sys/ioctl.h>
   28: #ifdef __OpenBSD__
   29: #include <soundcard.h>
   30: #else
   31: #include <sys/soundcard.h>
   32: #endif
   33: #include "qemu-common.h"
   34: #include "audio.h"
   35: 
   36: #define AUDIO_CAP "oss"
   37: #include "audio_int.h"
   38: 
   39: typedef struct OSSVoiceOut {
   40:     HWVoiceOut hw;
   41:     void *pcm_buf;
   42:     int fd;
   43:     int nfrags;
   44:     int fragsize;
   45:     int mmapped;
   46:     int old_optr;
   47: } OSSVoiceOut;
   48: 
   49: typedef struct OSSVoiceIn {
   50:     HWVoiceIn hw;
   51:     void *pcm_buf;
   52:     int fd;
   53:     int nfrags;
   54:     int fragsize;
   55:     int old_optr;
   56: } OSSVoiceIn;
   57: 
   58: static struct {
   59:     int try_mmap;
   60:     int nfrags;
   61:     int fragsize;
   62:     const char *devpath_out;
   63:     const char *devpath_in;
   64:     int debug;
   65: } conf = {
   66:     .try_mmap = 0,
   67:     .nfrags = 4,
   68:     .fragsize = 4096,
   69:     .devpath_out = "/dev/dsp",
   70:     .devpath_in = "/dev/dsp",
   71:     .debug = 0
   72: };
   73: 
   74: struct oss_params {
   75:     int freq;
   76:     audfmt_e fmt;
   77:     int nchannels;
   78:     int nfrags;
   79:     int fragsize;
   80: };
   81: 
   82: static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
   83: {
   84:     va_list ap;
   85: 
   86:     va_start (ap, fmt);
   87:     AUD_vlog (AUDIO_CAP, fmt, ap);
   88:     va_end (ap);
   89: 
   90:     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
   91: }
   92: 
   93: static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
   94:     int err,
   95:     const char *typ,
   96:     const char *fmt,
   97:     ...
   98:     )
   99: {
  100:     va_list ap;
  101: 
  102:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
  103: 
  104:     va_start (ap, fmt);
  105:     AUD_vlog (AUDIO_CAP, fmt, ap);
  106:     va_end (ap);
  107: 
  108:     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
  109: }
  110: 
  111: static void oss_anal_close (int *fdp)
  112: {
  113:     int err = close (*fdp);
  114:     if (err) {
  115:         oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
  116:     }
  117:     *fdp = -1;
  118: }
  119: 
  120: static int oss_write (SWVoiceOut *sw, void *buf, int len)
  121: {
  122:     return audio_pcm_sw_write (sw, buf, len);
  123: }
  124: 
  125: static int aud_to_ossfmt (audfmt_e fmt)
  126: {
  127:     switch (fmt) {
  128:     case AUD_FMT_S8:
  129:         return AFMT_S8;
  130: 
  131:     case AUD_FMT_U8:
  132:         return AFMT_U8;
  133: 
  134:     case AUD_FMT_S16:
  135:         return AFMT_S16_LE;
  136: 
  137:     case AUD_FMT_U16:
  138:         return AFMT_U16_LE;
  139: 
  140:     default:
  141:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
  142: #ifdef DEBUG_AUDIO
  143:         abort ();
  144: #endif
  145:         return AFMT_U8;
  146:     }
  147: }
  148: 
  149: static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
  150: {
  151:     switch (ossfmt) {
  152:     case AFMT_S8:
  153:         *endianness =0;
  154:         *fmt = AUD_FMT_S8;
  155:         break;
  156: 
  157:     case AFMT_U8:
  158:         *endianness = 0;
  159:         *fmt = AUD_FMT_U8;
  160:         break;
  161: 
  162:     case AFMT_S16_LE:
  163:         *endianness = 0;
  164:         *fmt = AUD_FMT_S16;
  165:         break;
  166: 
  167:     case AFMT_U16_LE:
  168:         *endianness = 0;
  169:         *fmt = AUD_FMT_U16;
  170:         break;
  171: 
  172:     case AFMT_S16_BE:
  173:         *endianness = 1;
  174:         *fmt = AUD_FMT_S16;
  175:         break;
  176: 
  177:     case AFMT_U16_BE:
  178:         *endianness = 1;
  179:         *fmt = AUD_FMT_U16;
  180:         break;
  181: 
  182:     default:
  183:         dolog ("Unrecognized audio format %d\n", ossfmt);
  184:         return -1;
  185:     }
  186: 
  187:     return 0;
  188: }
  189: 
  190: #if defined DEBUG_MISMATCHES || defined DEBUG
  191: static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
  192: {
  193:     dolog ("parameter | requested value | obtained value\n");
  194:     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
  195:     dolog ("channels  |      %10d |     %10d\n",
  196:            req->nchannels, obt->nchannels);
  197:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
  198:     dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
  199:     dolog ("fragsize  |      %10d |     %10d\n",
  200:            req->fragsize, obt->fragsize);
  201: }
  202: #endif
  203: 
  204: static int oss_open (int in, struct oss_params *req,
  205:                      struct oss_params *obt, int *pfd)
  206: {
  207:     int fd;
  208:     int mmmmssss;
  209:     audio_buf_info abinfo;
  210:     int fmt, freq, nchannels;
  211:     const char *dspname = in ? conf.devpath_in : conf.devpath_out;
  212:     const char *typ = in ? "ADC" : "DAC";
  213: 
  214:     fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
  215:     if (-1 == fd) {
  216:         oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
  217:         return -1;
  218:     }
  219: 
  220:     freq = req->freq;
  221:     nchannels = req->nchannels;
  222:     fmt = req->fmt;
  223: 
  224:     if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
  225:         oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
  226:         goto err;
  227:     }
  228: 
  229:     if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
  230:         oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
  231:                      req->nchannels);
  232:         goto err;
  233:     }
  234: 
  235:     if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
  236:         oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
  237:         goto err;
  238:     }
  239: 
  240:     if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
  241:         oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
  242:         goto err;
  243:     }
  244: 
  245:     mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
  246:     if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
  247:         oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
  248:                      req->nfrags, req->fragsize);
  249:         goto err;
  250:     }
  251: 
  252:     if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
  253:         oss_logerr2 (errno, typ, "Failed to get buffer length\n");
  254:         goto err;
  255:     }
  256: 
  257:     obt->fmt = fmt;
  258:     obt->nchannels = nchannels;
  259:     obt->freq = freq;
  260:     obt->nfrags = abinfo.fragstotal;
  261:     obt->fragsize = abinfo.fragsize;
  262:     *pfd = fd;
  263: 
  264: #ifdef DEBUG_MISMATCHES
  265:     if ((req->fmt != obt->fmt) ||
  266:         (req->nchannels != obt->nchannels) ||
  267:         (req->freq != obt->freq) ||
  268:         (req->fragsize != obt->fragsize) ||
  269:         (req->nfrags != obt->nfrags)) {
  270:         dolog ("Audio parameters mismatch\n");
  271:         oss_dump_info (req, obt);
  272:     }
  273: #endif
  274: 
  275: #ifdef DEBUG
  276:     oss_dump_info (req, obt);
  277: #endif
  278:     return 0;
  279: 
  280:  err:
  281:     oss_anal_close (&fd);
  282:     return -1;
  283: }
  284: 
  285: static int oss_run_out (HWVoiceOut *hw)
  286: {
  287:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  288:     int err, rpos, live, decr;
  289:     int samples;
  290:     uint8_t *dst;
  291:     st_sample_t *src;
  292:     struct audio_buf_info abinfo;
  293:     struct count_info cntinfo;
  294:     int bufsize;
  295: 
  296:     live = audio_pcm_hw_get_live_out (hw);
  297:     if (!live) {
  298:         return 0;
  299:     }
  300: 
  301:     bufsize = hw->samples << hw->info.shift;
  302: 
  303:     if (oss->mmapped) {
  304:         int bytes;
  305: 
  306:         err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
  307:         if (err < 0) {
  308:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
  309:             return 0;
  310:         }
  311: 
  312:         if (cntinfo.ptr == oss->old_optr) {
  313:             if (abs (hw->samples - live) < 64) {
  314:                 dolog ("warning: Overrun\n");
  315:             }
  316:             return 0;
  317:         }
  318: 
  319:         if (cntinfo.ptr > oss->old_optr) {
  320:             bytes = cntinfo.ptr - oss->old_optr;
  321:         }
  322:         else {
  323:             bytes = bufsize + cntinfo.ptr - oss->old_optr;
  324:         }
  325: 
  326:         decr = audio_MIN (bytes >> hw->info.shift, live);
  327:     }
  328:     else {
  329:         err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
  330:         if (err < 0) {
  331:             oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
  332:             return 0;
  333:         }
  334: 
  335:         if (abinfo.bytes > bufsize) {
  336:             if (conf.debug) {
  337:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
  338:                        "please report your OS/audio hw to malc@pulsesoft.com\n",
  339:                        abinfo.bytes, bufsize);
  340:             }
  341:             abinfo.bytes = bufsize;
  342:         }
  343: 
  344:         if (abinfo.bytes < 0) {
  345:             if (conf.debug) {
  346:                 dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
  347:                        abinfo.bytes, bufsize);
  348:             }
  349:             return 0;
  350:         }
  351: 
  352:         decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
  353:         if (!decr) {
  354:             return 0;
  355:         }
  356:     }
  357: 
  358:     samples = decr;
  359:     rpos = hw->rpos;
  360:     while (samples) {
  361:         int left_till_end_samples = hw->samples - rpos;
  362:         int convert_samples = audio_MIN (samples, left_till_end_samples);
  363: 
  364:         src = hw->mix_buf + rpos;
  365:         dst = advance (oss->pcm_buf, rpos << hw->info.shift);
  366: 
  367:         hw->clip (dst, src, convert_samples);
  368:         if (!oss->mmapped) {
  369:             int written;
  370: 
  371:             written = write (oss->fd, dst, convert_samples << hw->info.shift);
  372:             /* XXX: follow errno recommendations ? */
  373:             if (written == -1) {
  374:                 oss_logerr (
  375:                     errno,
  376:                     "Failed to write %d bytes of audio data from %p\n",
  377:                     convert_samples << hw->info.shift,
  378:                     dst
  379:                     );
  380:                 continue;
  381:             }
  382: 
  383:             if (written != convert_samples << hw->info.shift) {
  384:                 int wsamples = written >> hw->info.shift;
  385:                 int wbytes = wsamples << hw->info.shift;
  386:                 if (wbytes != written) {
  387:                     dolog ("warning: Misaligned write %d (requested %d), "
  388:                            "alignment %d\n",
  389:                            wbytes, written, hw->info.align + 1);
  390:                 }
  391:                 decr -= wsamples;
  392:                 rpos = (rpos + wsamples) % hw->samples;
  393:                 break;
  394:             }
  395:         }
  396: 
  397:         rpos = (rpos + convert_samples) % hw->samples;
  398:         samples -= convert_samples;
  399:     }
  400:     if (oss->mmapped) {
  401:         oss->old_optr = cntinfo.ptr;
  402:     }
  403: 
  404:     hw->rpos = rpos;
  405:     return decr;
  406: }
  407: 
  408: static void oss_fini_out (HWVoiceOut *hw)
  409: {
  410:     int err;
  411:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  412: 
  413:     ldebug ("oss_fini\n");
  414:     oss_anal_close (&oss->fd);
  415: 
  416:     if (oss->pcm_buf) {
  417:         if (oss->mmapped) {
  418:             err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
  419:             if (err) {
  420:                 oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
  421:                             oss->pcm_buf, hw->samples << hw->info.shift);
  422:             }
  423:         }
  424:         else {
  425:             qemu_free (oss->pcm_buf);
  426:         }
  427:         oss->pcm_buf = NULL;
  428:     }
  429: }
  430: 
  431: static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
  432: {
  433:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  434:     struct oss_params req, obt;
  435:     int endianness;
  436:     int err;
  437:     int fd;
  438:     audfmt_e effective_fmt;
  439:     audsettings_t obt_as;
  440: 
  441:     oss->fd = -1;
  442: 
  443:     req.fmt = aud_to_ossfmt (as->fmt);
  444:     req.freq = as->freq;
  445:     req.nchannels = as->nchannels;
  446:     req.fragsize = conf.fragsize;
  447:     req.nfrags = conf.nfrags;
  448: 
  449:     if (oss_open (0, &req, &obt, &fd)) {
  450:         return -1;
  451:     }
  452: 
  453:     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
  454:     if (err) {
  455:         oss_anal_close (&fd);
  456:         return -1;
  457:     }
  458: 
  459:     obt_as.freq = obt.freq;
  460:     obt_as.nchannels = obt.nchannels;
  461:     obt_as.fmt = effective_fmt;
  462:     obt_as.endianness = endianness;
  463: 
  464:     audio_pcm_init_info (&hw->info, &obt_as);
  465:     oss->nfrags = obt.nfrags;
  466:     oss->fragsize = obt.fragsize;
  467: 
  468:     if (obt.nfrags * obt.fragsize & hw->info.align) {
  469:         dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
  470:                obt.nfrags * obt.fragsize, hw->info.align + 1);
  471:     }
  472: 
  473:     hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
  474: 
  475:     oss->mmapped = 0;
  476:     if (conf.try_mmap) {
  477:         oss->pcm_buf = mmap (
  478:             0,
  479:             hw->samples << hw->info.shift,
  480:             PROT_READ | PROT_WRITE,
  481:             MAP_SHARED,
  482:             fd,
  483:             0
  484:             );
  485:         if (oss->pcm_buf == MAP_FAILED) {
  486:             oss_logerr (errno, "Failed to map %d bytes of DAC\n",
  487:                         hw->samples << hw->info.shift);
  488:         } else {
  489:             int err;
  490:             int trig = 0;
  491:             if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  492:                 oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
  493:             }
  494:             else {
  495:                 trig = PCM_ENABLE_OUTPUT;
  496:                 if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  497:                     oss_logerr (
  498:                         errno,
  499:                         "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
  500:                         );
  501:                 }
  502:                 else {
  503:                     oss->mmapped = 1;
  504:                 }
  505:             }
  506: 
  507:             if (!oss->mmapped) {
  508:                 err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
  509:                 if (err) {
  510:                     oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
  511:                                 oss->pcm_buf, hw->samples << hw->info.shift);
  512:                 }
  513:             }
  514:         }
  515:     }
  516: 
  517:     if (!oss->mmapped) {
  518:         oss->pcm_buf = audio_calloc (
  519:             AUDIO_FUNC,
  520:             hw->samples,
  521:             1 << hw->info.shift
  522:             );
  523:         if (!oss->pcm_buf) {
  524:             dolog (
  525:                 "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
  526:                 hw->samples,
  527:                 1 << hw->info.shift
  528:                 );
  529:             oss_anal_close (&fd);
  530:             return -1;
  531:         }
  532:     }
  533: 
  534:     oss->fd = fd;
  535:     return 0;
  536: }
  537: 
  538: static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
  539: {
  540:     int trig;
  541:     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  542: 
  543:     if (!oss->mmapped) {
  544:         return 0;
  545:     }
  546: 
  547:     switch (cmd) {
  548:     case VOICE_ENABLE:
  549:         ldebug ("enabling voice\n");
  550:         audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
  551:         trig = PCM_ENABLE_OUTPUT;
  552:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  553:             oss_logerr (
  554:                 errno,
  555:                 "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
  556:                 );
  557:             return -1;
  558:         }
  559:         break;
  560: 
  561:     case VOICE_DISABLE:
  562:         ldebug ("disabling voice\n");
  563:         trig = 0;
  564:         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  565:             oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
  566:             return -1;
  567:         }
  568:         break;
  569:     }
  570:     return 0;
  571: }
  572: 
  573: static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
  574: {
  575:     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  576:     struct oss_params req, obt;
  577:     int endianness;
  578:     int err;
  579:     int fd;
  580:     audfmt_e effective_fmt;
  581:     audsettings_t obt_as;
  582: 
  583:     oss->fd = -1;
  584: 
  585:     req.fmt = aud_to_ossfmt (as->fmt);
  586:     req.freq = as->freq;
  587:     req.nchannels = as->nchannels;
  588:     req.fragsize