Ticket #7757: 7757-directx_devices.patch

File 7757-directx_devices.patch, 9.6 KB (added by Jeff Lu <jll544@…>, 11 years ago)

Add device selection for DirectX sound output

  • libs/libmyth/audiooutputdx.cpp

     
    5757            dsbuffer(NULL),
    5858            playStarted(false),
    5959            writeCursor(0),
    60             lastValidTime(0)
     60            lastValidTime(0),
     61            chosenGUID(NULL),
     62            device_count(0),
     63            device_num(0)
    6164        {
    62             InitDirectSound();
    6365        }
    6466
    6567        ~AudioOutputDXPrivate()
     
    7476        }
    7577
    7678        int InitDirectSound(void);
     79        void ResetDirectSound(void);       
    7780        void DestroyDSBuffer(void);
    7881        void FillBuffer(unsigned char *buffer, int size);
    7982        bool StartPlayback(void);
    8083        void StopPlayback(bool reset);
     84        static int CALLBACK DSEnumCallback(LPGUID lpGuid,
     85                LPCSTR lpcstrDesc, LPCSTR lpcstrModule, LPVOID lpContext);
    8186
    8287    public:
    8388        AudioOutputDX *parent;
     
    8792        bool playStarted;       
    8893        DWORD writeCursor;       
    8994        DWORD lastValidTime;       
     95        GUID deviceGUID, *chosenGUID;
     96        int device_count, device_num;
     97        QString device_name;       
    9098};
    9199
    92100
     
    112120}
    113121
    114122typedef HRESULT (WINAPI *LPFNDSC) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
     123typedef HRESULT (WINAPI *LPFNDSE) (LPDSENUMCALLBACK, LPVOID);
    115124
     125int CALLBACK AudioOutputDXPrivate::DSEnumCallback(LPGUID lpGuid,
     126        LPCSTR lpcstrDesc, LPCSTR lpcstrModule, LPVOID lpContext)
     127{
     128    const QString enum_desc = lpcstrDesc,
     129                  cfg_desc = ((AudioOutputDXPrivate*)lpContext)->device_name;
     130    const int device_num = ((AudioOutputDXPrivate*)lpContext)->device_num,
     131              device_count = ((AudioOutputDXPrivate*)lpContext)->device_count;
     132
     133    VERBOSE(VB_AUDIO, QString(LOC + "Device %1:" + enum_desc)
     134            .arg(device_count));
     135
     136    if ( (device_num == device_count)
     137         || (device_num == 0 && !cfg_desc.isEmpty()
     138             && enum_desc.startsWith(cfg_desc, Qt::CaseInsensitive)) )
     139    {
     140        if (lpGuid)
     141        {
     142            ((AudioOutputDXPrivate*)lpContext)->deviceGUID = *lpGuid;
     143            ((AudioOutputDXPrivate*)lpContext)->chosenGUID =
     144                &(((AudioOutputDXPrivate*)lpContext)->deviceGUID);
     145            ((AudioOutputDXPrivate*)lpContext)->device_name = enum_desc;
     146            ((AudioOutputDXPrivate*)lpContext)->device_num = device_count;
     147        }
     148    }
     149
     150    ((AudioOutputDXPrivate*)lpContext)->device_count++;
     151    return 1;
     152}
     153
     154void AudioOutputDXPrivate::ResetDirectSound(void)
     155{
     156    DestroyDSBuffer();
     157
     158    if (dsobject)
     159    {
     160        IDirectSound_Release(dsobject);
     161        dsobject = NULL;
     162    }
     163 
     164    if (dsound_dll)
     165    {
     166       FreeLibrary(dsound_dll);
     167       dsound_dll = NULL;
     168    }
     169
     170    chosenGUID=NULL;
     171    device_count=0;
     172    device_num=0;
     173}
     174
    116175int AudioOutputDXPrivate::InitDirectSound(void)
    117176{
    118177    LPFNDSC OurDirectSoundCreate;
    119    
     178    LPFNDSE OurDirectSoundEnumerate;
     179    bool ok;
     180
     181    ResetDirectSound();
     182
    120183    dsound_dll = LoadLibrary("DSOUND.DLL");
    121184    if (dsound_dll == NULL )
    122185    {
     
    124187        goto error;
    125188    }
    126189
     190    device_name = (parent->m_UseSPDIF) ?
     191        parent->audio_passthru_device : parent->audio_main_device;
     192    device_name = device_name.section(':', 1);
     193    device_num = device_name.toInt(&ok, 10);
     194    VERBOSE(VB_AUDIO, LOC + QString("Looking for device num:%1 or name:%2")
     195            .arg(device_num).arg(device_name));
     196
     197    OurDirectSoundEnumerate =
     198        (LPFNDSE)GetProcAddress(dsound_dll, "DirectSoundEnumerateA" );
     199    if(OurDirectSoundEnumerate)
     200    {
     201        if(FAILED(OurDirectSoundEnumerate(DSEnumCallback, this)))
     202        {
     203            VERBOSE(VB_IMPORTANT, LOC_ERR + "DirectSoundEnumerate FAILED" );
     204        }
     205    }
     206
     207    if (!chosenGUID)
     208    {
     209        device_num = 0;
     210        device_name = "Primary Sound Driver";
     211    }
     212    VERBOSE(VB_AUDIO, LOC + QString("Using device %1:%2")
     213            .arg(device_num).arg(device_name));
     214
    127215    OurDirectSoundCreate =
    128216        (LPFNDSC)GetProcAddress(dsound_dll, "DirectSoundCreate");
    129217    if (OurDirectSoundCreate == NULL)
     
    132220        goto error;
    133221    }
    134222
    135     if (FAILED(OurDirectSoundCreate(NULL, &dsobject, NULL)))
     223    if (FAILED(OurDirectSoundCreate(chosenGUID, &dsobject, NULL)))
    136224    {
    137225        VERBOSE(VB_IMPORTANT, LOC_ERR + "cannot create a direct sound device" );
    138226        goto error;
     
    174262    if (dsbuffer)
    175263    {
    176264        VERBOSE(VB_AUDIO, LOC + "Destroying DirectSound buffer");
    177         IDirectSoundBuffer_Stop(dsbuffer);
     265        StopPlayback(true);
    178266        IDirectSoundBuffer_Release(dsbuffer);
    179267        dsbuffer = NULL;
    180268    }
    181     writeCursor = 0;
    182     playStarted = false;       
    183269}
    184270
    185271void AudioOutputDXPrivate::FillBuffer(unsigned char *buffer, int size)
     
    284370{
    285371    const int srates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000 };
    286372    vector<int> rates(srates, srates + sizeof(srates) / sizeof(int) );
     373    m_UseSPDIF = audio_passthru || audio_enc;
     374    if (m_UseSPDIF)
     375    {
     376        rates.clear();
     377        rates.push_back(48000);
     378    }
     379
    287380    DSCAPS devcaps;
    288381    devcaps.dwSize = sizeof(DSCAPS);
    289382
     383    m_priv->InitDirectSound();
    290384    if ((!m_priv->dsobject || !m_priv->dsound_dll) ||
    291385        FAILED(IDirectSound_GetCaps(m_priv->dsobject, &devcaps)) )
    292386    {
     
    316410    WAVEFORMATEXTENSIBLE wf;
    317411    DSBUFFERDESC         dsbdesc;
    318412
     413    CloseDevice();
     414
     415    m_UseSPDIF = audio_passthru || audio_enc;
     416    m_priv->InitDirectSound();
    319417    if (!m_priv->dsobject || !m_priv->dsound_dll)
    320418    {
    321419        Error("DirectSound initialization failed");
    322420        return false;
    323421    }
    324422
    325     CloseDevice();
    326 
    327423    SetBlocking(true);
    328424    fragment_size = (source == AUDIOOUTPUT_TELEPHONY) ? 320 : 6144;
    329425    if (audio_channels > 2)
    330426        fragment_size *= 2;
    331427    soundcard_buffer_size = kFramesNum * fragment_size;
    332428    audio_bytes_per_sample = audio_bits / 8 * audio_channels;
    333     m_UseSPDIF = audio_passthru || audio_enc;
    334429    if (m_UseSPDIF && (audio_channels != 2))
    335430    {
    336431        Error("SPDIF passthru requires 2 channel data");
     
    349444    wf.SubFormat = (m_UseSPDIF) ? _KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF
    350445                                : _KSDATAFORMAT_SUBTYPE_PCM;
    351446 
    352     VERBOSE(VB_AUDIO, LOC + QString("New format: %1bits %2ch %3Hz")
    353             .arg(audio_bits).arg(audio_channels).arg(audio_samplerate));
     447    VERBOSE(VB_AUDIO, LOC + QString("New format: %1bits %2ch %3Hz %4")
     448            .arg(audio_bits).arg(audio_channels).arg(audio_samplerate)
     449            .arg((m_UseSPDIF) ? "data" : "PCM"));
    354450
    355451    if (audio_channels <= 2)
    356452    {
     
    384480                m_priv->dsobject, &dsbdesc, &m_priv->dsbuffer, NULL);
    385481        if FAILED(dsresult)
    386482        {
    387            Error(QString("Failed to create DS buffer %1").arg((DWORD)dsresult));
    388            return false;
     483            if (dsresult == DSERR_UNSUPPORTED)
     484                Error(QString("Unsupported format for device %1:%2")
     485                        .arg(m_priv->device_num).arg(m_priv->device_name));
     486            else
     487                Error(QString("Failed to create DS buffer 0x%1")
     488                        .arg((DWORD)dsresult, 0, 16));
     489            return false;
    389490        }
    390491        VERBOSE(VB_AUDIO, LOC + "Using software mixer" );
    391492    }
     
    473574    if ( buffer_free < 0 )
    474575        buffer_free += soundcard_buffer_size;
    475576
    476     if (((write_pos > play_pos) && (m_priv->writeCursor <= write_pos)
    477                 && (m_priv->writeCursor > play_pos))
    478         || ((write_pos < play_pos) && ((m_priv->writeCursor <= write_pos)
    479                 || (play_pos < m_priv->writeCursor))))
     577    if (m_priv->lastValidTime && (currentTime > m_priv->lastValidTime))
    480578    {
    481         VERBOSE(VB_AUDIO, LOC + QString("buffer underrun(1) %1 %2 %3")
    482                     .arg(play_pos).arg(write_pos).arg(m_priv->writeCursor));
    483         // WriteCursor is in unsafe zone - stop playback for now
    484         // Next call to WriteAudio will restart the buffer
    485         m_priv->StopPlayback(false);
    486     }
    487     else if (m_priv->lastValidTime && (currentTime > m_priv->lastValidTime))
    488     {
    489579        VERBOSE(VB_AUDIO, LOC + QString("buffer underrun(2) %1 %2 %3 %4")
    490580                    .arg(play_pos).arg(write_pos).arg(m_priv->writeCursor)
    491581                    .arg(currentTime - m_priv->lastValidTime));
  • programs/mythfrontend/globalsettings.cpp

     
    8080#endif
    8181#ifdef USING_MINGW
    8282    gc->addSelection("Windows:");
    83     gc->addSelection("DirectX:");
     83    gc->addSelection("DirectX:Primary Sound Driver");
    8484#endif
    8585
    8686    gc->addSelection("NULL", "NULL");
     
    164164
    165165    gc->setLabel(QObject::tr("Digital output device"));
    166166    gc->addSelection(QObject::tr("Default"), "Default");
    167 #ifndef USING_MINGW
     167#ifdef USING_MINGW
     168    gc->addSelection("DirectX:Primary Sound Driver");
     169#else
    168170    gc->addSelection("ALSA:iec958:{ AES0 0x02 }", "ALSA:iec958:{ AES0 0x02 }");
    169171    gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
    170172    gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
     
    175177
    176178    gc->setHelpText(QObject::tr("Audio output device to use for digital audio. Default is the same as Audio output "
    177179                    "device. This value is currently only used with ALSA "
    178                     "sound output."));
     180                    "and DirectX sound output."));
    179181    return gc;
    180182}
    181183