Document how to switch audio input source
Is your feature request related to a problem? Please describe.
When using e.g. a bluetooth headset in an ongoing call, and then turning it off, it does not automatically switch to e.g. the MacBooks internal microphone.
I tried to manually switch to another audio input device, but no sound is ever transmitted to other participants.
Describe the solution you'd like
Ideally Agora would automatically switch to the next best input. Alternative please describe the steps the code would need to make in order to select another audio source.
Describe alternatives you've considered
I tried the following, which prints that it switched to my display's internal microphone, but I would never hear anything in the receiving tab.
if (audioState == rtc.AudioLocalState.Failed) {
// This case is entered when e.g. an external headset is shut off, in which case we need to use another audio device
void switchToFirstAudioRecordingDevice() async {
final audioDevices =
await engine.deviceManager.enumerateAudioRecordingDevices();
print(audioDevices);
if (audioDevices.isNotEmpty) {
await engine.muteLocalAudioStream(true);
await engine.deviceManager.setAudioRecordingDevice(
audioDevices.first.deviceId,
);
await engine.deviceManager.setAudioRecordingDeviceMute(false);
print('value.enableMicrophone');
print(value.enableMicrophone);
if (value.enableMicrophone) {
print('enabling mic after switch');
await engine.muteLocalAudioStream(false);
}
print(
'[Agora Engine] switched to device ${audioDevices.first.deviceName}',
);
}
}
switchToFirstAudioRecordingDevice();
}
Which device is best should be decided by the business, I think you can try to remove the await engine.muteLocalAudioStream(true), and call await engine.deviceManager.setAudioRecordingDevice directly.
Which device is best should be decided by the business, I think you can try to remove the
await engine.muteLocalAudioStream(true), and callawait engine.deviceManager.setAudioRecordingDevicedirectly.
The engine.muteLocalAudioStream(true) (and the optional unmuted a few lines further down), was only done in order to restore the previous user settings (whether they enabled the microphone or not). But I suppose we can simplify it and just set it once after the switch is done.
Generally though the code above does not work. That's my problem with it 😅Even though it prints that it switched to the other microphone, I can't hear myself from another participant / tab 🤔
I think you can try to remove the call of engine.muteLocalAudioStream(true) to see if work or not
I removed the muteLocalAudioStream, and then also added similar code to switch the playback device as well (else I thought maybe the recordings just end up in a void), but I still can't exchange any audio with other participants after turning the headphones off…
The following code seems to (by the prints) to switch both the playback and recording devices, but in the end no sound / recording comes out:
Future<void> ensureAudioPlaybackIsConnected() async {
bool foundPlaybackDevice = false;
try {
final playbackDeviceId =
await engine.deviceManager.getAudioPlaybackDevice();
print('playbackDeviceId: $playbackDeviceId');
foundPlaybackDevice =
playbackDeviceId?.trim().isNotEmpty == true;
} catch (e) {
// ignore, error expected when there is no device
}
print('foundPlaybackDevice: $foundPlaybackDevice');
if (!foundPlaybackDevice) {
final playbackDevices =
await engine.deviceManager.enumerateAudioPlaybackDevices();
if (playbackDevices.isNotEmpty) {
final newDevice = playbackDevices.first;
await engine.deviceManager.setAudioPlaybackDevice(
newDevice.deviceId,
);
await engine.deviceManager.setAudioPlaybackDeviceMute(false);
print(
'[Agora Engine] switched to playback device ${newDevice.deviceName}',
);
print('playback');
print(await engine.deviceManager.getAudioPlaybackDevice());
}
}
}
Future<void> ensureAudioRecordingIsConnected() async {
bool foundRecordingDevice = false;
try {
final recordingDeviceId =
await engine.deviceManager.getAudioRecordingDevice();
foundRecordingDevice =
recordingDeviceId?.trim().isNotEmpty == true;
} catch (e) {
// ignore, error expected when there is no device
}
print('foundRecordingDevice: $foundRecordingDevice');
if (!foundRecordingDevice) {
final audioDevices =
await engine.deviceManager.enumerateAudioRecordingDevices();
print(
'Available audio devices: ${audioDevices.map((d) => d.deviceName)}',
);
if (audioDevices.isNotEmpty) {
final newDevice = audioDevices.first;
await engine.deviceManager.setAudioRecordingDevice(
newDevice.deviceId,
);
await engine.deviceManager.setAudioRecordingDeviceMute(false);
await engine.enableLocalAudio(true);
print('value.enableMicrophone: ${value.enableMicrophone}');
await engine.muteLocalAudioStream(!value.enableMicrophone);
print(
'[Agora Engine] switched to recording device ${newDevice.deviceName}',
);
print('recording');
print(await engine.deviceManager.getAudioRecordingDevice());
}
}
}
ensureAudioRecordingIsConnected().then(
(_) => ensureAudioPlaybackIsConnected(),
);
The only suspicious thing I saw is that the getAudioPlaybackDevice / getAudioRecordingDevice just says default, whereas I would've expected some device-specific identifier (as it fell back to an external monitor).
If you still face this problem, please try upgrading the latest version of agora_rtc_engine to see if it works or not.
is there a way to getRecordingDevice() and change the audio input device for phones???
Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. If you find this problem please file a new issue with the same description, what happens, logs and the output. All system setups can be slightly different so it's always better to open new issues and reference the related ones. Thanks for your contribution.
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please raise a new issue.