|
8 | 8 | import android.graphics.SurfaceTexture; |
9 | 9 | import android.hardware.Camera; |
10 | 10 | import android.hardware.Camera.CameraInfo; |
| 11 | +import android.media.AudioManager; |
11 | 12 | import android.media.MediaRecorder; |
12 | 13 | import android.media.AudioAttributes; |
13 | 14 | import android.media.AudioDeviceInfo; |
@@ -202,7 +203,7 @@ void dispose() { |
202 | 203 | } |
203 | 204 |
|
204 | 205 | private void initialize(boolean bypassVoiceProcessing, int networkIgnoreMask, boolean forceSWCodec, List<String> forceSWCodecList, |
205 | | - @Nullable ConstraintsMap androidAudioConfiguration, Severity logSeverity) { |
| 206 | + @Nullable ConstraintsMap androidAudioConfiguration, Severity logSeverity, @Nullable Integer audioSampleRate, @Nullable Integer audioOutputSampleRate) { |
206 | 207 | if (mFactory != null) { |
207 | 208 | return; |
208 | 209 | } |
@@ -261,6 +262,39 @@ private void initialize(boolean bypassVoiceProcessing, int networkIgnoreMask, bo |
261 | 262 | .setUseHardwareNoiseSuppressor(useHardwareAudioProcessing); |
262 | 263 | } |
263 | 264 |
|
| 265 | + // Configure audio sample rates if specified |
| 266 | + // This allows high-quality audio playback instead of defaulting to WebRtcAudioManager's queried rate |
| 267 | + if (audioSampleRate != null) { |
| 268 | + Log.i(TAG, "Setting audio sample rate (both input and output) to: " + audioSampleRate + " Hz"); |
| 269 | + audioDeviceModuleBuilder.setSampleRate(audioSampleRate); |
| 270 | + } |
| 271 | + |
| 272 | + // audioOutputSampleRate takes precedence over audioSampleRate for output |
| 273 | + if (audioOutputSampleRate != null) { |
| 274 | + Log.i(TAG, "Setting audio output sample rate to: " + audioOutputSampleRate + " Hz"); |
| 275 | + audioDeviceModuleBuilder.setOutputSampleRate(audioOutputSampleRate); |
| 276 | + } else if (bypassVoiceProcessing && audioSampleRate == null && audioOutputSampleRate == null) { |
| 277 | + // When bypassVoiceProcessing is enabled, use the device's native optimal sample rate |
| 278 | + // This prevents the default behavior which may use a low sample rate based on audio mode |
| 279 | + AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); |
| 280 | + if (audioManager != null) { |
| 281 | + String nativeSampleRateStr = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); |
| 282 | + int nativeSampleRate = 48000; // fallback default |
| 283 | + if (nativeSampleRateStr != null) { |
| 284 | + try { |
| 285 | + nativeSampleRate = Integer.parseInt(nativeSampleRateStr); |
| 286 | + } catch (NumberFormatException e) { |
| 287 | + Log.w(TAG, "Failed to parse native sample rate, using default: " + e.getMessage()); |
| 288 | + } |
| 289 | + } |
| 290 | + Log.i(TAG, "bypassVoiceProcessing enabled with no explicit sample rate - using device's native optimal rate: " + nativeSampleRate + " Hz"); |
| 291 | + audioDeviceModuleBuilder.setOutputSampleRate(nativeSampleRate); |
| 292 | + } else { |
| 293 | + Log.w(TAG, "AudioManager not available, defaulting to 48000 Hz output"); |
| 294 | + audioDeviceModuleBuilder.setOutputSampleRate(48000); |
| 295 | + } |
| 296 | + } |
| 297 | + |
264 | 298 | audioDeviceModuleBuilder.setSamplesReadyCallback(recordSamplesReadyCallbackAdapter); |
265 | 299 | audioDeviceModuleBuilder.setPlaybackSamplesReadyCallback(playbackSamplesReadyCallbackAdapter); |
266 | 300 |
|
@@ -401,7 +435,19 @@ public void onMethodCall(MethodCall call, @NonNull Result notSafeResult) { |
401 | 435 | logSeverity = str2LogSeverity(logSeverityStr); |
402 | 436 | } |
403 | 437 |
|
404 | | - initialize(enableBypassVoiceProcessing, networkIgnoreMask, forceSWCodec, forceSWCodecList, androidAudioConfiguration, logSeverity); |
| 438 | + Integer audioSampleRate = null; |
| 439 | + if (constraintsMap.hasKey("audioSampleRate") |
| 440 | + && constraintsMap.getType("audioSampleRate") == ObjectType.Number) { |
| 441 | + audioSampleRate = constraintsMap.getInt("audioSampleRate"); |
| 442 | + } |
| 443 | + |
| 444 | + Integer audioOutputSampleRate = null; |
| 445 | + if (constraintsMap.hasKey("audioOutputSampleRate") |
| 446 | + && constraintsMap.getType("audioOutputSampleRate") == ObjectType.Number) { |
| 447 | + audioOutputSampleRate = constraintsMap.getInt("audioOutputSampleRate"); |
| 448 | + } |
| 449 | + |
| 450 | + initialize(enableBypassVoiceProcessing, networkIgnoreMask, forceSWCodec, forceSWCodecList, androidAudioConfiguration, logSeverity, audioSampleRate, audioOutputSampleRate); |
405 | 451 | result.success(null); |
406 | 452 | break; |
407 | 453 | } |
|
0 commit comments