/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ package org.webrtc.audio; import android.content.Context; import android.content.pm.PackageManager; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.os.Build; import org.webrtc.Logging; import org.webrtc.CalledByNative; /** * This class contains static functions to query sample rate and input/output audio buffer sizes. */ class WebRtcAudioManager { private static final String TAG = "WebRtcAudioManagerExternal"; private static final int DEFAULT_SAMPLE_RATE_HZ = 16000; // Default audio data format is PCM 16 bit per sample. // Guaranteed to be supported by all devices. private static final int BITS_PER_SAMPLE = 16; private static final int DEFAULT_FRAME_PER_BUFFER = 256; @CalledByNative static AudioManager getAudioManager(Context context) { return (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); } @CalledByNative static int getOutputBufferSize( Context context, AudioManager audioManager, int sampleRate, int numberOfOutputChannels) { return isLowLatencyOutputSupported(context) ? getLowLatencyFramesPerBuffer(audioManager) : getMinOutputFrameSize(sampleRate, numberOfOutputChannels); } @CalledByNative static int getInputBufferSize( Context context, AudioManager audioManager, int sampleRate, int numberOfInputChannels) { return isLowLatencyInputSupported(context) ? getLowLatencyFramesPerBuffer(audioManager) : getMinInputFrameSize(sampleRate, numberOfInputChannels); } private static boolean isLowLatencyOutputSupported(Context context) { return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY); } private static boolean isLowLatencyInputSupported(Context context) { // TODO(henrika): investigate if some sort of device list is needed here // as well. The NDK doc states that: "As of API level 21, lower latency // audio input is supported on select devices. To take advantage of this // feature, first confirm that lower latency output is available". return isLowLatencyOutputSupported(context); } /** * Returns the native input/output sample rate for this device's output stream. */ @CalledByNative static int getSampleRate(AudioManager audioManager) { // Override this if we're running on an old emulator image which only // supports 8 kHz and doesn't support PROPERTY_OUTPUT_SAMPLE_RATE. if (WebRtcAudioUtils.runningOnEmulator()) { Logging.d(TAG, "Running emulator, overriding sample rate to 8 kHz."); return 8000; } // Deliver best possible estimate based on default Android AudioManager APIs. final int sampleRateHz = getSampleRateForApiLevel(audioManager); Logging.d(TAG, "Sample rate is set to " + sampleRateHz + " Hz"); return sampleRateHz; } private static int getSampleRateForApiLevel(AudioManager audioManager) { String sampleRateString = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); return (sampleRateString == null) ? DEFAULT_SAMPLE_RATE_HZ : Integer.parseInt(sampleRateString); } // Returns the native output buffer size for low-latency output streams. private static int getLowLatencyFramesPerBuffer(AudioManager audioManager) { String framesPerBuffer = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); return framesPerBuffer == null ? DEFAULT_FRAME_PER_BUFFER : Integer.parseInt(framesPerBuffer); } // Returns the minimum output buffer size for Java based audio (AudioTrack). // This size can also be used for OpenSL ES implementations on devices that // lacks support of low-latency output. private static int getMinOutputFrameSize(int sampleRateInHz, int numChannels) { final int bytesPerFrame = numChannels * (BITS_PER_SAMPLE / 8); final int channelConfig = (numChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO); return AudioTrack.getMinBufferSize( sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT) / bytesPerFrame; } // Returns the minimum input buffer size for Java based audio (AudioRecord). // This size can calso be used for OpenSL ES implementations on devices that // lacks support of low-latency input. private static int getMinInputFrameSize(int sampleRateInHz, int numChannels) { final int bytesPerFrame = numChannels * (BITS_PER_SAMPLE / 8); final int channelConfig = (numChannels == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO); return AudioRecord.getMinBufferSize( sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT) / bytesPerFrame; } }