audio_manager_android.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/audio/android/audio_manager_android.h" 6 7#include "base/android/build_info.h" 8#include "base/android/jni_array.h" 9#include "base/android/jni_string.h" 10#include "base/android/scoped_java_ref.h" 11#include "base/logging.h" 12#include "base/message_loop/message_loop.h" 13#include "base/strings/string_number_conversions.h" 14#include "jni/AudioManagerAndroid_jni.h" 15#include "media/audio/android/audio_record_input.h" 16#include "media/audio/android/opensles_input.h" 17#include "media/audio/android/opensles_output.h" 18#include "media/audio/audio_manager.h" 19#include "media/audio/audio_parameters.h" 20#include "media/audio/fake_audio_input_stream.h" 21#include "media/base/channel_layout.h" 22 23using base::android::AppendJavaStringArrayToStringVector; 24using base::android::AttachCurrentThread; 25using base::android::ConvertJavaStringToUTF8; 26using base::android::ConvertUTF8ToJavaString; 27using base::android::ScopedJavaLocalRef; 28 29namespace media { 30 31static void AddDefaultDevice(AudioDeviceNames* device_names) { 32 DCHECK(device_names->empty()); 33 device_names->push_front( 34 AudioDeviceName(AudioManagerBase::kDefaultDeviceName, 35 AudioManagerBase::kDefaultDeviceId)); 36} 37 38// Maximum number of output streams that can be open simultaneously. 39static const int kMaxOutputStreams = 10; 40 41static const int kDefaultInputBufferSize = 1024; 42static const int kDefaultOutputBufferSize = 2048; 43 44AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 45 return new AudioManagerAndroid(audio_log_factory); 46} 47 48AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory) 49 : AudioManagerBase(audio_log_factory), 50 communication_mode_is_on_(false) { 51 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 52 53 // WARNING: This is executed on the UI loop, do not add any code here which 54 // loads libraries or attempts to call out into the OS. Instead add such code 55 // to the InitializeOnAudioThread() method below. 56 57 // Task must be posted last to avoid races from handing out "this" to the 58 // audio thread. 59 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 60 &AudioManagerAndroid::InitializeOnAudioThread, 61 base::Unretained(this))); 62} 63 64AudioManagerAndroid::~AudioManagerAndroid() { 65 // It's safe to post a task here since Shutdown() will wait for all tasks to 66 // complete before returning. 67 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 68 &AudioManagerAndroid::ShutdownOnAudioThread, base::Unretained(this))); 69 Shutdown(); 70} 71 72bool AudioManagerAndroid::HasAudioOutputDevices() { 73 return true; 74} 75 76bool AudioManagerAndroid::HasAudioInputDevices() { 77 return true; 78} 79 80void AudioManagerAndroid::GetAudioInputDeviceNames( 81 AudioDeviceNames* device_names) { 82 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 83 84 // Always add default device parameters as first element. 85 DCHECK(device_names->empty()); 86 AddDefaultDevice(device_names); 87 88 // Get list of available audio devices. 89 JNIEnv* env = AttachCurrentThread(); 90 ScopedJavaLocalRef<jobjectArray> j_device_array = 91 Java_AudioManagerAndroid_getAudioInputDeviceNames( 92 env, j_audio_manager_.obj()); 93 jsize len = env->GetArrayLength(j_device_array.obj()); 94 AudioDeviceName device; 95 for (jsize i = 0; i < len; ++i) { 96 ScopedJavaLocalRef<jobject> j_device( 97 env, env->GetObjectArrayElement(j_device_array.obj(), i)); 98 ScopedJavaLocalRef<jstring> j_device_name = 99 Java_AudioDeviceName_name(env, j_device.obj()); 100 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); 101 ScopedJavaLocalRef<jstring> j_device_id = 102 Java_AudioDeviceName_id(env, j_device.obj()); 103 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); 104 device_names->push_back(device); 105 } 106} 107 108void AudioManagerAndroid::GetAudioOutputDeviceNames( 109 AudioDeviceNames* device_names) { 110 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). 111 AddDefaultDevice(device_names); 112} 113 114AudioParameters AudioManagerAndroid::GetInputStreamParameters( 115 const std::string& device_id) { 116 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 117 118 // Use mono as preferred number of input channels on Android to save 119 // resources. Using mono also avoids a driver issue seen on Samsung 120 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details. 121 JNIEnv* env = AttachCurrentThread(); 122 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; 123 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize( 124 env, GetNativeOutputSampleRate(), 125 ChannelLayoutToChannelCount(channel_layout)); 126 int effects = AudioParameters::NO_EFFECTS; 127 effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ? 128 AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS; 129 AudioParameters params( 130 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, 131 GetNativeOutputSampleRate(), 16, 132 buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects); 133 return params; 134} 135 136AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( 137 const AudioParameters& params, 138 const std::string& device_id) { 139 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 140 AudioOutputStream* stream = 141 AudioManagerBase::MakeAudioOutputStream(params, std::string()); 142 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); 143 return stream; 144} 145 146AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( 147 const AudioParameters& params, const std::string& device_id) { 148 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 149 bool has_no_input_streams = HasNoAudioInputStreams(); 150 AudioInputStream* stream = 151 AudioManagerBase::MakeAudioInputStream(params, device_id); 152 153 // The audio manager for Android creates streams intended for real-time 154 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION. 155 // If a Bluetooth headset is used, the audio stream will use the SCO 156 // channel and therefore have a limited bandwidth (8kHz). 157 if (stream && has_no_input_streams) { 158 communication_mode_is_on_ = true; 159 SetCommunicationAudioModeOn(true); 160 } 161 return stream; 162} 163 164void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { 165 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 166 AudioManagerBase::ReleaseOutputStream(stream); 167 streams_.erase(static_cast<OpenSLESOutputStream*>(stream)); 168} 169 170void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) { 171 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 172 DCHECK(!j_audio_manager_.is_null()); 173 AudioManagerBase::ReleaseInputStream(stream); 174 175 // Restore the audio mode which was used before the first communication- 176 // mode stream was created. 177 if (HasNoAudioInputStreams()) { 178 communication_mode_is_on_ = false; 179 SetCommunicationAudioModeOn(false); 180 } 181} 182 183AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( 184 const AudioParameters& params) { 185 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 186 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 187 return new OpenSLESOutputStream(this, params, SL_ANDROID_STREAM_MEDIA); 188} 189 190AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( 191 const AudioParameters& params, 192 const std::string& device_id) { 193 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 194 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 195 196 // Set stream type which matches the current system-wide audio mode used by 197 // the Android audio manager. 198 const SLint32 stream_type = communication_mode_is_on_ ? 199 SL_ANDROID_STREAM_VOICE : SL_ANDROID_STREAM_MEDIA; 200 return new OpenSLESOutputStream(this, params, stream_type); 201} 202 203AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( 204 const AudioParameters& params, const std::string& device_id) { 205 // TODO(henrika): add support for device selection if/when any client 206 // needs it. 207 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 208 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 209 return new OpenSLESInputStream(this, params); 210} 211 212AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( 213 const AudioParameters& params, const std::string& device_id) { 214 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 215 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 216 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; 217 218 // Use the device ID to select the correct input device. 219 // Note that the input device is always associated with a certain output 220 // device, i.e., this selection does also switch the output device. 221 // All input and output streams will be affected by the device selection. 222 if (!SetAudioDevice(device_id)) { 223 LOG(ERROR) << "Unable to select audio device!"; 224 return NULL; 225 } 226 227 if (params.effects() != AudioParameters::NO_EFFECTS) { 228 // Platform effects can only be enabled through the AudioRecord path. 229 // An effect should only have been requested here if recommended by 230 // AudioManagerAndroid.shouldUse<Effect>. 231 // 232 // Creating this class requires Jelly Bean, which is already guaranteed by 233 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use 234 // the effect settings as a way to select the input path. 235 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); 236 DVLOG(1) << "Creating AudioRecordInputStream"; 237 return new AudioRecordInputStream(this, params); 238 } 239 DVLOG(1) << "Creating OpenSLESInputStream"; 240 return new OpenSLESInputStream(this, params); 241} 242 243// static 244bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { 245 return RegisterNativesImpl(env); 246} 247 248void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { 249 GetTaskRunner()->PostTask( 250 FROM_HERE, 251 base::Bind( 252 &AudioManagerAndroid::DoSetMuteOnAudioThread, 253 base::Unretained(this), 254 muted)); 255} 256 257AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters( 258 const std::string& output_device_id, 259 const AudioParameters& input_params) { 260 // TODO(tommi): Support |output_device_id|. 261 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 262 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; 263 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 264 int sample_rate = GetNativeOutputSampleRate(); 265 int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2); 266 int bits_per_sample = 16; 267 int input_channels = 0; 268 if (input_params.IsValid()) { 269 // Use the client's input parameters if they are valid. 270 sample_rate = input_params.sample_rate(); 271 bits_per_sample = input_params.bits_per_sample(); 272 channel_layout = input_params.channel_layout(); 273 input_channels = input_params.input_channels(); 274 buffer_size = GetOptimalOutputFrameSize( 275 sample_rate, ChannelLayoutToChannelCount(channel_layout)); 276 } 277 278 int user_buffer_size = GetUserBufferSize(); 279 if (user_buffer_size) 280 buffer_size = user_buffer_size; 281 282 return AudioParameters( 283 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, 284 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); 285} 286 287bool AudioManagerAndroid::HasNoAudioInputStreams() { 288 return input_stream_count() == 0; 289} 290 291void AudioManagerAndroid::InitializeOnAudioThread() { 292 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 293 294 // Create the Android audio manager on the audio thread. 295 DVLOG(2) << "Creating Java part of the audio manager"; 296 j_audio_manager_.Reset( 297 Java_AudioManagerAndroid_createAudioManagerAndroid( 298 base::android::AttachCurrentThread(), 299 base::android::GetApplicationContext(), 300 reinterpret_cast<intptr_t>(this))); 301 302 // Prepare the list of audio devices and register receivers for device 303 // notifications. 304 Java_AudioManagerAndroid_init( 305 base::android::AttachCurrentThread(), 306 j_audio_manager_.obj()); 307} 308 309void AudioManagerAndroid::ShutdownOnAudioThread() { 310 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 311 DVLOG(2) << "Destroying Java part of the audio manager"; 312 Java_AudioManagerAndroid_close( 313 base::android::AttachCurrentThread(), 314 j_audio_manager_.obj()); 315 j_audio_manager_.Reset(); 316} 317 318void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { 319 Java_AudioManagerAndroid_setCommunicationAudioModeOn( 320 base::android::AttachCurrentThread(), 321 j_audio_manager_.obj(), on); 322} 323 324bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { 325 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 326 327 // Send the unique device ID to the Java audio manager and make the 328 // device switch. Provide an empty string to the Java audio manager 329 // if the default device is selected. 330 JNIEnv* env = AttachCurrentThread(); 331 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( 332 env, 333 device_id == AudioManagerBase::kDefaultDeviceId ? 334 std::string() : device_id); 335 return Java_AudioManagerAndroid_setDevice( 336 env, j_audio_manager_.obj(), j_device_id.obj()); 337} 338 339int AudioManagerAndroid::GetNativeOutputSampleRate() { 340 return Java_AudioManagerAndroid_getNativeOutputSampleRate( 341 base::android::AttachCurrentThread(), 342 j_audio_manager_.obj()); 343} 344 345bool AudioManagerAndroid::IsAudioLowLatencySupported() { 346 return Java_AudioManagerAndroid_isAudioLowLatencySupported( 347 base::android::AttachCurrentThread(), 348 j_audio_manager_.obj()); 349} 350 351int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { 352 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( 353 base::android::AttachCurrentThread(), 354 j_audio_manager_.obj()); 355} 356 357int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, 358 int channels) { 359 if (IsAudioLowLatencySupported()) 360 return GetAudioLowLatencyOutputFrameSize(); 361 362 return std::max(kDefaultOutputBufferSize, 363 Java_AudioManagerAndroid_getMinOutputFrameSize( 364 base::android::AttachCurrentThread(), 365 sample_rate, channels)); 366} 367 368void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { 369 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 370 for (OutputStreams::iterator it = streams_.begin(); 371 it != streams_.end(); ++it) { 372 (*it)->SetMute(muted); 373 } 374} 375 376} // namespace media 377