Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reopen default device if default is changed #13

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion webrtc/details/webrtc_openal_adm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ auto kAL_EVENT_TYPE_DISCONNECTED_SOFT = ALenum();
auto kAL_SAMPLE_OFFSET_CLOCK_SOFT = ALenum();
auto kAL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT = ALenum();

auto kALC_DEVICE_LATENCY_SOFT = ALenum();
auto kALC_DEVICE_LATENCY_SOFT = ALCenum();
auto kALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT = ALCenum();
auto kALC_PLAYBACK_DEVICE_SOFT = ALCenum();
auto kALC_CAPTURE_DEVICE_SOFT = ALCenum();

using AL_INT64_TYPE = std::int64_t;

Expand All @@ -69,6 +72,16 @@ using ALEVENTPROCSOFT = void(*)(
using ALEVENTCALLBACKSOFT = void(*)(
ALEVENTPROCSOFT callback,
void *userParam);
using ALCEVENTPROCTYPESOFT = void(*)(
ALCenum eventType,
ALCenum deviceType,
ALCdevice* device,
ALCsizei length,
const ALCchar* message,
void* userParam);
using ALCEVENTCALLBACKSOFT = void(*)(
ALCEVENTPROCTYPESOFT callback,
void* userParam);
using ALCSETTHREADCONTEXT = ALCboolean(*)(ALCcontext *context);
using ALGETSOURCEI64VSOFT = void(*)(
ALuint source,
Expand All @@ -79,11 +92,22 @@ using ALCGETINTEGER64VSOFT = void(*)(
ALCenum pname,
ALsizei size,
AL_INT64_TYPE *values);
using ALCREOPENDEVICESOFT = ALCboolean(*)(
ALCdevice* device,
const ALCchar* deviceName,
const ALCint* attribs);
using ALCEVENTCONTROLSOFT = ALCboolean(*)(
ALCsizei count,
const ALCenum* events,
ALCboolean enable);

ALEVENTCALLBACKSOFT alEventCallbackSOFT/* = nullptr*/;
ALCSETTHREADCONTEXT alcSetThreadContext/* = nullptr*/;
ALGETSOURCEI64VSOFT alGetSourcei64vSOFT/* = nullptr*/;
ALCGETINTEGER64VSOFT alcGetInteger64vSOFT/* = nullptr*/;
ALCEVENTCALLBACKSOFT alcEventCallbackSOFT/* = nullptr*/;
ALCREOPENDEVICESOFT alcReopenDeviceSOFT/*= nullptr*/;
ALCEVENTCONTROLSOFT alcEventControlSOFT/*= nullptr*/;

[[nodiscard]] bool Failed(ALCdevice *device) {
if (auto code = alcGetError(device); code != ALC_NO_ERROR) {
Expand Down Expand Up @@ -268,6 +292,15 @@ int32_t AudioDeviceOpenAL::Init() {
alcGetInteger64vSOFT = (ALCGETINTEGER64VSOFT)alcGetProcAddress(
nullptr,
"alcGetInteger64vSOFT");
alcEventCallbackSOFT = (ALCEVENTCALLBACKSOFT)alcGetProcAddress(
nullptr,
"alcEventCallbackSOFT");
alcReopenDeviceSOFT = (ALCREOPENDEVICESOFT)alcGetProcAddress(
nullptr,
"alcReopenDeviceSOFT");
alcEventControlSOFT = (ALCEVENTCONTROLSOFT)alcGetProcAddress(
nullptr,
"alcEventControlSOFT");

#define RESOLVE_AL_ENUM(ENUM) k##ENUM = alGetEnumValue(#ENUM)
#define RESOLVE_ALC_ENUM(ENUM) k##ENUM = alcGetEnumValue(nullptr, #ENUM)
Expand All @@ -280,6 +313,9 @@ int32_t AudioDeviceOpenAL::Init() {
RESOLVE_AL_ENUM(AL_SAMPLE_OFFSET_CLOCK_SOFT);
RESOLVE_AL_ENUM(AL_SAMPLE_OFFSET_CLOCK_EXACT_SOFT);
RESOLVE_ALC_ENUM(ALC_DEVICE_LATENCY_SOFT);
RESOLVE_ALC_ENUM(ALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT);
RESOLVE_ALC_ENUM(ALC_PLAYBACK_DEVICE_SOFT);
RESOLVE_ALC_ENUM(ALC_CAPTURE_DEVICE_SOFT);
#undef RESOLVE_ALC_ENUM
#undef RESOLVE_AL_ENUM

Expand Down Expand Up @@ -452,11 +488,13 @@ int32_t AudioDeviceOpenAL::SetPlayoutDevice(uint16_t index) {
index,
nullptr,
&_playoutDeviceId);
_playoutIsDefaultDevice = false;
return result ? result : restartPlayout();
}

int32_t AudioDeviceOpenAL::SetPlayoutDevice(WindowsDeviceType /*device*/) {
_playoutDeviceId = ComputeDefaultDeviceId(ALC_DEFAULT_DEVICE_SPECIFIER);
_playoutIsDefaultDevice = true;
return _playoutDeviceId.empty() ? -1 : restartPlayout();
}

Expand Down Expand Up @@ -484,12 +522,14 @@ int32_t AudioDeviceOpenAL::SetRecordingDevice(uint16_t index) {
index,
nullptr,
&_recordingDeviceId);
_recordingIsDefaultDevice = false;
return result ? result : restartRecording();
}

int32_t AudioDeviceOpenAL::SetRecordingDevice(WindowsDeviceType /*device*/) {
_recordingDeviceId = ComputeDefaultDeviceId(
ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
_recordingIsDefaultDevice = true;
return _recordingDeviceId.empty() ? -1 : restartRecording();
}

Expand Down Expand Up @@ -593,6 +633,26 @@ void AudioDeviceOpenAL::openPlayoutDevice() {
message);
}, this);
}
if (alcEventCallbackSOFT) {
alcEventCallbackSOFT([](
ALCenum eventType,
ALCenum deviceType,
ALCdevice* device,
ALCsizei length,
const ALCchar* message,
void* that) {
static_cast<AudioDeviceOpenAL*>(that)->handleALCEvent(
eventType,
deviceType,
device,
length,
message);
}, this);
}
if (alcEventControlSOFT) {
const std::array<ALCenum, 1> events = { kALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT };
alcEventControlSOFT(events.size(), events.data(), ALC_TRUE);
}
});
}

Expand All @@ -612,6 +672,25 @@ void AudioDeviceOpenAL::handleEvent(
}
}

void AudioDeviceOpenAL::handleALCEvent(
ALCenum eventType,
ALCenum deviceType,
ALCdevice* device,
ALCsizei length,
const ALchar* message) {
if (eventType == kALC_EVENT_TYPE_DEFAULT_DEVICE_CHANGED_SOFT && _thread) {
const auto weak = QPointer<QObject>(&_data->context);
_thread->PostTask([=] {
if (weak) {
if (deviceType == kALC_PLAYBACK_DEVICE_SOFT && _playoutIsDefaultDevice)
reopenPlayout();
else if (deviceType == kALC_CAPTURE_DEVICE_SOFT && _recordingIsDefaultDevice)
reopenRecording();
}
});
}
}

int32_t AudioDeviceOpenAL::InitRecording() {
if (!_initialized) {
return -1;
Expand Down Expand Up @@ -1021,6 +1100,9 @@ void AudioDeviceOpenAL::stopPlayingOnThread() {
if (alEventCallbackSOFT) {
alEventCallbackSOFT(nullptr, nullptr);
}
if (alcEventCallbackSOFT) {
alcEventCallbackSOFT(nullptr, nullptr);
}
alcSetThreadContext(nullptr);
});
if (!_data->playing) {
Expand Down Expand Up @@ -1077,6 +1159,26 @@ void AudioDeviceOpenAL::restartRecordingQueued() {
});
}

void AudioDeviceOpenAL::reopenRecording() {
if (!alcReopenDeviceSOFT)
return;

if (!_recordingInitialized)
return;

alcReopenDeviceSOFT(_recordingDevice, nullptr, nullptr);
}

void AudioDeviceOpenAL::reopenPlayout() {
if (!alcReopenDeviceSOFT)
return;

if (!_playoutInitialized)
return;

alcReopenDeviceSOFT(_playoutDevice, nullptr, nullptr);
}

int AudioDeviceOpenAL::restartRecording() {
if (!_data || !_data->recording) {
return 0;
Expand Down
10 changes: 10 additions & 0 deletions webrtc/details/webrtc_openal_adm.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ class AudioDeviceOpenAL : public webrtc::AudioDeviceModule {

int restartPlayout();
int restartRecording();
void reopenPlayout();
void reopenRecording();
void restartRecordingQueued();
void restartPlayoutQueued();
bool validateRecordingDeviceId();
Expand Down Expand Up @@ -166,6 +168,12 @@ class AudioDeviceOpenAL : public webrtc::AudioDeviceModule {
ALuint param,
ALsizei length,
const ALchar *message);
void handleALCEvent(
ALCenum eventType,
ALCenum deviceType,
ALCdevice* device,
ALCsizei length,
const ALchar* message);

[[nodiscard]] crl::time countExactQueuedMsForLatency(
crl::time now,
Expand All @@ -179,13 +187,15 @@ class AudioDeviceOpenAL : public webrtc::AudioDeviceModule {
ALCdevice *_playoutDevice = nullptr;
ALCcontext *_playoutContext = nullptr;
std::string _playoutDeviceId;
bool _playoutIsDefaultDevice = false;
crl::time _playoutLatency = 0;
int _playoutChannels = 2;
bool _playoutInitialized = false;
bool _playoutFailed = false;

ALCdevice *_recordingDevice = nullptr;
std::string _recordingDeviceId;
bool _recordingIsDefaultDevice = false;
crl::time _recordingLatency = 0;
bool _recordingInitialized = false;
bool _recordingFailed = false;
Expand Down