Skip to content

Commit

Permalink
[Mac] Allow audio device selection (#21)
Browse files Browse the repository at this point in the history
* first attempt

* remove unused dep

* init playout / recording

* use AudioDeviceID as guid

* switch device method

* equality

* default device

* `isDefault` property

* dont format default device name

* type param

* bypass

* refactor

* fix

* append Audio to thread labels

* ref

* lk headers

* low level apis

* fix thread checks

Some methods of ADM needs to be run on worker thread, otherwise RTC's thread check will fail.

* switch to default device when removed

* close mixerManager if didn't switch to default device

* default audio device switched

* expose devices update handler

* fix ios compile

* fix bug: don't always recreate RTCAudioDeviceModule
  • Loading branch information
hiroshihorie authored and cloudwebrtc committed Aug 3, 2022
1 parent a828846 commit f8f48bd
Show file tree
Hide file tree
Showing 25 changed files with 864 additions and 54 deletions.
4 changes: 4 additions & 0 deletions modules/audio_device/audio_device_data_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ class ADMWrapper : public AudioDeviceModule, public AudioTransport {
}
#endif // WEBRTC_IOS

int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const override {
return impl_->SetAudioDeviceSink(sink);
}

protected:
rtc::scoped_refptr<AudioDeviceModule> impl_;
AudioDeviceDataObserver* legacy_observer_ = nullptr;
Expand Down
6 changes: 6 additions & 0 deletions modules/audio_device/audio_device_generic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,10 @@ int AudioDeviceGeneric::GetRecordAudioParameters(
}
#endif // WEBRTC_IOS

int32_t AudioDeviceGeneric::SetAudioDeviceSink(AudioDeviceSink* sink) {
RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << sink << ")";
audio_device_module_sink_ = sink;
return 0;
}

} // namespace webrtc
5 changes: 5 additions & 0 deletions modules/audio_device/audio_device_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,14 @@ class AudioDeviceGeneric {
virtual int GetRecordAudioParameters(AudioParameters* params) const;
#endif // WEBRTC_IOS

int32_t SetAudioDeviceSink(AudioDeviceSink* sink);

virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0;

virtual ~AudioDeviceGeneric() {}

protected:
AudioDeviceSink* audio_device_module_sink_ = nullptr;
};

} // namespace webrtc
Expand Down
28 changes: 21 additions & 7 deletions modules/audio_device/audio_device_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,17 @@ namespace webrtc {

rtc::scoped_refptr<AudioDeviceModule> AudioDeviceModule::Create(
AudioLayer audio_layer,
TaskQueueFactory* task_queue_factory) {
TaskQueueFactory* task_queue_factory,
bool bypass_voice_processing) {
RTC_DLOG(LS_INFO) << __FUNCTION__;
return AudioDeviceModule::CreateForTest(audio_layer, task_queue_factory);
return AudioDeviceModule::CreateForTest(audio_layer, task_queue_factory, bypass_voice_processing);
}

// static
rtc::scoped_refptr<AudioDeviceModuleForTest> AudioDeviceModule::CreateForTest(
AudioLayer audio_layer,
TaskQueueFactory* task_queue_factory) {
TaskQueueFactory* task_queue_factory,
bool bypass_voice_processing) {
RTC_DLOG(LS_INFO) << __FUNCTION__;

// The "AudioDeviceModule::kWindowsCoreAudio2" audio layer has its own
Expand All @@ -93,7 +95,7 @@ rtc::scoped_refptr<AudioDeviceModuleForTest> AudioDeviceModule::CreateForTest(

// Create the generic reference counted (platform independent) implementation.
auto audio_device = rtc::make_ref_counted<AudioDeviceModuleImpl>(
audio_layer, task_queue_factory);
audio_layer, task_queue_factory, bypass_voice_processing);

// Ensure that the current platform is supported.
if (audio_device->CheckPlatform() == -1) {
Expand All @@ -116,8 +118,13 @@ rtc::scoped_refptr<AudioDeviceModuleForTest> AudioDeviceModule::CreateForTest(

AudioDeviceModuleImpl::AudioDeviceModuleImpl(
AudioLayer audio_layer,
TaskQueueFactory* task_queue_factory)
: audio_layer_(audio_layer), audio_device_buffer_(task_queue_factory) {
TaskQueueFactory* task_queue_factory,
bool bypass_voice_processing)
: audio_layer_(audio_layer),
#if defined(WEBRTC_IOS)
bypass_voice_processing_(bypass_voice_processing),
#endif
audio_device_buffer_(task_queue_factory) {
RTC_DLOG(LS_INFO) << __FUNCTION__;
}

Expand Down Expand Up @@ -280,7 +287,7 @@ int32_t AudioDeviceModuleImpl::CreatePlatformSpecificObjects() {
#if defined(WEBRTC_IOS)
if (audio_layer == kPlatformDefaultAudio) {
audio_device_.reset(
new ios_adm::AudioDeviceIOS(/*bypass_voice_processing=*/false));
new ios_adm::AudioDeviceIOS(/*bypass_voice_processing=*/bypass_voice_processing_));
RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized.";
}
// END #if defined(WEBRTC_IOS)
Expand Down Expand Up @@ -937,6 +944,13 @@ int AudioDeviceModuleImpl::GetRecordAudioParameters(
}
#endif // WEBRTC_IOS

int32_t AudioDeviceModuleImpl::SetAudioDeviceSink(AudioDeviceSink* sink) const {
RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << sink << ")";
int32_t ok = audio_device_->SetAudioDeviceSink(sink);
RTC_LOG(LS_INFO) << "output: " << ok;
return ok;
}

AudioDeviceModuleImpl::PlatformType AudioDeviceModuleImpl::Platform() const {
RTC_LOG(LS_INFO) << __FUNCTION__;
return platform_type_;
Expand Down
9 changes: 7 additions & 2 deletions modules/audio_device/audio_device_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
int32_t AttachAudioBuffer();

AudioDeviceModuleImpl(AudioLayer audio_layer,
TaskQueueFactory* task_queue_factory);
TaskQueueFactory* task_queue_factory,
bool bypass_voice_processing = false);
~AudioDeviceModuleImpl() override;

// Retrieve the currently utilized audio layer
Expand Down Expand Up @@ -145,6 +146,8 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
int GetRecordAudioParameters(AudioParameters* params) const override;
#endif // WEBRTC_IOS

int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const override;

#if defined(WEBRTC_ANDROID)
// Only use this acccessor for test purposes on Android.
AudioManager* GetAndroidAudioManagerForTest() {
Expand All @@ -165,7 +168,9 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
AudioLayer audio_layer_;
PlatformType platform_type_ = kPlatformNotSupported;
bool initialized_ = false;
#if defined(WEBRTC_ANDROID)
#if defined(WEBRTC_IOS)
bool bypass_voice_processing_;
#elif defined(WEBRTC_ANDROID)
// Should be declared first to ensure that it outlives other resources.
std::unique_ptr<AudioManager> audio_manager_android_;
#endif
Expand Down
17 changes: 15 additions & 2 deletions modules/audio_device/include/audio_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ namespace webrtc {

class AudioDeviceModuleForTest;

// Sink for callbacks related to a audio device.
class AudioDeviceSink {
public:
virtual ~AudioDeviceSink() = default;

// input/output devices updated or default device changed
virtual void OnDevicesUpdated() {}
};

class AudioDeviceModule : public rtc::RefCountInterface {
public:
enum AudioLayer {
Expand All @@ -45,12 +54,14 @@ class AudioDeviceModule : public rtc::RefCountInterface {
// Creates a default ADM for usage in production code.
static rtc::scoped_refptr<AudioDeviceModule> Create(
AudioLayer audio_layer,
TaskQueueFactory* task_queue_factory);
TaskQueueFactory* task_queue_factory,
bool bypass_voice_processing = false);
// Creates an ADM with support for extra test methods. Don't use this factory
// in production code.
static rtc::scoped_refptr<AudioDeviceModuleForTest> CreateForTest(
AudioLayer audio_layer,
TaskQueueFactory* task_queue_factory);
TaskQueueFactory* task_queue_factory,
bool bypass_voice_processing = false);

// Retrieve the currently utilized audio layer
virtual int32_t ActiveAudioLayer(AudioLayer* audioLayer) const = 0;
Expand Down Expand Up @@ -156,6 +167,8 @@ class AudioDeviceModule : public rtc::RefCountInterface {
virtual int GetRecordAudioParameters(AudioParameters* params) const = 0;
#endif // WEBRTC_IOS

virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const = 0;

protected:
~AudioDeviceModule() override {}
};
Expand Down
5 changes: 5 additions & 0 deletions modules/audio_device/include/test_audio_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ class TestAudioDeviceModuleImpl
return capturing_;
}

int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const override {
// no-op
return 0;
}

// Blocks until the Renderer refuses to receive data.
// Returns false if `timeout_ms` passes before that happens.
bool WaitForPlayoutEnd(int timeout_ms = rtc::Event::kForever) override {
Expand Down
Loading

0 comments on commit f8f48bd

Please sign in to comment.