Skip to content

Commit 1bbef2a

Browse files
authored
fix: keep exceptions inside the audio device change callbacks (#333)
CoreAudioDeviceManager::deviceListenerProc and the IMMNotificationClient callbacks of WindowsAudioDeviceManager run on threads the operating system owns, and call code that throws jni::Exception when a device's properties cannot be read. A device that disappears between the device list and that read is an ordinary event, and the exception had no handler above it: std::terminate, and the JVM process aborted. The callbacks now log what was thrown and return normally. Fixes #332
1 parent 4d205e9 commit 1bbef2a

2 files changed

Lines changed: 70 additions & 29 deletions

File tree

‎webrtc-jni/src/main/cpp/src/media/audio/macos/CoreAudioDeviceManager.cpp‎

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <Foundation/Foundation.h>
2323
#include <IOKit/audio/IOAudioTypes.h>
2424

25+
#include <exception>
26+
2527
#if !defined(MAC_OS_VERSION_12_0) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0
2628
#define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
2729
#endif
@@ -388,28 +390,40 @@ namespace jni
388390
OSStatus CoreAudioDeviceManager::deviceListenerProc(AudioObjectID objectID, UInt32 numberAddresses, const AudioObjectPropertyAddress addresses[], void * clientData) {
389391
CoreAudioDeviceManager * manager = static_cast<CoreAudioDeviceManager *>(clientData);
390392

393+
// This runs on a CoreAudio HAL queue. An exception that leaves it has no handler above
394+
// it and terminates the process, so nothing thrown below may escape: a device that
395+
// vanishes between the device list and the read of its properties is an ordinary event
396+
// (Bluetooth profile switch, an aggregate device torn down), not a fatal one.
391397
for (int i = 0; i < numberAddresses; i++) {
392-
switch (addresses[i].mSelector) {
393-
case kAudioHardwarePropertyDevices:
394-
{
395-
manager->onDevicesChanged();
396-
break;
397-
}
398+
try {
399+
switch (addresses[i].mSelector) {
400+
case kAudioHardwarePropertyDevices:
401+
{
402+
manager->onDevicesChanged();
403+
break;
404+
}
398405

399-
case kAudioHardwarePropertyDefaultInputDevice:
400-
{
401-
AudioDevicePtr def = manager->getDefaultCaptureDevice();
402-
manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeInput, manager->captureDevices, def);
403-
break;
404-
}
406+
case kAudioHardwarePropertyDefaultInputDevice:
407+
{
408+
AudioDevicePtr def = manager->getDefaultCaptureDevice();
409+
manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeInput, manager->captureDevices, def);
410+
break;
411+
}
405412

406-
case kAudioHardwarePropertyDefaultOutputDevice:
407-
{
408-
AudioDevicePtr defp = manager->getDefaultPlaybackDevice();
409-
manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeOutput, manager->playbackDevices, defp);
410-
break;
413+
case kAudioHardwarePropertyDefaultOutputDevice:
414+
{
415+
AudioDevicePtr defp = manager->getDefaultPlaybackDevice();
416+
manager->onDefaultDeviceChanged(kAudioObjectPropertyScopeOutput, manager->playbackDevices, defp);
417+
break;
418+
}
411419
}
412420
}
421+
catch (const std::exception & e) {
422+
RTC_LOG(LS_ERROR) << "CoreAudio: Device change handling failed: " << e.what();
423+
}
424+
catch (...) {
425+
RTC_LOG(LS_ERROR) << "CoreAudio: Device change handling failed";
426+
}
413427
}
414428

415429
return noErr;

‎webrtc-jni/src/main/cpp/src/media/audio/windows/WindowsAudioDeviceManager.cpp‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "modules/audio_device/include/audio_device.h"
2828
#include "rtc_base/logging.h"
2929

30+
#include <exception>
3031
#include <stdlib.h>
3132

3233
namespace jni
@@ -408,7 +409,17 @@ namespace jni
408409
{
409410
RTC_LOG(LS_INFO) << "MMF: Device added: " << deviceId;
410411

411-
addDevice(deviceId);
412+
// IMMNotificationClient callbacks run on a system thread. An exception that leaves one
413+
// has no handler above it and terminates the process, so it is logged and dropped.
414+
try {
415+
addDevice(deviceId);
416+
}
417+
catch (const std::exception & e) {
418+
RTC_LOG(LS_ERROR) << "MMF: Device added handling failed: " << e.what();
419+
}
420+
catch (...) {
421+
RTC_LOG(LS_ERROR) << "MMF: Device added handling failed";
422+
}
412423

413424
return S_OK;
414425
}
@@ -417,7 +428,15 @@ namespace jni
417428
{
418429
RTC_LOG(LS_INFO) << "MMF: Device removed: " << deviceId;
419430

420-
removeDevice(deviceId);
431+
try {
432+
removeDevice(deviceId);
433+
}
434+
catch (const std::exception & e) {
435+
RTC_LOG(LS_ERROR) << "MMF: Device removed handling failed: " << e.what();
436+
}
437+
catch (...) {
438+
RTC_LOG(LS_ERROR) << "MMF: Device removed handling failed";
439+
}
421440

422441
return S_OK;
423442
}
@@ -430,16 +449,24 @@ namespace jni
430449
return S_OK;
431450
}
432451

433-
switch (newState) {
434-
case DEVICE_STATE_ACTIVE:
435-
addDevice(deviceId);
436-
break;
437-
438-
case DEVICE_STATE_DISABLED:
439-
case DEVICE_STATE_NOTPRESENT:
440-
case DEVICE_STATE_UNPLUGGED:
441-
removeDevice(deviceId);
442-
break;
452+
try {
453+
switch (newState) {
454+
case DEVICE_STATE_ACTIVE:
455+
addDevice(deviceId);
456+
break;
457+
458+
case DEVICE_STATE_DISABLED:
459+
case DEVICE_STATE_NOTPRESENT:
460+
case DEVICE_STATE_UNPLUGGED:
461+
removeDevice(deviceId);
462+
break;
463+
}
464+
}
465+
catch (const std::exception & e) {
466+
RTC_LOG(LS_ERROR) << "MMF: Device state change handling failed: " << e.what();
467+
}
468+
catch (...) {
469+
RTC_LOG(LS_ERROR) << "MMF: Device state change handling failed";
443470
}
444471

445472
return S_OK;

0 commit comments

Comments
 (0)