fix(bluetooth): use Shared mode for Oboe + delay restart for BT route
Two fixes for BT audio silence: 1. Switch Oboe streams from Exclusive to Shared sharing mode. Exclusive mode bypasses Oboe's internal resampler, so opening a 48kHz stream against a BT SCO device (8/16kHz only) fails at the AudioPolicy level. Shared mode lets Oboe's resampler bridge the gap. 2. Add 500ms post-SCO delay before Oboe restart. The audio policy needs time to apply the bt-sco route after setCommunicationDevice returns. Without the delay, Oboe opens against the old device (handset). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -254,16 +254,15 @@ int wzp_oboe_start(const WzpOboeConfig* config, const WzpOboeRings* rings) {
|
||||
oboe::AudioStreamBuilder captureBuilder;
|
||||
captureBuilder.setDirection(oboe::Direction::Input)
|
||||
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||
->setSharingMode(oboe::SharingMode::Exclusive)
|
||||
// Shared mode allows Oboe's internal resampler to bridge 48kHz to
|
||||
// the hardware rate (8/16kHz for BT SCO). Exclusive mode bypasses
|
||||
// the resampler and fails with "getInputProfile could not find profile".
|
||||
->setSharingMode(oboe::SharingMode::Shared)
|
||||
->setFormat(oboe::AudioFormat::I16)
|
||||
->setChannelCount(config->channel_count)
|
||||
->setSampleRate(config->sample_rate)
|
||||
->setFramesPerDataCallback(config->frames_per_burst)
|
||||
->setInputPreset(oboe::InputPreset::VoiceCommunication)
|
||||
// Bluetooth SCO only supports 8/16kHz. Without resampling, opening
|
||||
// a 48kHz capture stream against a BT device fails with
|
||||
// "getInputProfile could not find profile". Oboe resamples internally
|
||||
// so our ring buffers stay at 48kHz regardless of the hardware rate.
|
||||
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Best)
|
||||
->setDataCallback(&g_capture_cb);
|
||||
|
||||
@@ -319,13 +318,12 @@ int wzp_oboe_start(const WzpOboeConfig* config, const WzpOboeRings* rings) {
|
||||
oboe::AudioStreamBuilder playoutBuilder;
|
||||
playoutBuilder.setDirection(oboe::Direction::Output)
|
||||
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||
->setSharingMode(oboe::SharingMode::Exclusive)
|
||||
->setSharingMode(oboe::SharingMode::Shared)
|
||||
->setFormat(oboe::AudioFormat::I16)
|
||||
->setChannelCount(config->channel_count)
|
||||
->setSampleRate(config->sample_rate)
|
||||
->setFramesPerDataCallback(config->frames_per_burst)
|
||||
->setUsage(oboe::Usage::VoiceCommunication)
|
||||
// Match capture: Oboe resamples 48kHz ↔ device rate (8/16kHz for BT SCO)
|
||||
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Best)
|
||||
->setDataCallback(&g_playout_cb);
|
||||
|
||||
|
||||
@@ -794,7 +794,7 @@ async fn set_bluetooth_sco(on: bool) -> Result<(), String> {
|
||||
// startBluetoothSco() is async — jumping straight to Oboe restart
|
||||
// would open streams against earpiece, not the BT device.
|
||||
let mut connected = false;
|
||||
for i in 0..30 {
|
||||
for i in 0..50 {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
if android_audio::is_bluetooth_sco_on().unwrap_or(false) {
|
||||
tracing::info!(polls = i + 1, "set_bluetooth_sco: SCO connected");
|
||||
@@ -803,8 +803,12 @@ async fn set_bluetooth_sco(on: bool) -> Result<(), String> {
|
||||
}
|
||||
}
|
||||
if !connected {
|
||||
tracing::warn!("set_bluetooth_sco: SCO did not connect within 3s, proceeding anyway");
|
||||
tracing::warn!("set_bluetooth_sco: SCO did not connect within 5s, proceeding anyway");
|
||||
}
|
||||
// Extra delay: even after getCommunicationDevice reports BT,
|
||||
// the audio policy needs ~500ms to apply the bt-sco route.
|
||||
// Without this, Oboe opens against the old device.
|
||||
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||
} else {
|
||||
android_audio::stop_bluetooth_sco()?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user