VirtualBox

Changeset 53392 in vbox for trunk


Ignore:
Timestamp:
Nov 24, 2014 7:35:57 PM (10 years ago)
Author:
vboxsync
Message:

Devices/Audio: handle host audio input device disconnect in the DirectSound backend.

Location:
trunk/src/VBox/Devices/Audio
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/dsound_template.h

    r32936 r53392  
     1/* $Id$ */
     2
    13/*
     4 * Copyright (C) 2014 Oracle Corporation
     5 *
     6 * This file is part of VirtualBox Open Source Edition (OSE), as
     7 * available from http://www.virtualbox.org. This file is free software;
     8 * you can redistribute it and/or modify it under the terms of the GNU
     9 * General Public License (GPL) as published by the Free Software
     10 * Foundation, in version 2 as it comes in the "COPYING" file of the
     11 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
     12 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     13 * --------------------------------------------------------------------
     14 *
     15 * This code is based on: audio.h
     16 *
    217 * QEMU DirectSound audio driver header
    318 *
     
    146161#ifdef DSBTYPE_IN
    147162static void dsound_fini_in (HWVoiceIn *hw)
     163{
     164    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
     165    dsoundCaptureClose (ds);
     166    ds->last_read_pos = 0;
     167    ds->capture_buffer_size = 0;
     168    memset (&ds->as, 0, sizeof(ds->as));
     169}
    148170#else
    149171static void dsound_fini_out (HWVoiceOut *hw)
    150 #endif
    151172{
    152173    HRESULT hr;
    153 #ifdef DSBTYPE_IN
    154     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
    155 #else
    156174    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
    157 #endif
    158175
    159176    if (ds->FIELD) {
     
    170187    }
    171188}
     189#endif
    172190
    173191#ifdef DSBTYPE_IN
    174192static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
     193{
     194    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
     195
     196    ds->last_read_pos = 0;
     197    ds->capture_buffer_size = 0;
     198    ds->dsound_capture_buffer = NULL;
     199    ds->as = *as;
     200
     201    /* Init default settings. */
     202    audio_pcm_init_info (&hw->info, &ds->as);
     203    hw->samples = conf.bufsize_in >> hw->info.shift;
     204
     205    /* Try to open capture in case the device is already there. */
     206    dsoundCaptureOpen (ds);
     207
     208    return 0;
     209}
    175210#else
    176211static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
    177 #endif
    178212{
    179213    int err;
     
    182216    WAVEFORMATEX wfx;
    183217    audsettings_t obt_as;
    184 #ifdef DSBTYPE_IN
    185     const char *typ = "ADC";
    186     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
    187     DSCBUFFERDESC bd;
    188     DSCBCAPS bc;
    189 #else
    190218    const char *typ = "DAC";
    191219    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
    192220    DSBUFFERDESC bd;
    193221    DSBCAPS bc;
    194 #endif
    195222
    196223    err = waveformat_from_audio_settings (&wfx, as);
     
    199226    }
    200227
    201 #ifdef DSBTYPE_IN
    202     if (!s->dsound_capture)
    203         return -1;
    204 #endif
    205 
    206228    memset (&bd, 0, sizeof (bd));
    207229    bd.dwSize = sizeof (bd);
    208230    bd.lpwfxFormat = &wfx;
    209 #ifdef DSBTYPE_IN
    210     bd.dwBufferBytes = conf.bufsize_in;
    211     hr = IDirectSoundCapture_CreateCaptureBuffer (
    212         s->dsound_capture,
    213         &bd,
    214         &ds->dsound_capture_buffer,
    215         NULL
    216         );
    217 #else
    218231    bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
    219232    bd.dwBufferBytes = conf.bufsize_out;
     
    224237        NULL
    225238        );
    226 #endif
    227239
    228240    if (FAILED (hr)) {
     
    285297    return -1;
    286298}
     299#endif
    287300
    288301#undef NAME
  • trunk/src/VBox/Devices/Audio/dsoundaudio.c

    r53361 r53392  
     1/* $Id$ */
     2/** @file
     3 * DirectSound Windows Host Audio Backend.
     4 */
     5
    16/*
     7 * Copyright (C) 2014 Oracle Corporation
     8 *
     9 * This file is part of VirtualBox Open Source Edition (OSE), as
     10 * available from http://www.virtualbox.org. This file is free software;
     11 * you can redistribute it and/or modify it under the terms of the GNU
     12 * General Public License (GPL) as published by the Free Software
     13 * Foundation, in version 2 as it comes in the "COPYING" file of the
     14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
     15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     16 * --------------------------------------------------------------------
     17 *
     18 * This code is based on: dsoundaudio.c
     19 *
    220 * QEMU DirectSound audio driver
    321 *
     
    4563
    4664/* #define DEBUG_DSOUND */
     65
     66#define DSLOGF(a) do { LogRel2(a); } while(0)
     67#define DSLOGREL(a)                 \
     68    do {                            \
     69        static int8_t scLogged = 0; \
     70        if (scLogged < 8) {         \
     71            ++scLogged;             \
     72            LogRel(a);              \
     73        }                           \
     74        else {                      \
     75            DSLOGF(a);              \
     76        }                           \
     77    } while (0)
    4778
    4879static struct {
     
    79110    LPDIRECTSOUNDBUFFER dsound_primary_buffer;
    80111    audsettings_t settings;
     112    LPCGUID devguidp;
     113    LPCGUID devguidp_capture;
    81114} dsound;
    82115
     
    97130typedef struct {
    98131    HWVoiceIn hw;
    99     int first_time;
     132    int last_read_pos;
     133    int capture_buffer_size;
    100134    LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
     135    audsettings_t as;
     136    HRESULT hr_last_run_in;
    101137} DSoundVoiceIn;
    102138
     
    408444
    409445    return 0;
     446}
     447
     448static void dsoundCaptureInterfaceRelease (dsound *s)
     449{
     450    if (s->dsound_capture) {
     451        HRESULT hr = IDirectSoundCapture_Release (s->dsound_capture);
     452        if (FAILED (hr)) {
     453            DSLOGF(("DSound: DirectSoundCapture release %Rhrc\n", hr));
     454        }
     455        s->dsound_capture = NULL;
     456    }
     457}
     458
     459static int dsoundCaptureInterfaceCreate (dsound *s)
     460{
     461    HRESULT hr;
     462
     463    if (s->dsound_capture != NULL) {
     464        DSLOGF(("DSound: DirectSoundCapture instance already exists\n"));
     465        return -1;
     466    }
     467
     468    hr = CoCreateInstance (&CLSID_DirectSoundCapture, NULL, CLSCTX_ALL,
     469                           &IID_IDirectSoundCapture, (void **) &s->dsound_capture);
     470    if (FAILED (hr)) {
     471        DSLOGREL(("DSound: DirectSoundCapture create instance %Rhrc\n", hr));
     472    }
     473    else {
     474        hr = IDirectSoundCapture_Initialize (s->dsound_capture, s->devguidp_capture);
     475        if (FAILED (hr)) {
     476            DSLOGREL(("DSound: DirectSoundCapture initialize %Rhrc\n", hr));
     477            dsoundCaptureInterfaceRelease (s);
     478        }
     479    }
     480
     481    return SUCCEEDED (hr)? 0: -1;
     482}
     483
     484static void dsoundCaptureClose (DSoundVoiceIn *ds)
     485{
     486    dsound *s = &glob_dsound;
     487
     488    DSLOGF(("DSound: capture close %p buffer %p\n", ds, ds->dsound_capture_buffer));
     489
     490    if (ds->dsound_capture_buffer) {
     491        HRESULT hr = IDirectSoundCaptureBuffer_Stop (ds->dsound_capture_buffer);
     492        if (FAILED (hr)) {
     493            DSLOGF(("DSound: close capture buffer stop %Rhrc\n", hr));
     494        }
     495
     496        hr = IDirectSoundCaptureBuffer_Release (ds->dsound_capture_buffer);
     497        if (FAILED (hr)) {
     498            DSLOGF(("DSound: close capture buffer release %Rhrc\n", hr));
     499        }
     500        ds->dsound_capture_buffer = NULL;
     501    }
     502
     503    dsoundCaptureInterfaceRelease (s);
     504}
     505
     506static int dsoundCaptureOpen (DSoundVoiceIn *ds)
     507{
     508    dsound *s = &glob_dsound;
     509
     510    int err;
     511    HRESULT hr;
     512    WAVEFORMATEX wfx;
     513    DSCBUFFERDESC bd;
     514    DSCBCAPS bc;
     515    DWORD cpos;
     516
     517    DSLOGF(("DSound: capture open %p size %d samples, freq %d, chan %d, bits %d, sign %d\n",
     518            ds,
     519            ds->hw.samples,
     520            ds->hw.info.freq,
     521            ds->hw.info.nchannels,
     522            ds->hw.info.bits,
     523            ds->hw.info.sign));
     524
     525    if (ds->dsound_capture_buffer != NULL) {
     526        /* Should not happen but be forgiving. */
     527        DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));
     528        dsoundCaptureClose (ds);
     529    }
     530
     531    err = waveformat_from_audio_settings (&wfx, &ds->as);
     532    if (err) {
     533        return err;
     534    }
     535
     536    err = dsoundCaptureInterfaceCreate (s);
     537    if (err) {
     538        return err;
     539    }
     540
     541    memset (&bd, 0, sizeof (bd));
     542    bd.dwSize = sizeof (bd);
     543    bd.lpwfxFormat = &wfx;
     544    bd.dwBufferBytes = ds->hw.samples << ds->hw.info.shift;
     545    hr = IDirectSoundCapture_CreateCaptureBuffer (s->dsound_capture,
     546                                                  &bd, &ds->dsound_capture_buffer, NULL);
     547
     548    if (FAILED (hr)) {
     549        DSLOGREL(("DSound: create capture buffer %Rhrc\n", hr));
     550        ds->dsound_capture_buffer = NULL;
     551        goto fail0;
     552    }
     553
     554    /* Query the actual parameters. */
     555
     556    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (ds->dsound_capture_buffer, &cpos, NULL);
     557    if (FAILED (hr)) {
     558        cpos = 0;
     559        DSLOGF(("DSound: open GetCurrentPosition %Rhrc\n", hr));
     560    }
     561
     562    memset (&wfx, 0, sizeof (wfx));
     563    hr = IDirectSoundCaptureBuffer_GetFormat (ds->dsound_capture_buffer, &wfx, sizeof (wfx), NULL);
     564    if (FAILED (hr)) {
     565        DSLOGREL(("DSound: capture buffer GetFormat %Rhrc\n", hr));
     566        goto fail0;
     567    }
     568
     569    memset (&bc, 0, sizeof (bc));
     570    bc.dwSize = sizeof (bc);
     571    hr = IDirectSoundCaptureBuffer_GetCaps (ds->dsound_capture_buffer, &bc);
     572    if (FAILED (hr)) {
     573        DSLOGREL(("DSound: capture buffer GetCaps %Rhrc\n", hr));
     574        goto fail0;
     575    }
     576
     577    DSLOGF(("DSound: capture buffer format: size %d bytes\n"
     578            "  tag             = %d\n"
     579            "  nChannels       = %d\n"
     580            "  nSamplesPerSec  = %d\n"
     581            "  nAvgBytesPerSec = %d\n"
     582            "  nBlockAlign     = %d\n"
     583            "  wBitsPerSample  = %d\n"
     584            "  cbSize          = %d\n",
     585            bc.dwBufferBytes,
     586            wfx.wFormatTag,
     587            wfx.nChannels,
     588            wfx.nSamplesPerSec,
     589            wfx.nAvgBytesPerSec,
     590            wfx.nBlockAlign,
     591            wfx.wBitsPerSample,
     592            wfx.cbSize));
     593
     594    if (bc.dwBufferBytes & ds->hw.info.align) {
     595        DSLOGREL(("DSound: GetCaps returned misaligned buffer size %ld, alignment %d\n",
     596                  bc.dwBufferBytes, ds->hw.info.align + 1));
     597    }
     598
     599    if (ds->hw.samples != 0 && ds->hw.samples != (bc.dwBufferBytes >> ds->hw.info.shift)) {
     600        DSLOGREL(("DSound: buffer size mismatch dsound %d, hw %d bytes\n",
     601                  bc.dwBufferBytes, ds->hw.samples << ds->hw.info.shift));
     602    }
     603
     604    /* Initial state: reading at the initial capture position. */
     605    ds->hw.wpos = 0;
     606    ds->last_read_pos = cpos >> ds->hw.info.shift;
     607    ds->capture_buffer_size = bc.dwBufferBytes >> ds->hw.info.shift;
     608    DSLOGF(("DSound: open last_read_pos %d, capture_buffer_size %d\n", ds->last_read_pos, ds->capture_buffer_size));
     609
     610    ds->hr_last_run_in = S_OK;
     611
     612    return 0;
     613
     614 fail0:
     615    dsoundCaptureClose (ds);
     616    return -1;
     617}
     618
     619static void dsoundCaptureStop (DSoundVoiceIn *ds)
     620{
     621    if (ds->dsound_capture_buffer) {
     622        HRESULT hr = IDirectSoundCaptureBuffer_Stop (ds->dsound_capture_buffer);
     623        if (FAILED (hr)) {
     624            DSLOGF(("DSound: stop capture buffer %Rhrc\n", hr));
     625        }
     626    }
     627}
     628
     629static int dsoundCaptureStart (DSoundVoiceIn *ds)
     630{
     631    HRESULT hr;
     632    DWORD status;
     633
     634    if (ds->dsound_capture_buffer != NULL) {
     635        hr = IDirectSoundCaptureBuffer_GetStatus (ds->dsound_capture_buffer, &status);
     636        if (FAILED (hr)) {
     637            DSLOGF(("DSound: start GetStatus %Rhrc\n", hr));
     638        }
     639        else {
     640            if (status & DSCBSTATUS_CAPTURING) {
     641                DSLOGF(("DSound: already capturing\n"));
     642            }
     643            else {
     644                hr = IDirectSoundCaptureBuffer_Start (ds->dsound_capture_buffer, DSCBSTART_LOOPING);
     645                if (FAILED (hr)) {
     646                    DSLOGREL(("DSound: start %Rhrc\n", hr));
     647                }
     648            }
     649        }
     650    }
     651    else {
     652        hr = E_FAIL;
     653    }
     654
     655    return SUCCEEDED (hr)? 0: -1;
    410656}
    411657
     
    8331079static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
    8341080{
    835     HRESULT hr;
    836     DWORD status;
    8371081    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
    838     LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
    839 
    840     if (!dscb) {
    841         dolog ("Attempt to control capture voice without a buffer\n");
    842         return -1;
    843     }
    8441082
    8451083    switch (cmd) {
    8461084    case VOICE_ENABLE:
    847         if (dsound_get_status_in (dscb, &status)) {
    848             return -1;
    849         }
    850 
    851         if (status & DSCBSTATUS_CAPTURING) {
    852             dolog ("warning: Voice is already capturing\n");
    853             return 0;
    854         }
    855 
    856         /* clear ?? */
    857 
    858         hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
    859         if (FAILED (hr)) {
    860             dsound_logerr (hr, "Could not start capturing\n");
    861             return -1;
    862         }
    863         break;
    864 
    865     case VOICE_DISABLE:
    866         if (dsound_get_status_in (dscb, &status)) {
    867             return -1;
    868         }
    869 
    870         if (status & DSCBSTATUS_CAPTURING) {
    871             hr = IDirectSoundCaptureBuffer_Stop (dscb);
    872             if (FAILED (hr)) {
    873                 dsound_logerr (hr, "Could not stop capturing\n");
     1085        /* Try to start capture. If it fails, then reopen and try again. */
     1086        if (dsoundCaptureStart (ds)) {
     1087            dsoundCaptureClose (ds);
     1088            dsoundCaptureOpen (ds);
     1089
     1090            if (dsoundCaptureStart (ds)) {
    8741091                return -1;
    8751092            }
    8761093        }
    877         else {
    878             dolog ("warning: Voice is not capturing\n");
    879         }
     1094        break;
     1095
     1096    case VOICE_DISABLE:
     1097        dsoundCaptureStop (ds);
    8801098        break;
    8811099    }
     
    8951113    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
    8961114    int live, len, dead;
     1115    int ltmp;
    8971116    DWORD blen1, blen2;
    898     DWORD len1, len2;
    899     DWORD decr;
    900     DWORD cpos, rpos;
     1117    int len1, len2;
     1118    int decr;
     1119    DWORD cpos;
    9011120    LPVOID p1, p2;
    9021121    int hwshift;
    9031122
    9041123    if (!dscb) {
    905         dolog ("Attempt to run without capture buffer\n");
     1124        DSLOGF(("DSound: run_in no capture buffer\n"));
    9061125        return 0;
    9071126    }
     
    9181137        dscb,
    9191138        &cpos,
    920         ds->first_time ? &rpos : NULL
     1139        NULL
    9211140        );
    9221141    if (FAILED (hr)) {
    923         dsound_logerr (hr, "Could not get capture buffer position\n");
     1142        if (hr != ds->hr_last_run_in) {
     1143            DSLOGREL(("DSound: run_in GetCurrentPosition %Rhrc\n", hr));
     1144        }
     1145        ds->hr_last_run_in = hr;
    9241146        return 0;
    9251147    }
    926 
    927     if (ds->first_time) {
    928         ds->first_time = 0;
    929         if (rpos & hw->info.align) {
    930             ldebug ("warning: Misaligned capture read position %ld(%d)\n",
    931                     rpos, hw->info.align);
    932         }
    933         hw->wpos = rpos >> hwshift;
    934     }
     1148    ds->hr_last_run_in = hr;
    9351149
    9361150    if (cpos & hw->info.align) {
    937         ldebug ("warning: Misaligned capture position %ld(%d)\n",
    938                 cpos, hw->info.align);
    939     }
     1151        DSLOGF(("DSound: run_in misaligned capture position %ld(%d)\n", cpos, hw->info.align));
     1152    }
     1153
    9401154    cpos >>= hwshift;
    9411155
    942     len = audio_ring_dist (cpos, hw->wpos, hw->samples);
     1156    /* Number of samples available in the capture buffer. */
     1157    len = audio_ring_dist (cpos, ds->last_read_pos, ds->capture_buffer_size);
    9431158    if (!len) {
    9441159        return 0;
     
    9491164        dscb,
    9501165        &hw->info,
    951         hw->wpos << hwshift,
     1166        ds->last_read_pos << hwshift,
    9521167        len << hwshift,
    9531168        &p1,
     
    9651180    decr = len1 + len2;
    9661181
    967 #ifndef VBOX
    9681182    if (p1 && len1) {
    969         hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
     1183        ltmp = audio_MIN(len1, hw->samples - hw->wpos);
     1184        hw->conv (hw->conv_buf + hw->wpos, p1, ltmp, &pcm_in_volume);
     1185        if (len1 > ltmp) {
     1186            hw->conv (hw->conv_buf, (void *)((uintptr_t)p1 + (ltmp << hwshift)), len1 - ltmp, &pcm_in_volume);
     1187        }
     1188        hw->wpos = (hw->wpos + len1) % hw->samples;
    9701189    }
    9711190
    9721191    if (p2 && len2) {
    973         hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
    974     }
    975 #else
    976     if (p1 && len1) {
    977         hw->conv (hw->conv_buf + hw->wpos, p1, len1, &pcm_in_volume);
    978     }
    979 
    980     if (p2 && len2) {
    981         hw->conv (hw->conv_buf, p2, len2, &pcm_in_volume);
    982     }
    983 #endif
     1192        ltmp = audio_MIN(len2, hw->samples - hw->wpos);
     1193        hw->conv (hw->conv_buf + hw->wpos, p2, ltmp, &pcm_in_volume);
     1194        if (len2 > ltmp) {
     1195            hw->conv (hw->conv_buf, (void *)((uintptr_t)p2 + (ltmp << hwshift)), len2 - ltmp, &pcm_in_volume);
     1196        }
     1197        hw->wpos = (hw->wpos + len2) % hw->samples;
     1198    }
    9841199
    9851200    dsound_unlock_in (dscb, p1, p2, blen1, blen2);
    986     hw->wpos = (hw->wpos + decr) % hw->samples;
     1201    ds->last_read_pos = (ds->last_read_pos + decr) % ds->capture_buffer_size;
    9871202    return decr;
    9881203}
     
    10811296    }
    10821297
    1083     hr = CoCreateInstance (
    1084         &CLSID_DirectSoundCapture,
    1085         NULL,
    1086         CLSCTX_ALL,
    1087         &IID_IDirectSoundCapture,
    1088         (void **) &s->dsound_capture
    1089         );
    1090     if (FAILED (hr)) {
    1091 #ifndef VBOX
    1092         dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
    1093 #else
    1094         LogRel(("DSound: Could not create DirectSoundCapture instance\n"));
    1095         dsound_log_hresult(hr);
    1096 #endif
    1097     }
    1098     else {
    1099         if (conf.device_guid_in) {
    1100             hr = RTUuidFromStr(&devguid, conf.device_guid_in);
    1101             if (FAILED (hr)) {
    1102                 LogRel(("DSound: Could not parse DirectSound input device GUID\n"));
    1103             }
    1104             devguidp = (LPCGUID)&devguid;
    1105         } else {
    1106             devguidp = NULL;
    1107         }
    1108         hr = IDirectSoundCapture_Initialize (s->dsound_capture, devguidp);
    1109         if (FAILED (hr)) {
    1110 #ifndef VBOX
    1111             dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
    1112 #else
    1113             LogRel(("DSound: Could not initialize DirectSoundCapture\n"));
    1114             dsound_log_hresult(hr);
    1115 #endif
    1116 
    1117             hr = IDirectSoundCapture_Release (s->dsound_capture);
    1118             if (FAILED (hr)) {
    1119                 dsound_logerr (hr,
    1120                                "Could not release DirectSoundCapture\n");
    1121             }
    1122             s->dsound_capture = NULL;
    1123         }
     1298    if (conf.device_guid_in) {
     1299        int rc = RTUuidFromStr(&devguid, conf.device_guid_in);
     1300        if (RT_FAILURE(rc)) {
     1301            LogRel(("DSound: Could not parse DirectSound input device GUID\n"));
     1302        }
     1303        s->devguidp = (LPCGUID)&devguid;
     1304    } else {
     1305        s->devguidp = NULL;
    11241306    }
    11251307
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette