From b53968fd6465bce1e16cddf8b8009d3d9fea8cd1 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 30 Mar 2016 23:12:53 -0700 Subject: [PATCH 1/2] Add automatic switching the Oculus headphones and mic when activating the plugin --- libraries/plugins/src/plugins/DisplayPlugin.h | 3 + plugins/oculus/CMakeLists.txt | 5 +- plugins/oculus/src/OculusBaseDisplayPlugin.h | 1 + plugins/oculus/src/OculusDisplayPlugin.cpp | 105 ++++++++++++++++++ plugins/oculus/src/OculusDisplayPlugin.h | 11 +- 5 files changed, 118 insertions(+), 7 deletions(-) diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 77d984f924..b855e08ff1 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -74,6 +74,9 @@ public: /// whether the HMD is being worn virtual bool isDisplayVisible() const { return false; } + virtual QString getPreferredAudioInDevice() const { return QString(); } + virtual QString getPreferredAudioOutDevice() const { return QString(); } + // Rendering support /** diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index e5cbffda21..a91690ecdd 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -12,8 +12,8 @@ if (WIN32) add_definitions(-DGLEW_STATIC) set(TARGET_NAME oculus) - setup_hifi_plugin() - link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins) + setup_hifi_plugin(Multimedia) + link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins audio-client networking) include_hifi_library_headers(octree) @@ -21,5 +21,6 @@ if (WIN32) find_package(LibOVR REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) + target_link_libraries(${TARGET_NAME} Winmm.lib) endif() \ No newline at end of file diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index 2259a4ca89..71f876a82a 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -21,6 +21,7 @@ public: // Stereo specific methods virtual void resetSensors() override final; virtual void beginFrameRender(uint32_t frameIndex) override; + float getTargetFrameRate() override { return _hmdDesc.DisplayRefreshRate; } protected: diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 8078e8d6ec..9e52bb80d3 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -6,7 +6,22 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OculusDisplayPlugin.h" + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + #include +#include #include "OculusHelpers.h" const QString OculusDisplayPlugin::NAME("Oculus Rift"); @@ -18,9 +33,38 @@ bool OculusDisplayPlugin::internalActivate() { if (result && _session) { ovr_SetInt(_session, OVR_PERF_HUD_MODE, currentDebugMode); } + + auto audioClient = DependencyManager::get(); + QString riftAudioIn = getPreferredAudioInDevice(); + if (riftAudioIn != QString()) { + _savedAudioIn = audioClient->getDeviceName(QAudio::Mode::AudioInput); + QMetaObject::invokeMethod(audioClient.data(), "switchInputToAudioDevice", Q_ARG(const QString&, riftAudioIn)); + } else { + _savedAudioIn.clear(); + } + + QString riftAudioOut = getPreferredAudioOutDevice(); + if (riftAudioOut != QString()) { + _savedAudioOut = audioClient->getDeviceName(QAudio::Mode::AudioOutput); + QMetaObject::invokeMethod(audioClient.data(), "switchOutputToAudioDevice", Q_ARG(const QString&, riftAudioOut)); + } else { + _savedAudioOut.clear(); + } + return result; } +void OculusDisplayPlugin::internalDeactivate() { + auto audioClient = DependencyManager::get(); + if (_savedAudioIn != QString()) { + QMetaObject::invokeMethod(audioClient.data(), "switchInputToAudioDevice", Q_ARG(const QString&, _savedAudioIn)); + } + if (_savedAudioOut != QString()) { + QMetaObject::invokeMethod(audioClient.data(), "switchOutputToAudioDevice", Q_ARG(const QString&, _savedAudioOut)); + } + Parent::internalDeactivate(); +} + void OculusDisplayPlugin::cycleDebugOutput() { if (_session) { currentDebugMode = static_cast((currentDebugMode + 1) % ovrPerfHud_Count); @@ -86,3 +130,64 @@ void OculusDisplayPlugin::hmdPresent() { } } } + +bool OculusDisplayPlugin::isHmdMounted() const { + ovrSessionStatus status; + return (OVR_SUCCESS(ovr_GetSessionStatus(_session, &status)) && + (ovrFalse != status.HmdMounted)); +} + +static QString audioDeviceFriendlyName(LPCWSTR device) { + QString deviceName; + + HRESULT hr = S_OK; + CoInitialize(NULL); + IMMDeviceEnumerator* pMMDeviceEnumerator = NULL; + CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); + IMMDevice* pEndpoint; + hr = pMMDeviceEnumerator->GetDevice(device, &pEndpoint); + if (hr == E_NOTFOUND) { + printf("Audio Error: device not found\n"); + deviceName = QString("NONE"); + } else { + IPropertyStore* pPropertyStore; + pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); + pEndpoint->Release(); + pEndpoint = NULL; + PROPVARIANT pv; + PropVariantInit(&pv); + hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); + pPropertyStore->Release(); + pPropertyStore = NULL; + deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); + if (!IsWindows8OrGreater()) { + // Windows 7 provides only the 31 first characters of the device name. + const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31; + deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN); + } + qDebug() << " device:" << deviceName; + PropVariantClear(&pv); + } + pMMDeviceEnumerator->Release(); + pMMDeviceEnumerator = NULL; + CoUninitialize(); + return deviceName; +} + + +QString OculusDisplayPlugin::getPreferredAudioInDevice() const { + WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; + if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) { + return QString(); + } + return audioDeviceFriendlyName(buffer); +} + +QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { + WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; + if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) { + return QString(); + } + return audioDeviceFriendlyName(buffer); +} + diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index e7d7791e7f..a5dd70c68d 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -12,20 +12,19 @@ struct SwapFramebufferWrapper; using SwapFboPtr = QSharedPointer; -const float TARGET_RATE_Oculus = 75.0f; - class OculusDisplayPlugin : public OculusBaseDisplayPlugin { using Parent = OculusBaseDisplayPlugin; public: const QString& getName() const override { return NAME; } - float getTargetFrameRate() override { return TARGET_RATE_Oculus; } + QString getPreferredAudioInDevice() const override; + QString getPreferredAudioOutDevice() const override; protected: bool internalActivate() override; + void internalDeactivate() override; void hmdPresent() override; - // FIXME update with Oculus API call once it's available in the SDK - bool isHmdMounted() const override { return true; } + bool isHmdMounted() const override; void customizeContext() override; void uncustomizeContext() override; void cycleDebugOutput() override; @@ -34,6 +33,8 @@ private: static const QString NAME; bool _enablePreview { false }; bool _monoPreview { true }; + QString _savedAudioIn; + QString _savedAudioOut; SwapFboPtr _sceneFbo; }; From 97e96f7b6790531b51b1da100940e72e34fe2a34 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 31 Mar 2016 10:11:20 -0700 Subject: [PATCH 2/2] PR comments --- .../src/scripting/HMDScriptingInterface.cpp | 8 ++ .../src/scripting/HMDScriptingInterface.h | 2 + libraries/audio-client/src/AudioClient.cpp | 62 ++++++++++---- libraries/audio-client/src/AudioClient.h | 5 ++ plugins/oculus/src/OculusDisplayPlugin.cpp | 85 ++----------------- plugins/oculus/src/OculusDisplayPlugin.h | 3 - 6 files changed, 65 insertions(+), 100 deletions(-) diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index 5949b3318a..7bf1547a3c 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -97,3 +97,11 @@ bool HMDScriptingInterface::isMounted() const{ auto displayPlugin = qApp->getActiveDisplayPlugin(); return (displayPlugin->isHmd() && displayPlugin->isDisplayVisible()); } + +QString HMDScriptingInterface::preferredAudioInput() const { + return qApp->getActiveDisplayPlugin()->getPreferredAudioInDevice(); +} + +QString HMDScriptingInterface::preferredAudioOutput() const { + return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); +} diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 0057fe4eb9..d4c7b7cc0e 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -34,6 +34,8 @@ public: Q_INVOKABLE glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; Q_INVOKABLE glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; + Q_INVOKABLE QString preferredAudioInput() const; + Q_INVOKABLE QString preferredAudioOutput() const; public: HMDScriptingInterface(); diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a81a6dab09..0c7a79e2a3 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -175,6 +175,50 @@ int numDestinationSamplesRequired(const QAudioFormat& sourceFormat, const QAudio return (numSourceSamples * ratio) + 0.5f; } +#ifdef Q_OS_WIN +QString friendlyNameForAudioDevice(IMMDevice* pEndpoint) { + QString deviceName; + IPropertyStore* pPropertyStore; + pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); + pEndpoint->Release(); + pEndpoint = NULL; + PROPVARIANT pv; + PropVariantInit(&pv); + HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); + pPropertyStore->Release(); + pPropertyStore = NULL; + deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); + if (!IsWindows8OrGreater()) { + // Windows 7 provides only the 31 first characters of the device name. + const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31; + deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN); + } + PropVariantClear(&pv); + return deviceName; +} + +QString AudioClient::friendlyNameForAudioDevice(wchar_t* guid) { + QString deviceName; + HRESULT hr = S_OK; + CoInitialize(NULL); + IMMDeviceEnumerator* pMMDeviceEnumerator = NULL; + CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); + IMMDevice* pEndpoint; + hr = pMMDeviceEnumerator->GetDevice(guid, &pEndpoint); + if (hr == E_NOTFOUND) { + printf("Audio Error: device not found\n"); + deviceName = QString("NONE"); + } else { + deviceName = ::friendlyNameForAudioDevice(pEndpoint); + } + pMMDeviceEnumerator->Release(); + pMMDeviceEnumerator = NULL; + CoUninitialize(); + return deviceName; +} + +#endif + QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { #ifdef __APPLE__ if (QAudioDeviceInfo::availableDevices(mode).size() > 1) { @@ -248,23 +292,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { printf("Audio Error: device not found\n"); deviceName = QString("NONE"); } else { - IPropertyStore* pPropertyStore; - pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); - pEndpoint->Release(); - pEndpoint = NULL; - PROPVARIANT pv; - PropVariantInit(&pv); - hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); - pPropertyStore->Release(); - pPropertyStore = NULL; - deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); - if (!IsWindows8OrGreater()) { - // Windows 7 provides only the 31 first characters of the device name. - const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31; - deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN); - } - qCDebug(audioclient) << (mode == QAudio::AudioOutput ? "output" : "input") << " device:" << deviceName; - PropVariantClear(&pv); + deviceName = friendlyNameForAudioDevice(pEndpoint); } pMMDeviceEnumerator->Release(); pMMDeviceEnumerator = NULL; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index d3145629ee..3a14c878f6 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -126,6 +127,10 @@ public: static const float CALLBACK_ACCELERATOR_RATIO; +#ifdef Q_OS_WIN + static QString friendlyNameForAudioDevice(wchar_t* guid); +#endif + public slots: void start(); void stop(); diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 9e52bb80d3..a53643ba21 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -7,21 +7,13 @@ // #include "OculusDisplayPlugin.h" -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#endif +// Odd ordering of header is required to avoid 'macro redinition warnings' +#include #include -#include #include -#include + #include "OculusHelpers.h" const QString OculusDisplayPlugin::NAME("Oculus Rift"); @@ -33,38 +25,9 @@ bool OculusDisplayPlugin::internalActivate() { if (result && _session) { ovr_SetInt(_session, OVR_PERF_HUD_MODE, currentDebugMode); } - - auto audioClient = DependencyManager::get(); - QString riftAudioIn = getPreferredAudioInDevice(); - if (riftAudioIn != QString()) { - _savedAudioIn = audioClient->getDeviceName(QAudio::Mode::AudioInput); - QMetaObject::invokeMethod(audioClient.data(), "switchInputToAudioDevice", Q_ARG(const QString&, riftAudioIn)); - } else { - _savedAudioIn.clear(); - } - - QString riftAudioOut = getPreferredAudioOutDevice(); - if (riftAudioOut != QString()) { - _savedAudioOut = audioClient->getDeviceName(QAudio::Mode::AudioOutput); - QMetaObject::invokeMethod(audioClient.data(), "switchOutputToAudioDevice", Q_ARG(const QString&, riftAudioOut)); - } else { - _savedAudioOut.clear(); - } - return result; } -void OculusDisplayPlugin::internalDeactivate() { - auto audioClient = DependencyManager::get(); - if (_savedAudioIn != QString()) { - QMetaObject::invokeMethod(audioClient.data(), "switchInputToAudioDevice", Q_ARG(const QString&, _savedAudioIn)); - } - if (_savedAudioOut != QString()) { - QMetaObject::invokeMethod(audioClient.data(), "switchOutputToAudioDevice", Q_ARG(const QString&, _savedAudioOut)); - } - Parent::internalDeactivate(); -} - void OculusDisplayPlugin::cycleDebugOutput() { if (_session) { currentDebugMode = static_cast((currentDebugMode + 1) % ovrPerfHud_Count); @@ -137,50 +100,12 @@ bool OculusDisplayPlugin::isHmdMounted() const { (ovrFalse != status.HmdMounted)); } -static QString audioDeviceFriendlyName(LPCWSTR device) { - QString deviceName; - - HRESULT hr = S_OK; - CoInitialize(NULL); - IMMDeviceEnumerator* pMMDeviceEnumerator = NULL; - CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); - IMMDevice* pEndpoint; - hr = pMMDeviceEnumerator->GetDevice(device, &pEndpoint); - if (hr == E_NOTFOUND) { - printf("Audio Error: device not found\n"); - deviceName = QString("NONE"); - } else { - IPropertyStore* pPropertyStore; - pEndpoint->OpenPropertyStore(STGM_READ, &pPropertyStore); - pEndpoint->Release(); - pEndpoint = NULL; - PROPVARIANT pv; - PropVariantInit(&pv); - hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); - pPropertyStore->Release(); - pPropertyStore = NULL; - deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); - if (!IsWindows8OrGreater()) { - // Windows 7 provides only the 31 first characters of the device name. - const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31; - deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN); - } - qDebug() << " device:" << deviceName; - PropVariantClear(&pv); - } - pMMDeviceEnumerator->Release(); - pMMDeviceEnumerator = NULL; - CoUninitialize(); - return deviceName; -} - - QString OculusDisplayPlugin::getPreferredAudioInDevice() const { WCHAR buffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]; if (!OVR_SUCCESS(ovr_GetAudioDeviceInGuidStr(buffer))) { return QString(); } - return audioDeviceFriendlyName(buffer); + return AudioClient::friendlyNameForAudioDevice(buffer); } QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { @@ -188,6 +113,6 @@ QString OculusDisplayPlugin::getPreferredAudioOutDevice() const { if (!OVR_SUCCESS(ovr_GetAudioDeviceOutGuidStr(buffer))) { return QString(); } - return audioDeviceFriendlyName(buffer); + return AudioClient::friendlyNameForAudioDevice(buffer); } diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index a5dd70c68d..d6cd6f6f3d 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -22,7 +22,6 @@ public: protected: bool internalActivate() override; - void internalDeactivate() override; void hmdPresent() override; bool isHmdMounted() const override; void customizeContext() override; @@ -33,8 +32,6 @@ private: static const QString NAME; bool _enablePreview { false }; bool _monoPreview { true }; - QString _savedAudioIn; - QString _savedAudioOut; SwapFboPtr _sceneFbo; };