diff --git a/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp b/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp index cb6e12ec..97f03c7f 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp @@ -22,6 +22,8 @@ #include #include +#include + #if !defined(MAC_OS_VERSION_12_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0 #define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster #endif @@ -388,28 +390,40 @@ namespace jni OSStatus CoreAudioDeviceManager::deviceListenerProc(AudioObjectID objectID, UInt32 numberAddresses, const AudioObjectPropertyAddress addresses[], void * clientData) { CoreAudioDeviceManager * manager = static_cast(clientData); + // This runs on a CoreAudio HAL queue. An exception that leaves it has no handler above + // it and terminates the process, so nothing thrown below may escape: a device that + // vanishes between the device list and the read of its properties is an ordinary event + // (Bluetooth profile switch, an aggregate device torn down), not a fatal one. for (int i = 0; i < numberAddresses; i++) { - switch (addresses[i].mSelector) { - case kAudioHardwarePropertyDevices: - { - manager->onDevicesChanged(); - break; - } + try { + switch (addresses[i].mSelector) { + case kAudioHardwarePropertyDevices: + { + manager->onDevicesChanged(); + break; + } - case kAudioHardwarePropertyDefaultInputDevice: - { - AudioDevicePtr def = manager->getDefaultCaptureDevice(); - manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeInput, manager->captureDevices, def); - break; - } + case kAudioHardwarePropertyDefaultInputDevice: + { + AudioDevicePtr def = manager->getDefaultCaptureDevice(); + manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeInput, manager->captureDevices, def); + break; + } - case kAudioHardwarePropertyDefaultOutputDevice: - { - AudioDevicePtr defp = manager->getDefaultPlaybackDevice(); - manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeOutput, manager->playbackDevices, defp); - break; + case kAudioHardwarePropertyDefaultOutputDevice: + { + AudioDevicePtr defp = manager->getDefaultPlaybackDevice(); + manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeOutput, manager->playbackDevices, defp); + break; + } } } + catch (const std::exception & e) { + RTC_LOG(LS_ERROR) << "CoreAudio: Device change handling failed: " << e.what(); + } + catch (...) { + RTC_LOG(LS_ERROR) << "CoreAudio: Device change handling failed"; + } } return noErr; diff --git a/webrtc-jni/src/main/cpp/src/media/audio/windows/WindowsAudioDeviceManager.cpp b/webrtc-jni/src/main/cpp/src/media/audio/windows/WindowsAudioDeviceManager.cpp index 705d8dd7..2a46bf1b 100644 --- a/webrtc-jni/src/main/cpp/src/media/audio/windows/WindowsAudioDeviceManager.cpp +++ b/webrtc-jni/src/main/cpp/src/media/audio/windows/WindowsAudioDeviceManager.cpp @@ -27,6 +27,7 @@ #include "modules/audio_device/include/audio_device.h" #include "rtc_base/logging.h" +#include #include namespace jni @@ -408,7 +409,17 @@ namespace jni { RTC_LOG(LS_INFO) << "MMF: Device added: " << deviceId; - addDevice(deviceId); + // IMMNotificationClient callbacks run on a system thread. An exception that leaves one + // has no handler above it and terminates the process, so it is logged and dropped. + try { + addDevice(deviceId); + } + catch (const std::exception & e) { + RTC_LOG(LS_ERROR) << "MMF: Device added handling failed: " << e.what(); + } + catch (...) { + RTC_LOG(LS_ERROR) << "MMF: Device added handling failed"; + } return S_OK; } @@ -417,7 +428,15 @@ namespace jni { RTC_LOG(LS_INFO) << "MMF: Device removed: " << deviceId; - removeDevice(deviceId); + try { + removeDevice(deviceId); + } + catch (const std::exception & e) { + RTC_LOG(LS_ERROR) << "MMF: Device removed handling failed: " << e.what(); + } + catch (...) { + RTC_LOG(LS_ERROR) << "MMF: Device removed handling failed"; + } return S_OK; } @@ -430,16 +449,24 @@ namespace jni return S_OK; } - switch (newState) { - case DEVICE_STATE_ACTIVE: - addDevice(deviceId); - break; - - case DEVICE_STATE_DISABLED: - case DEVICE_STATE_NOTPRESENT: - case DEVICE_STATE_UNPLUGGED: - removeDevice(deviceId); - break; + try { + switch (newState) { + case DEVICE_STATE_ACTIVE: + addDevice(deviceId); + break; + + case DEVICE_STATE_DISABLED: + case DEVICE_STATE_NOTPRESENT: + case DEVICE_STATE_UNPLUGGED: + removeDevice(deviceId); + break; + } + } + catch (const std::exception & e) { + RTC_LOG(LS_ERROR) << "MMF: Device state change handling failed: " << e.what(); + } + catch (...) { + RTC_LOG(LS_ERROR) << "MMF: Device state change handling failed"; } return S_OK;