Home | History | Annotate | Download | only in audio
      1 /*
      2  * QEMU DirectSound audio driver header
      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 #ifdef DSBTYPE_IN
     25 #define NAME "capture buffer"
     26 #define NAME2 "DirectSoundCapture"
     27 #define TYPE in
     28 #define IFACE IDirectSoundCaptureBuffer
     29 #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
     30 #define FIELD dsound_capture_buffer
     31 #define FIELD2 dsound_capture
     32 #else
     33 #define NAME "playback buffer"
     34 #define NAME2 "DirectSound"
     35 #define TYPE out
     36 #define IFACE IDirectSoundBuffer
     37 #define BUFPTR LPDIRECTSOUNDBUFFER
     38 #define FIELD dsound_buffer
     39 #define FIELD2 dsound
     40 #endif
     41 
     42 static int glue (dsound_unlock_, TYPE) (
     43     BUFPTR buf,
     44     LPVOID p1,
     45     LPVOID p2,
     46     DWORD blen1,
     47     DWORD blen2
     48     )
     49 {
     50     HRESULT hr;
     51 
     52     hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
     53     if (FAILED (hr)) {
     54         dsound_logerr (hr, "Could not unlock " NAME "\n");
     55         return -1;
     56     }
     57 
     58     return 0;
     59 }
     60 
     61 static int glue (dsound_lock_, TYPE) (
     62     BUFPTR buf,
     63     struct audio_pcm_info *info,
     64     DWORD pos,
     65     DWORD len,
     66     LPVOID *p1p,
     67     LPVOID *p2p,
     68     DWORD *blen1p,
     69     DWORD *blen2p,
     70     int entire
     71     )
     72 {
     73     HRESULT hr;
     74     int i;
     75     LPVOID p1 = NULL, p2 = NULL;
     76     DWORD blen1 = 0, blen2 = 0;
     77     DWORD flag;
     78 
     79 #ifdef DSBTYPE_IN
     80     flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
     81 #else
     82     flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
     83 #endif
     84     for (i = 0; i < conf.lock_retries; ++i) {
     85         hr = glue (IFACE, _Lock) (
     86             buf,
     87             pos,
     88             len,
     89             &p1,
     90             &blen1,
     91             &p2,
     92             &blen2,
     93             flag
     94             );
     95 
     96         if (FAILED (hr)) {
     97 #ifndef DSBTYPE_IN
     98             if (hr == DSERR_BUFFERLOST) {
     99                 if (glue (dsound_restore_, TYPE) (buf)) {
    100                     dsound_logerr (hr, "Could not lock " NAME "\n");
    101                     goto fail;
    102                 }
    103                 continue;
    104             }
    105 #endif
    106             dsound_logerr (hr, "Could not lock " NAME "\n");
    107             goto fail;
    108         }
    109 
    110         break;
    111     }
    112 
    113     if (i == conf.lock_retries) {
    114         dolog ("%d attempts to lock " NAME " failed\n", i);
    115         goto fail;
    116     }
    117 
    118     if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
    119         dolog ("DirectSound returned misaligned buffer %ld %ld\n",
    120                blen1, blen2);
    121         glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
    122         goto fail;
    123     }
    124 
    125     if (!p1 && blen1) {
    126         dolog ("warning: !p1 && blen1=%ld\n", blen1);
    127         blen1 = 0;
    128     }
    129 
    130     if (!p2 && blen2) {
    131         dolog ("warning: !p2 && blen2=%ld\n", blen2);
    132         blen2 = 0;
    133     }
    134 
    135     *p1p = p1;
    136     *p2p = p2;
    137     *blen1p = blen1;
    138     *blen2p = blen2;
    139     return 0;
    140 
    141  fail:
    142     *p1p = NULL - 1;
    143     *p2p = NULL - 1;
    144     *blen1p = -1;
    145     *blen2p = -1;
    146     return -1;
    147 }
    148 
    149 #ifdef DSBTYPE_IN
    150 static void dsound_fini_in (HWVoiceIn *hw)
    151 #else
    152 static void dsound_fini_out (HWVoiceOut *hw)
    153 #endif
    154 {
    155     HRESULT hr;
    156 #ifdef DSBTYPE_IN
    157     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
    158 #else
    159     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
    160 #endif
    161 
    162     if (ds->FIELD) {
    163         hr = glue (IFACE, _Stop) (ds->FIELD);
    164         if (FAILED (hr)) {
    165             dsound_logerr (hr, "Could not stop " NAME "\n");
    166         }
    167 
    168         hr = glue (IFACE, _Release) (ds->FIELD);
    169         if (FAILED (hr)) {
    170             dsound_logerr (hr, "Could not release " NAME "\n");
    171         }
    172         ds->FIELD = NULL;
    173     }
    174 }
    175 
    176 #ifdef DSBTYPE_IN
    177 static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
    178 #else
    179 static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
    180 #endif
    181 {
    182     int err;
    183     HRESULT hr;
    184     dsound *s = &glob_dsound;
    185     WAVEFORMATEX wfx;
    186     struct audsettings obt_as;
    187 #ifdef DSBTYPE_IN
    188     const char *typ = "ADC";
    189     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
    190     DSCBUFFERDESC bd;
    191     DSCBCAPS bc;
    192 #else
    193     const char *typ = "DAC";
    194     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
    195     DSBUFFERDESC bd;
    196     DSBCAPS bc;
    197 #endif
    198 
    199     if (!s->FIELD2) {
    200         dolog ("Attempt to initialize voice without " NAME2 " object\n");
    201         return -1;
    202     }
    203 
    204     err = waveformat_from_audio_settings (&wfx, as);
    205     if (err) {
    206         return -1;
    207     }
    208 
    209     memset (&bd, 0, sizeof (bd));
    210     bd.dwSize = sizeof (bd);
    211     bd.lpwfxFormat = &wfx;
    212 #ifdef DSBTYPE_IN
    213     bd.dwBufferBytes = conf.bufsize_in;
    214     hr = IDirectSoundCapture_CreateCaptureBuffer (
    215         s->dsound_capture,
    216         &bd,
    217         &ds->dsound_capture_buffer,
    218         NULL
    219         );
    220 #else
    221     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
    222     bd.dwBufferBytes = conf.bufsize_out;
    223     hr = IDirectSound_CreateSoundBuffer (
    224         s->dsound,
    225         &bd,
    226         &ds->dsound_buffer,
    227         NULL
    228         );
    229 #endif
    230 
    231     if (FAILED (hr)) {
    232         dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
    233         return -1;
    234     }
    235 
    236     hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
    237     if (FAILED (hr)) {
    238         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
    239         goto fail0;
    240     }
    241 
    242 #ifdef DEBUG_DSOUND
    243     dolog (NAME "\n");
    244     print_wave_format (&wfx);
    245 #endif
    246 
    247     memset (&bc, 0, sizeof (bc));
    248     bc.dwSize = sizeof (bc);
    249 
    250     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
    251     if (FAILED (hr)) {
    252         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
    253         goto fail0;
    254     }
    255 
    256     err = waveformat_to_audio_settings (&wfx, &obt_as);
    257     if (err) {
    258         goto fail0;
    259     }
    260 
    261     ds->first_time = 1;
    262     obt_as.endianness = 0;
    263     audio_pcm_init_info (&hw->info, &obt_as);
    264 
    265     if (bc.dwBufferBytes & hw->info.align) {
    266         dolog (
    267             "GetCaps returned misaligned buffer size %ld, alignment %d\n",
    268             bc.dwBufferBytes, hw->info.align + 1
    269             );
    270     }
    271     hw->samples = bc.dwBufferBytes >> hw->info.shift;
    272 
    273 #ifdef DEBUG_DSOUND
    274     dolog ("caps %ld, desc %ld\n",
    275            bc.dwBufferBytes, bd.dwBufferBytes);
    276 
    277     dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
    278            hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
    279 #endif
    280     return 0;
    281 
    282  fail0:
    283     glue (dsound_fini_, TYPE) (hw);
    284     return -1;
    285 }
    286 
    287 #undef NAME
    288 #undef NAME2
    289 #undef TYPE
    290 #undef IFACE
    291 #undef BUFPTR
    292 #undef FIELD
    293 #undef FIELD2
    294