Annotation of qemu/audio/dsoundaudio.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU DirectSound audio driver
        !             3:  *
        !             4:  * Copyright (c) 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: 
        !            25: /*
        !            26:  * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
        !            27:  */
        !            28: 
        !            29: #include "vl.h"
        !            30: 
        !            31: #define AUDIO_CAP "dsound"
        !            32: #include "audio_int.h"
        !            33: 
        !            34: #include <windows.h>
        !            35: #include <objbase.h>
        !            36: #include <dsound.h>
        !            37: 
        !            38: /* #define DEBUG_DSOUND */
        !            39: 
        !            40: static struct {
        !            41:     int lock_retries;
        !            42:     int restore_retries;
        !            43:     int getstatus_retries;
        !            44:     int set_primary;
        !            45:     int bufsize_in;
        !            46:     int bufsize_out;
        !            47:     audsettings_t settings;
        !            48:     int latency_millis;
        !            49: } conf = {
        !            50:     1,
        !            51:     1,
        !            52:     1,
        !            53:     0,
        !            54:     16384,
        !            55:     16384,
        !            56:     {
        !            57:         44100,
        !            58:         2,
        !            59:         AUD_FMT_S16
        !            60:     },
        !            61:     10
        !            62: };
        !            63: 
        !            64: typedef struct {
        !            65:     LPDIRECTSOUND dsound;
        !            66:     LPDIRECTSOUNDCAPTURE dsound_capture;
        !            67:     LPDIRECTSOUNDBUFFER dsound_primary_buffer;
        !            68:     audsettings_t settings;
        !            69: } dsound;
        !            70: 
        !            71: static dsound glob_dsound;
        !            72: 
        !            73: typedef struct {
        !            74:     HWVoiceOut hw;
        !            75:     LPDIRECTSOUNDBUFFER dsound_buffer;
        !            76:     DWORD old_pos;
        !            77:     int first_time;
        !            78: #ifdef DEBUG_DSOUND
        !            79:     DWORD old_ppos;
        !            80:     DWORD played;
        !            81:     DWORD mixed;
        !            82: #endif
        !            83: } DSoundVoiceOut;
        !            84: 
        !            85: typedef struct {
        !            86:     HWVoiceIn hw;
        !            87:     int first_time;
        !            88:     LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
        !            89: } DSoundVoiceIn;
        !            90: 
        !            91: static void dsound_log_hresult (HRESULT hr)
        !            92: {
        !            93:     const char *str = "BUG";
        !            94: 
        !            95:     switch (hr) {
        !            96:     case DS_OK:
        !            97:         str = "The method succeeded";
        !            98:         break;
        !            99: #ifdef DS_NO_VIRTUALIZATION
        !           100:     case DS_NO_VIRTUALIZATION:
        !           101:         str = "The buffer was created, but another 3D algorithm was substituted";
        !           102:         break;
        !           103: #endif
        !           104: #ifdef DS_INCOMPLETE
        !           105:     case DS_INCOMPLETE:
        !           106:         str = "The method succeeded, but not all the optional effects were obtained";
        !           107:         break;
        !           108: #endif
        !           109: #ifdef DSERR_ACCESSDENIED
        !           110:     case DSERR_ACCESSDENIED:
        !           111:         str = "The request failed because access was denied";
        !           112:         break;
        !           113: #endif
        !           114: #ifdef DSERR_ALLOCATED
        !           115:     case DSERR_ALLOCATED:
        !           116:         str = "The request failed because resources, such as a priority level, were already in use by another caller";
        !           117:         break;
        !           118: #endif
        !           119: #ifdef DSERR_ALREADYINITIALIZED
        !           120:     case DSERR_ALREADYINITIALIZED:
        !           121:         str = "The object is already initialized";
        !           122:         break;
        !           123: #endif
        !           124: #ifdef DSERR_BADFORMAT
        !           125:     case DSERR_BADFORMAT:
        !           126:         str = "The specified wave format is not supported";
        !           127:         break;
        !           128: #endif
        !           129: #ifdef DSERR_BADSENDBUFFERGUID
        !           130:     case DSERR_BADSENDBUFFERGUID:
        !           131:         str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
        !           132:         break;
        !           133: #endif
        !           134: #ifdef DSERR_BUFFERLOST
        !           135:     case DSERR_BUFFERLOST:
        !           136:         str = "The buffer memory has been lost and must be restored";
        !           137:         break;
        !           138: #endif
        !           139: #ifdef DSERR_BUFFERTOOSMALL
        !           140:     case DSERR_BUFFERTOOSMALL:
        !           141:         str = "The buffer size is not great enough to enable effects processing";
        !           142:         break;
        !           143: #endif
        !           144: #ifdef DSERR_CONTROLUNAVAIL
        !           145:     case DSERR_CONTROLUNAVAIL:
        !           146:         str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
        !           147:         break;
        !           148: #endif
        !           149: #ifdef DSERR_DS8_REQUIRED
        !           150:     case DSERR_DS8_REQUIRED:
        !           151:         str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
        !           152:         break;
        !           153: #endif
        !           154: #ifdef DSERR_FXUNAVAILABLE
        !           155:     case DSERR_FXUNAVAILABLE:
        !           156:         str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
        !           157:         break;
        !           158: #endif
        !           159: #ifdef DSERR_GENERIC
        !           160:     case DSERR_GENERIC :
        !           161:         str = "An undetermined error occurred inside the DirectSound subsystem";
        !           162:         break;
        !           163: #endif
        !           164: #ifdef DSERR_INVALIDCALL
        !           165:     case DSERR_INVALIDCALL:
        !           166:         str = "This function is not valid for the current state of this object";
        !           167:         break;
        !           168: #endif
        !           169: #ifdef DSERR_INVALIDPARAM
        !           170:     case DSERR_INVALIDPARAM:
        !           171:         str = "An invalid parameter was passed to the returning function";
        !           172:         break;
        !           173: #endif
        !           174: #ifdef DSERR_NOAGGREGATION
        !           175:     case DSERR_NOAGGREGATION:
        !           176:         str = "The object does not support aggregation";
        !           177:         break;
        !           178: #endif
        !           179: #ifdef DSERR_NODRIVER
        !           180:     case DSERR_NODRIVER:
        !           181:         str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
        !           182:         break;
        !           183: #endif
        !           184: #ifdef DSERR_NOINTERFACE
        !           185:     case DSERR_NOINTERFACE:
        !           186:         str = "The requested COM interface is not available";
        !           187:         break;
        !           188: #endif
        !           189: #ifdef DSERR_OBJECTNOTFOUND
        !           190:     case DSERR_OBJECTNOTFOUND:
        !           191:         str = "The requested object was not found";
        !           192:         break;
        !           193: #endif
        !           194: #ifdef DSERR_OTHERAPPHASPRIO
        !           195:     case DSERR_OTHERAPPHASPRIO:
        !           196:         str = "Another application has a higher priority level, preventing this call from succeeding";
        !           197:         break;
        !           198: #endif
        !           199: #ifdef DSERR_OUTOFMEMORY
        !           200:     case DSERR_OUTOFMEMORY:
        !           201:         str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
        !           202:         break;
        !           203: #endif
        !           204: #ifdef DSERR_PRIOLEVELNEEDED
        !           205:     case DSERR_PRIOLEVELNEEDED:
        !           206:         str = "A cooperative level of DSSCL_PRIORITY or higher is required";
        !           207:         break;
        !           208: #endif
        !           209: #ifdef DSERR_SENDLOOP
        !           210:     case DSERR_SENDLOOP:
        !           211:         str = "A circular loop of send effects was detected";
        !           212:         break;
        !           213: #endif
        !           214: #ifdef DSERR_UNINITIALIZED
        !           215:     case DSERR_UNINITIALIZED:
        !           216:         str = "The Initialize method has not been called or has not been called successfully before other methods were called";
        !           217:         break;
        !           218: #endif
        !           219: #ifdef DSERR_UNSUPPORTED
        !           220:     case DSERR_UNSUPPORTED:
        !           221:         str = "The function called is not supported at this time";
        !           222:         break;
        !           223: #endif
        !           224:     default:
        !           225:         AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
        !           226:         return;
        !           227:     }
        !           228: 
        !           229:     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
        !           230: }
        !           231: 
        !           232: static void GCC_FMT_ATTR (2, 3) dsound_logerr (
        !           233:     HRESULT hr,
        !           234:     const char *fmt,
        !           235:     ...
        !           236:     )
        !           237: {
        !           238:     va_list ap;
        !           239: 
        !           240:     va_start (ap, fmt);
        !           241:     AUD_vlog (AUDIO_CAP, fmt, ap);
        !           242:     va_end (ap);
        !           243: 
        !           244:     dsound_log_hresult (hr);
        !           245: }
        !           246: 
        !           247: static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
        !           248:     HRESULT hr,
        !           249:     const char *typ,
        !           250:     const char *fmt,
        !           251:     ...
        !           252:     )
        !           253: {
        !           254:     va_list ap;
        !           255: 
        !           256:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
        !           257:     va_start (ap, fmt);
        !           258:     AUD_vlog (AUDIO_CAP, fmt, ap);
        !           259:     va_end (ap);
        !           260: 
        !           261:     dsound_log_hresult (hr);
        !           262: }
        !           263: 
        !           264: static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
        !           265: {
        !           266:     return (millis * info->bytes_per_second) / 1000;
        !           267: }
        !           268: 
        !           269: #ifdef DEBUG_DSOUND
        !           270: static void print_wave_format (WAVEFORMATEX *wfx)
        !           271: {
        !           272:     dolog ("tag             = %d\n", wfx->wFormatTag);
        !           273:     dolog ("nChannels       = %d\n", wfx->nChannels);
        !           274:     dolog ("nSamplesPerSec  = %ld\n", wfx->nSamplesPerSec);
        !           275:     dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec);
        !           276:     dolog ("nBlockAlign     = %d\n", wfx->nBlockAlign);
        !           277:     dolog ("wBitsPerSample  = %d\n", wfx->wBitsPerSample);
        !           278:     dolog ("cbSize          = %d\n", wfx->cbSize);
        !           279: }
        !           280: #endif
        !           281: 
        !           282: static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
        !           283: {
        !           284:     HRESULT hr;
        !           285:     int i;
        !           286: 
        !           287:     for (i = 0; i < conf.restore_retries; ++i) {
        !           288:         hr = IDirectSoundBuffer_Restore (dsb);
        !           289: 
        !           290:         switch (hr) {
        !           291:         case DS_OK:
        !           292:             return 0;
        !           293: 
        !           294:         case DSERR_BUFFERLOST:
        !           295:             continue;
        !           296: 
        !           297:         default:
        !           298:             dsound_logerr (hr, "Could not restore playback buffer\n");
        !           299:             return -1;
        !           300:         }
        !           301:     }
        !           302: 
        !           303:     dolog ("%d attempts to restore playback buffer failed\n", i);
        !           304:     return -1;
        !           305: }
        !           306: 
        !           307: static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
        !           308: {
        !           309:     memset (wfx, 0, sizeof (*wfx));
        !           310: 
        !           311:     wfx->wFormatTag = WAVE_FORMAT_PCM;
        !           312:     wfx->nChannels = as->nchannels;
        !           313:     wfx->nSamplesPerSec = as->freq;
        !           314:     wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
        !           315:     wfx->nBlockAlign = 1 << (as->nchannels == 2);
        !           316:     wfx->cbSize = 0;
        !           317: 
        !           318:     switch (as->fmt) {
        !           319:     case AUD_FMT_S8:
        !           320:         wfx->wBitsPerSample = 8;
        !           321:         break;
        !           322: 
        !           323:     case AUD_FMT_U8:
        !           324:         wfx->wBitsPerSample = 8;
        !           325:         break;
        !           326: 
        !           327:     case AUD_FMT_S16:
        !           328:         wfx->wBitsPerSample = 16;
        !           329:         wfx->nAvgBytesPerSec <<= 1;
        !           330:         wfx->nBlockAlign <<= 1;
        !           331:         break;
        !           332: 
        !           333:     case AUD_FMT_U16:
        !           334:         wfx->wBitsPerSample = 16;
        !           335:         wfx->nAvgBytesPerSec <<= 1;
        !           336:         wfx->nBlockAlign <<= 1;
        !           337:         break;
        !           338: 
        !           339:     default:
        !           340:         dolog ("Internal logic error: Bad audio format %d\n", as->freq);
        !           341:         return -1;
        !           342:     }
        !           343: 
        !           344:     return 0;
        !           345: }
        !           346: 
        !           347: static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
        !           348: {
        !           349:     if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
        !           350:         dolog ("Invalid wave format, tag is not PCM, but %d\n",
        !           351:                wfx->wFormatTag);
        !           352:         return -1;
        !           353:     }
        !           354: 
        !           355:     if (!wfx->nSamplesPerSec) {
        !           356:         dolog ("Invalid wave format, frequency is zero\n");
        !           357:         return -1;
        !           358:     }
        !           359:     as->freq = wfx->nSamplesPerSec;
        !           360: 
        !           361:     switch (wfx->nChannels) {
        !           362:     case 1:
        !           363:         as->nchannels = 1;
        !           364:         break;
        !           365: 
        !           366:     case 2:
        !           367:         as->nchannels = 2;
        !           368:         break;
        !           369: 
        !           370:     default:
        !           371:         dolog (
        !           372:             "Invalid wave format, number of channels is not 1 or 2, but %d\n",
        !           373:             wfx->nChannels
        !           374:             );
        !           375:         return -1;
        !           376:     }
        !           377: 
        !           378:     switch (wfx->wBitsPerSample) {
        !           379:     case 8:
        !           380:         as->fmt = AUD_FMT_U8;
        !           381:         break;
        !           382: 
        !           383:     case 16:
        !           384:         as->fmt = AUD_FMT_S16;
        !           385:         break;
        !           386: 
        !           387:     default:
        !           388:         dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
        !           389:                wfx->wBitsPerSample);
        !           390:         return -1;
        !           391:     }
        !           392: 
        !           393:     return 0;
        !           394: }
        !           395: 
        !           396: #include "dsound_template.h"
        !           397: #define DSBTYPE_IN
        !           398: #include "dsound_template.h"
        !           399: #undef DSBTYPE_IN
        !           400: 
        !           401: static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp)
        !           402: {
        !           403:     HRESULT hr;
        !           404:     int i;
        !           405: 
        !           406:     for (i = 0; i < conf.getstatus_retries; ++i) {
        !           407:         hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
        !           408:         if (FAILED (hr)) {
        !           409:             dsound_logerr (hr, "Could not get playback buffer status\n");
        !           410:             return -1;
        !           411:         }
        !           412: 
        !           413:         if (*statusp & DSERR_BUFFERLOST) {
        !           414:             if (dsound_restore_out (dsb)) {
        !           415:                 return -1;
        !           416:             }
        !           417:             continue;
        !           418:         }
        !           419:         break;
        !           420:     }
        !           421: 
        !           422:     return 0;
        !           423: }
        !           424: 
        !           425: static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
        !           426:                                  DWORD *statusp)
        !           427: {
        !           428:     HRESULT hr;
        !           429: 
        !           430:     hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
        !           431:     if (FAILED (hr)) {
        !           432:         dsound_logerr (hr, "Could not get capture buffer status\n");
        !           433:         return -1;
        !           434:     }
        !           435: 
        !           436:     return 0;
        !           437: }
        !           438: 
        !           439: static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
        !           440: {
        !           441:     int src_len1 = dst_len;
        !           442:     int src_len2 = 0;
        !           443:     int pos = hw->rpos + dst_len;
        !           444:     st_sample_t *src1 = hw->mix_buf + hw->rpos;
        !           445:     st_sample_t *src2 = NULL;
        !           446: 
        !           447:     if (pos > hw->samples) {
        !           448:         src_len1 = hw->samples - hw->rpos;
        !           449:         src2 = hw->mix_buf;
        !           450:         src_len2 = dst_len - src_len1;
        !           451:         pos = src_len2;
        !           452:     }
        !           453: 
        !           454:     if (src_len1) {
        !           455:         hw->clip (dst, src1, src_len1);
        !           456:         mixeng_clear (src1, src_len1);
        !           457:     }
        !           458: 
        !           459:     if (src_len2) {
        !           460:         dst = advance (dst, src_len1 << hw->info.shift);
        !           461:         hw->clip (dst, src2, src_len2);
        !           462:         mixeng_clear (src2, src_len2);
        !           463:     }
        !           464: 
        !           465:     hw->rpos = pos % hw->samples;
        !           466: }
        !           467: 
        !           468: static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
        !           469: {
        !           470:     int err;
        !           471:     LPVOID p1, p2;
        !           472:     DWORD blen1, blen2, len1, len2;
        !           473: 
        !           474:     err = dsound_lock_out (
        !           475:         dsb,
        !           476:         &hw->info,
        !           477:         0,
        !           478:         hw->samples << hw->info.shift,
        !           479:         &p1, &p2,
        !           480:         &blen1, &blen2,
        !           481:         1
        !           482:         );
        !           483:     if (err) {
        !           484:         return;
        !           485:     }
        !           486: 
        !           487:     len1 = blen1 >> hw->info.shift;
        !           488:     len2 = blen2 >> hw->info.shift;
        !           489: 
        !           490: #ifdef DEBUG_DSOUND
        !           491:     dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",
        !           492:            p1, blen1, len1,
        !           493:            p2, blen2, len2);
        !           494: #endif
        !           495: 
        !           496:     if (p1 && len1) {
        !           497:         audio_pcm_info_clear_buf (&hw->info, p1, len1);
        !           498:     }
        !           499: 
        !           500:     if (p2 && len2) {
        !           501:         audio_pcm_info_clear_buf (&hw->info, p2, len2);
        !           502:     }
        !           503: 
        !           504:     dsound_unlock_out (dsb, p1, p2, blen1, blen2);
        !           505: }
        !           506: 
        !           507: static void dsound_close (dsound *s)
        !           508: {
        !           509:     HRESULT hr;
        !           510: 
        !           511:     if (s->dsound_primary_buffer) {
        !           512:         hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
        !           513:         if (FAILED (hr)) {
        !           514:             dsound_logerr (hr, "Could not release primary buffer\n");
        !           515:         }
        !           516:         s->dsound_primary_buffer = NULL;
        !           517:     }
        !           518: }
        !           519: 
        !           520: static int dsound_open (dsound *s)
        !           521: {
        !           522:     int err;
        !           523:     HRESULT hr;
        !           524:     WAVEFORMATEX wfx;
        !           525:     DSBUFFERDESC dsbd;
        !           526:     HWND hwnd;
        !           527: 
        !           528:     hwnd = GetForegroundWindow ();
        !           529:     hr = IDirectSound_SetCooperativeLevel (
        !           530:         s->dsound,
        !           531:         hwnd,
        !           532:         DSSCL_PRIORITY
        !           533:         );
        !           534: 
        !           535:     if (FAILED (hr)) {
        !           536:         dsound_logerr (hr, "Could not set cooperative level for window %p\n",
        !           537:                        hwnd);
        !           538:         return -1;
        !           539:     }
        !           540: 
        !           541:     if (!conf.set_primary) {
        !           542:         return 0;
        !           543:     }
        !           544: 
        !           545:     err = waveformat_from_audio_settings (&wfx, &conf.settings);
        !           546:     if (err) {
        !           547:         return -1;
        !           548:     }
        !           549: 
        !           550:     memset (&dsbd, 0, sizeof (dsbd));
        !           551:     dsbd.dwSize = sizeof (dsbd);
        !           552:     dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
        !           553:     dsbd.dwBufferBytes = 0;
        !           554:     dsbd.lpwfxFormat = NULL;
        !           555: 
        !           556:     hr = IDirectSound_CreateSoundBuffer (
        !           557:         s->dsound,
        !           558:         &dsbd,
        !           559:         &s->dsound_primary_buffer,
        !           560:         NULL
        !           561:         );
        !           562:     if (FAILED (hr)) {
        !           563:         dsound_logerr (hr, "Could not create primary playback buffer\n");
        !           564:         return -1;
        !           565:     }
        !           566: 
        !           567:     hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
        !           568:     if (FAILED (hr)) {
        !           569:         dsound_logerr (hr, "Could not set primary playback buffer format\n");
        !           570:     }
        !           571: 
        !           572:     hr = IDirectSoundBuffer_GetFormat (
        !           573:         s->dsound_primary_buffer,
        !           574:         &wfx,
        !           575:         sizeof (wfx),
        !           576:         NULL
        !           577:         );
        !           578:     if (FAILED (hr)) {
        !           579:         dsound_logerr (hr, "Could not get primary playback buffer format\n");
        !           580:         goto fail0;
        !           581:     }
        !           582: 
        !           583: #ifdef DEBUG_DSOUND
        !           584:     dolog ("Primary\n");
        !           585:     print_wave_format (&wfx);
        !           586: #endif
        !           587: 
        !           588:     err = waveformat_to_audio_settings (&wfx, &s->settings);
        !           589:     if (err) {
        !           590:         goto fail0;
        !           591:     }
        !           592: 
        !           593:     return 0;
        !           594: 
        !           595:  fail0:
        !           596:     dsound_close (s);
        !           597:     return -1;
        !           598: }
        !           599: 
        !           600: static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
        !           601: {
        !           602:     HRESULT hr;
        !           603:     DWORD status;
        !           604:     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
        !           605:     LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
        !           606: 
        !           607:     if (!dsb) {
        !           608:         dolog ("Attempt to control voice without a buffer\n");
        !           609:         return 0;
        !           610:     }
        !           611: 
        !           612:     switch (cmd) {
        !           613:     case VOICE_ENABLE:
        !           614:         if (dsound_get_status_out (dsb, &status)) {
        !           615:             return -1;
        !           616:         }
        !           617: 
        !           618:         if (status & DSBSTATUS_PLAYING) {
        !           619:             dolog ("warning: Voice is already playing\n");
        !           620:             return 0;
        !           621:         }
        !           622: 
        !           623:         dsound_clear_sample (hw, dsb);
        !           624: 
        !           625:         hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
        !           626:         if (FAILED (hr)) {
        !           627:             dsound_logerr (hr, "Could not start playing buffer\n");
        !           628:             return -1;
        !           629:         }
        !           630:         break;
        !           631: 
        !           632:     case VOICE_DISABLE:
        !           633:         if (dsound_get_status_out (dsb, &status)) {
        !           634:             return -1;
        !           635:         }
        !           636: 
        !           637:         if (status & DSBSTATUS_PLAYING) {
        !           638:             hr = IDirectSoundBuffer_Stop (dsb);
        !           639:             if (FAILED (hr)) {
        !           640:                 dsound_logerr (hr, "Could not stop playing buffer\n");
        !           641:                 return -1;
        !           642:             }
        !           643:         }
        !           644:         else {
        !           645:             dolog ("warning: Voice is not playing\n");
        !           646:         }
        !           647:         break;
        !           648:     }
        !           649:     return 0;
        !           650: }
        !           651: 
        !           652: static int dsound_write (SWVoiceOut *sw, void *buf, int len)
        !           653: {
        !           654:     return audio_pcm_sw_write (sw, buf, len);
        !           655: }
        !           656: 
        !           657: static int dsound_run_out (HWVoiceOut *hw)
        !           658: {
        !           659:     int err;
        !           660:     HRESULT hr;
        !           661:     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
        !           662:     LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
        !           663:     int live, len, hwshift;
        !           664:     DWORD blen1, blen2;
        !           665:     DWORD len1, len2;
        !           666:     DWORD decr;
        !           667:     DWORD wpos, ppos, old_pos;
        !           668:     LPVOID p1, p2;
        !           669:     int bufsize;
        !           670: 
        !           671:     if (!dsb) {
        !           672:         dolog ("Attempt to run empty with playback buffer\n");
        !           673:         return 0;
        !           674:     }
        !           675: 
        !           676:     hwshift = hw->info.shift;
        !           677:     bufsize = hw->samples << hwshift;
        !           678: 
        !           679:     live = audio_pcm_hw_get_live_out (hw);
        !           680: 
        !           681:     hr = IDirectSoundBuffer_GetCurrentPosition (
        !           682:         dsb,
        !           683:         &ppos,
        !           684:         ds->first_time ? &wpos : NULL
        !           685:         );
        !           686:     if (FAILED (hr)) {
        !           687:         dsound_logerr (hr, "Could not get playback buffer position\n");
        !           688:         return 0;
        !           689:     }
        !           690: 
        !           691:     len = live << hwshift;
        !           692: 
        !           693:     if (ds->first_time) {
        !           694:         if (conf.latency_millis) {
        !           695:             DWORD cur_blat;
        !           696: 
        !           697:             cur_blat = audio_ring_dist (wpos, ppos, bufsize);
        !           698:             ds->first_time = 0;
        !           699:             old_pos = wpos;
        !           700:             old_pos +=
        !           701:                 millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
        !           702:             old_pos %= bufsize;
        !           703:             old_pos &= ~hw->info.align;
        !           704:         }
        !           705:         else {
        !           706:             old_pos = wpos;
        !           707:         }
        !           708: #ifdef DEBUG_DSOUND
        !           709:         ds->played = 0;
        !           710:         ds->mixed = 0;
        !           711: #endif
        !           712:     }
        !           713:     else {
        !           714:         if (ds->old_pos == ppos) {
        !           715: #ifdef DEBUG_DSOUND
        !           716:             dolog ("old_pos == ppos\n");
        !           717: #endif
        !           718:             return 0;
        !           719:         }
        !           720: 
        !           721: #ifdef DEBUG_DSOUND
        !           722:         ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
        !           723: #endif
        !           724:         old_pos = ds->old_pos;
        !           725:     }
        !           726: 
        !           727:     if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
        !           728:         len = ppos - old_pos;
        !           729:     }
        !           730:     else {
        !           731:         if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
        !           732:             len = bufsize - old_pos + ppos;
        !           733:         }
        !           734:     }
        !           735: 
        !           736:     if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) {
        !           737:         dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
        !           738:                len, bufsize, old_pos, ppos);
        !           739:         return 0;
        !           740:     }
        !           741: 
        !           742:     len &= ~hw->info.align;
        !           743:     if (!len) {
        !           744:         return 0;
        !           745:     }
        !           746: 
        !           747: #ifdef DEBUG_DSOUND
        !           748:     ds->old_ppos = ppos;
        !           749: #endif
        !           750:     err = dsound_lock_out (
        !           751:         dsb,
        !           752:         &hw->info,
        !           753:         old_pos,
        !           754:         len,
        !           755:         &p1, &p2,
        !           756:         &blen1, &blen2,
        !           757:         0
        !           758:         );
        !           759:     if (err) {
        !           760:         return 0;
        !           761:     }
        !           762: 
        !           763:     len1 = blen1 >> hwshift;
        !           764:     len2 = blen2 >> hwshift;
        !           765:     decr = len1 + len2;
        !           766: 
        !           767:     if (p1 && len1) {
        !           768:         dsound_write_sample (hw, p1, len1);
        !           769:     }
        !           770: 
        !           771:     if (p2 && len2) {
        !           772:         dsound_write_sample (hw, p2, len2);
        !           773:     }
        !           774: 
        !           775:     dsound_unlock_out (dsb, p1, p2, blen1, blen2);
        !           776:     ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
        !           777: 
        !           778: #ifdef DEBUG_DSOUND
        !           779:     ds->mixed += decr << hwshift;
        !           780: 
        !           781:     dolog ("played %lu mixed %lu diff %ld sec %f\n",
        !           782:            ds->played,
        !           783:            ds->mixed,
        !           784:            ds->mixed - ds->played,
        !           785:            abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
        !           786: #endif
        !           787:     return decr;
        !           788: }
        !           789: 
        !           790: static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
        !           791: {
        !           792:     HRESULT hr;
        !           793:     DWORD status;
        !           794:     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
        !           795:     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
        !           796: 
        !           797:     if (!dscb) {
        !           798:         dolog ("Attempt to control capture voice without a buffer\n");
        !           799:         return -1;
        !           800:     }
        !           801: 
        !           802:     switch (cmd) {
        !           803:     case VOICE_ENABLE:
        !           804:         if (dsound_get_status_in (dscb, &status)) {
        !           805:             return -1;
        !           806:         }
        !           807: 
        !           808:         if (status & DSCBSTATUS_CAPTURING) {
        !           809:             dolog ("warning: Voice is already capturing\n");
        !           810:             return 0;
        !           811:         }
        !           812: 
        !           813:         /* clear ?? */
        !           814: 
        !           815:         hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
        !           816:         if (FAILED (hr)) {
        !           817:             dsound_logerr (hr, "Could not start capturing\n");
        !           818:             return -1;
        !           819:         }
        !           820:         break;
        !           821: 
        !           822:     case VOICE_DISABLE:
        !           823:         if (dsound_get_status_in (dscb, &status)) {
        !           824:             return -1;
        !           825:         }
        !           826: 
        !           827:         if (status & DSCBSTATUS_CAPTURING) {
        !           828:             hr = IDirectSoundCaptureBuffer_Stop (dscb);
        !           829:             if (FAILED (hr)) {
        !           830:                 dsound_logerr (hr, "Could not stop capturing\n");
        !           831:                 return -1;
        !           832:             }
        !           833:         }
        !           834:         else {
        !           835:             dolog ("warning: Voice is not capturing\n");
        !           836:         }
        !           837:         break;
        !           838:     }
        !           839:     return 0;
        !           840: }
        !           841: 
        !           842: static int dsound_read (SWVoiceIn *sw, void *buf, int len)
        !           843: {
        !           844:     return audio_pcm_sw_read (sw, buf, len);
        !           845: }
        !           846: 
        !           847: static int dsound_run_in (HWVoiceIn *hw)
        !           848: {
        !           849:     int err;
        !           850:     HRESULT hr;
        !           851:     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
        !           852:     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
        !           853:     int live, len, dead;
        !           854:     DWORD blen1, blen2;
        !           855:     DWORD len1, len2;
        !           856:     DWORD decr;
        !           857:     DWORD cpos, rpos;
        !           858:     LPVOID p1, p2;
        !           859:     int hwshift;
        !           860: 
        !           861:     if (!dscb) {
        !           862:         dolog ("Attempt to run without capture buffer\n");
        !           863:         return 0;
        !           864:     }
        !           865: 
        !           866:     hwshift = hw->info.shift;
        !           867: 
        !           868:     live = audio_pcm_hw_get_live_in (hw);
        !           869:     dead = hw->samples - live;
        !           870:     if (!dead) {
        !           871:         return 0;
        !           872:     }
        !           873: 
        !           874:     hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
        !           875:         dscb,
        !           876:         &cpos,
        !           877:         ds->first_time ? &rpos : NULL
        !           878:         );
        !           879:     if (FAILED (hr)) {
        !           880:         dsound_logerr (hr, "Could not get capture buffer position\n");
        !           881:         return 0;
        !           882:     }
        !           883: 
        !           884:     if (ds->first_time) {
        !           885:         ds->first_time = 0;
        !           886:         if (rpos & hw->info.align) {
        !           887:             ldebug ("warning: Misaligned capture read position %ld(%d)\n",
        !           888:                     rpos, hw->info.align);
        !           889:         }
        !           890:         hw->wpos = rpos >> hwshift;
        !           891:     }
        !           892: 
        !           893:     if (cpos & hw->info.align) {
        !           894:         ldebug ("warning: Misaligned capture position %ld(%d)\n",
        !           895:                 cpos, hw->info.align);
        !           896:     }
        !           897:     cpos >>= hwshift;
        !           898: 
        !           899:     len = audio_ring_dist (cpos, hw->wpos, hw->samples);
        !           900:     if (!len) {
        !           901:         return 0;
        !           902:     }
        !           903:     len = audio_MIN (len, dead);
        !           904: 
        !           905:     err = dsound_lock_in (
        !           906:         dscb,
        !           907:         &hw->info,
        !           908:         hw->wpos << hwshift,
        !           909:         len << hwshift,
        !           910:         &p1,
        !           911:         &p2,
        !           912:         &blen1,
        !           913:         &blen2,
        !           914:         0
        !           915:         );
        !           916:     if (err) {
        !           917:         return 0;
        !           918:     }
        !           919: 
        !           920:     len1 = blen1 >> hwshift;
        !           921:     len2 = blen2 >> hwshift;
        !           922:     decr = len1 + len2;
        !           923: 
        !           924:     if (p1 && len1) {
        !           925:         hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
        !           926:     }
        !           927: 
        !           928:     if (p2 && len2) {
        !           929:         hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
        !           930:     }
        !           931: 
        !           932:     dsound_unlock_in (dscb, p1, p2, blen1, blen2);
        !           933:     hw->wpos = (hw->wpos + decr) % hw->samples;
        !           934:     return decr;
        !           935: }
        !           936: 
        !           937: static void dsound_audio_fini (void *opaque)
        !           938: {
        !           939:     HRESULT hr;
        !           940:     dsound *s = opaque;
        !           941: 
        !           942:     if (!s->dsound) {
        !           943:         return;
        !           944:     }
        !           945: 
        !           946:     hr = IDirectSound_Release (s->dsound);
        !           947:     if (FAILED (hr)) {
        !           948:         dsound_logerr (hr, "Could not release DirectSound\n");
        !           949:     }
        !           950:     s->dsound = NULL;
        !           951: 
        !           952:     if (!s->dsound_capture) {
        !           953:         return;
        !           954:     }
        !           955: 
        !           956:     hr = IDirectSoundCapture_Release (s->dsound_capture);
        !           957:     if (FAILED (hr)) {
        !           958:         dsound_logerr (hr, "Could not release DirectSoundCapture\n");
        !           959:     }
        !           960:     s->dsound_capture = NULL;
        !           961: }
        !           962: 
        !           963: static void *dsound_audio_init (void)
        !           964: {
        !           965:     int err;
        !           966:     HRESULT hr;
        !           967:     dsound *s = &glob_dsound;
        !           968: 
        !           969:     hr = CoInitialize (NULL);
        !           970:     if (FAILED (hr)) {
        !           971:         dsound_logerr (hr, "Could not initialize COM\n");
        !           972:         return NULL;
        !           973:     }
        !           974: 
        !           975:     hr = CoCreateInstance (
        !           976:         &CLSID_DirectSound,
        !           977:         NULL,
        !           978:         CLSCTX_ALL,
        !           979:         &IID_IDirectSound,
        !           980:         (void **) &s->dsound
        !           981:         );
        !           982:     if (FAILED (hr)) {
        !           983:         dsound_logerr (hr, "Could not create DirectSound instance\n");
        !           984:         return NULL;
        !           985:     }
        !           986: 
        !           987:     hr = IDirectSound_Initialize (s->dsound, NULL);
        !           988:     if (FAILED (hr)) {
        !           989:         dsound_logerr (hr, "Could not initialize DirectSound\n");
        !           990:         return NULL;
        !           991:     }
        !           992: 
        !           993:     hr = CoCreateInstance (
        !           994:         &CLSID_DirectSoundCapture,
        !           995:         NULL,
        !           996:         CLSCTX_ALL,
        !           997:         &IID_IDirectSoundCapture,
        !           998:         (void **) &s->dsound_capture
        !           999:         );
        !          1000:     if (FAILED (hr)) {
        !          1001:         dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
        !          1002:     }
        !          1003:     else {
        !          1004:         hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
        !          1005:         if (FAILED (hr)) {
        !          1006:             dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
        !          1007: 
        !          1008:             hr = IDirectSoundCapture_Release (s->dsound_capture);
        !          1009:             if (FAILED (hr)) {
        !          1010:                 dsound_logerr (hr, "Could not release DirectSoundCapture\n");
        !          1011:             }
        !          1012:             s->dsound_capture = NULL;
        !          1013:         }
        !          1014:     }
        !          1015: 
        !          1016:     err = dsound_open (s);
        !          1017:     if (err) {
        !          1018:         dsound_audio_fini (s);
        !          1019:         return NULL;
        !          1020:     }
        !          1021: 
        !          1022:     return s;
        !          1023: }
        !          1024: 
        !          1025: static struct audio_option dsound_options[] = {
        !          1026:     {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
        !          1027:      "Number of times to attempt locking the buffer", NULL, 0},
        !          1028:     {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
        !          1029:      "Number of times to attempt restoring the buffer", NULL, 0},
        !          1030:     {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
        !          1031:      "Number of times to attempt getting status of the buffer", NULL, 0},
        !          1032:     {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
        !          1033:      "Set the parameters of primary buffer", NULL, 0},
        !          1034:     {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
        !          1035:      "(undocumented)", NULL, 0},
        !          1036:     {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq,
        !          1037:      "Primary buffer frequency", NULL, 0},
        !          1038:     {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
        !          1039:      "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
        !          1040:     {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt,
        !          1041:      "Primary buffer format", NULL, 0},
        !          1042:     {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
        !          1043:      "(undocumented)", NULL, 0},
        !          1044:     {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
        !          1045:      "(undocumented)", NULL, 0},
        !          1046:     {NULL, 0, NULL, NULL, NULL, 0}
        !          1047: };
        !          1048: 
        !          1049: static struct audio_pcm_ops dsound_pcm_ops = {
        !          1050:     dsound_init_out,
        !          1051:     dsound_fini_out,
        !          1052:     dsound_run_out,
        !          1053:     dsound_write,
        !          1054:     dsound_ctl_out,
        !          1055: 
        !          1056:     dsound_init_in,
        !          1057:     dsound_fini_in,
        !          1058:     dsound_run_in,
        !          1059:     dsound_read,
        !          1060:     dsound_ctl_in
        !          1061: };
        !          1062: 
        !          1063: struct audio_driver dsound_audio_driver = {
        !          1064:     INIT_FIELD (name           = ) "dsound",
        !          1065:     INIT_FIELD (descr          = )
        !          1066:     "DirectSound http://wikipedia.org/wiki/DirectSound",
        !          1067:     INIT_FIELD (options        = ) dsound_options,
        !          1068:     INIT_FIELD (init           = ) dsound_audio_init,
        !          1069:     INIT_FIELD (fini           = ) dsound_audio_fini,
        !          1070:     INIT_FIELD (pcm_ops        = ) &dsound_pcm_ops,
        !          1071:     INIT_FIELD (can_be_default = ) 1,
        !          1072:     INIT_FIELD (max_voices_out = ) INT_MAX,
        !          1073:     INIT_FIELD (max_voices_in  = ) 1,
        !          1074:     INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
        !          1075:     INIT_FIELD (voice_size_in  = ) sizeof (DSoundVoiceIn)
        !          1076: };

unix.superglobalmegacorp.com

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