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/strings/string_number_conversions.h" 13 #include "jni/AudioManagerAndroid_jni.h" 14 #include "media/audio/android/audio_record_input.h" 15 #include "media/audio/android/opensles_input.h" 16 #include "media/audio/android/opensles_output.h" 17 #include "media/audio/audio_manager.h" 18 #include "media/audio/audio_parameters.h" 19 #include "media/audio/fake_audio_input_stream.h" 20 #include "media/base/channel_layout.h" 21 22 using base::android::AppendJavaStringArrayToStringVector; 23 using base::android::AttachCurrentThread; 24 using base::android::ConvertJavaStringToUTF8; 25 using base::android::ConvertUTF8ToJavaString; 26 using base::android::ScopedJavaLocalRef; 27 28 namespace media { 29 30 static void AddDefaultDevice(AudioDeviceNames* device_names) { 31 DCHECK(device_names->empty()); 32 device_names->push_front( 33 AudioDeviceName(AudioManagerBase::kDefaultDeviceName, 34 AudioManagerBase::kDefaultDeviceId)); 35 } 36 37 // Maximum number of output streams that can be open simultaneously. 38 static const int kMaxOutputStreams = 10; 39 40 static const int kAudioModeNormal = 0x00000000; 41 static const int kAudioModeInCommunication = 0x00000003; 42 43 static const int kDefaultInputBufferSize = 1024; 44 static const int kDefaultOutputBufferSize = 2048; 45 46 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 47 return new AudioManagerAndroid(audio_log_factory); 48 } 49 50 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory) 51 : AudioManagerBase(audio_log_factory) { 52 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 53 54 j_audio_manager_.Reset( 55 Java_AudioManagerAndroid_createAudioManagerAndroid( 56 base::android::AttachCurrentThread(), 57 base::android::GetApplicationContext(), 58 reinterpret_cast<intptr_t>(this))); 59 Init(); 60 } 61 62 AudioManagerAndroid::~AudioManagerAndroid() { 63 Close(); 64 Shutdown(); 65 } 66 67 bool AudioManagerAndroid::HasAudioOutputDevices() { 68 return true; 69 } 70 71 bool AudioManagerAndroid::HasAudioInputDevices() { 72 return true; 73 } 74 75 void AudioManagerAndroid::GetAudioInputDeviceNames( 76 AudioDeviceNames* device_names) { 77 // Always add default device parameters as first element. 78 AddDefaultDevice(device_names); 79 80 JNIEnv* env = AttachCurrentThread(); 81 ScopedJavaLocalRef<jobjectArray> j_device_array = 82 Java_AudioManagerAndroid_getAudioInputDeviceNames( 83 env, j_audio_manager_.obj()); 84 jsize len = env->GetArrayLength(j_device_array.obj()); 85 AudioDeviceName device; 86 for (jsize i = 0; i < len; ++i) { 87 ScopedJavaLocalRef<jobject> j_device( 88 env, env->GetObjectArrayElement(j_device_array.obj(), i)); 89 ScopedJavaLocalRef<jstring> j_device_name = 90 Java_AudioDeviceName_name(env, j_device.obj()); 91 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); 92 ScopedJavaLocalRef<jstring> j_device_id = 93 Java_AudioDeviceName_id(env, j_device.obj()); 94 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); 95 device_names->push_back(device); 96 } 97 } 98 99 void AudioManagerAndroid::GetAudioOutputDeviceNames( 100 AudioDeviceNames* device_names) { 101 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). 102 AddDefaultDevice(device_names); 103 } 104 105 AudioParameters AudioManagerAndroid::GetInputStreamParameters( 106 const std::string& device_id) { 107 JNIEnv* env = AttachCurrentThread(); 108 // Use mono as preferred number of input channels on Android to save 109 // resources. Using mono also avoids a driver issue seen on Samsung 110 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details. 111 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; 112 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize( 113 env, GetNativeOutputSampleRate(), 114 ChannelLayoutToChannelCount(channel_layout)); 115 int effects = AudioParameters::NO_EFFECTS; 116 effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ? 117 AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS; 118 AudioParameters params( 119 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, 120 GetNativeOutputSampleRate(), 16, 121 buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects); 122 return params; 123 } 124 125 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( 126 const AudioParameters& params, 127 const std::string& device_id, 128 const std::string& input_device_id) { 129 AudioOutputStream* stream = 130 AudioManagerBase::MakeAudioOutputStream(params, std::string(), 131 std::string()); 132 if (stream && output_stream_count() == 1) { 133 SetAudioMode(kAudioModeInCommunication); 134 } 135 136 { 137 base::AutoLock lock(streams_lock_); 138 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); 139 } 140 141 return stream; 142 } 143 144 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( 145 const AudioParameters& params, const std::string& device_id) { 146 AudioInputStream* stream = 147 AudioManagerBase::MakeAudioInputStream(params, device_id); 148 return stream; 149 } 150 151 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { 152 AudioManagerBase::ReleaseOutputStream(stream); 153 if (!output_stream_count()) { 154 SetAudioMode(kAudioModeNormal); 155 } 156 base::AutoLock lock(streams_lock_); 157 streams_.erase(static_cast<OpenSLESOutputStream*>(stream)); 158 } 159 160 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) { 161 AudioManagerBase::ReleaseInputStream(stream); 162 } 163 164 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( 165 const AudioParameters& params) { 166 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 167 return new OpenSLESOutputStream(this, params); 168 } 169 170 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( 171 const AudioParameters& params, 172 const std::string& device_id, 173 const std::string& input_device_id) { 174 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 175 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 176 return new OpenSLESOutputStream(this, params); 177 } 178 179 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( 180 const AudioParameters& params, const std::string& device_id) { 181 // TODO(henrika): add support for device selection if/when any client 182 // needs it. 183 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 184 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 185 return new OpenSLESInputStream(this, params); 186 } 187 188 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( 189 const AudioParameters& params, const std::string& device_id) { 190 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 191 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; 192 // Utilize the device ID to select the correct input device. 193 // Note that the input device is always associated with a certain output 194 // device, i.e., this selection does also switch the output device. 195 // All input and output streams will be affected by the device selection. 196 SetAudioDevice(device_id); 197 198 if (params.effects() != AudioParameters::NO_EFFECTS) { 199 // Platform effects can only be enabled through the AudioRecord path. 200 // An effect should only have been requested here if recommended by 201 // AudioManagerAndroid.shouldUse<Effect>. 202 // 203 // Creating this class requires Jelly Bean, which is already guaranteed by 204 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use 205 // the effect settings as a way to select the input path. 206 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); 207 DVLOG(1) << "Creating AudioRecordInputStream"; 208 return new AudioRecordInputStream(this, params); 209 } 210 DVLOG(1) << "Creating OpenSLESInputStream"; 211 return new OpenSLESInputStream(this, params); 212 } 213 214 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, 215 int channels) { 216 if (IsAudioLowLatencySupported()) { 217 return GetAudioLowLatencyOutputFrameSize(); 218 } else { 219 return std::max(kDefaultOutputBufferSize, 220 Java_AudioManagerAndroid_getMinOutputFrameSize( 221 base::android::AttachCurrentThread(), 222 sample_rate, channels)); 223 } 224 } 225 226 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters( 227 const std::string& output_device_id, 228 const AudioParameters& input_params) { 229 // TODO(tommi): Support |output_device_id|. 230 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; 231 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 232 int sample_rate = GetNativeOutputSampleRate(); 233 int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2); 234 int bits_per_sample = 16; 235 int input_channels = 0; 236 if (input_params.IsValid()) { 237 // Use the client's input parameters if they are valid. 238 sample_rate = input_params.sample_rate(); 239 bits_per_sample = input_params.bits_per_sample(); 240 channel_layout = input_params.channel_layout(); 241 input_channels = input_params.input_channels(); 242 buffer_size = GetOptimalOutputFrameSize( 243 sample_rate, ChannelLayoutToChannelCount(channel_layout)); 244 } 245 246 int user_buffer_size = GetUserBufferSize(); 247 if (user_buffer_size) 248 buffer_size = user_buffer_size; 249 250 return AudioParameters( 251 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, 252 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); 253 } 254 255 // static 256 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { 257 return RegisterNativesImpl(env); 258 } 259 260 void AudioManagerAndroid::Init() { 261 Java_AudioManagerAndroid_init( 262 base::android::AttachCurrentThread(), 263 j_audio_manager_.obj()); 264 } 265 266 void AudioManagerAndroid::Close() { 267 Java_AudioManagerAndroid_close( 268 base::android::AttachCurrentThread(), 269 j_audio_manager_.obj()); 270 } 271 272 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { 273 GetMessageLoop()->PostTask( 274 FROM_HERE, 275 base::Bind( 276 &AudioManagerAndroid::DoSetMuteOnAudioThread, 277 base::Unretained(this), 278 muted)); 279 } 280 281 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { 282 base::AutoLock lock(streams_lock_); 283 for (OutputStreams::iterator it = streams_.begin(); 284 it != streams_.end(); ++it) { 285 (*it)->SetMute(muted); 286 } 287 } 288 289 void AudioManagerAndroid::SetAudioMode(int mode) { 290 Java_AudioManagerAndroid_setMode( 291 base::android::AttachCurrentThread(), 292 j_audio_manager_.obj(), mode); 293 } 294 295 void AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { 296 JNIEnv* env = AttachCurrentThread(); 297 298 // Send the unique device ID to the Java audio manager and make the 299 // device switch. Provide an empty string to the Java audio manager 300 // if the default device is selected. 301 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( 302 env, 303 device_id == AudioManagerBase::kDefaultDeviceId ? 304 std::string() : device_id); 305 Java_AudioManagerAndroid_setDevice( 306 env, j_audio_manager_.obj(), j_device_id.obj()); 307 } 308 309 int AudioManagerAndroid::GetNativeOutputSampleRate() { 310 return Java_AudioManagerAndroid_getNativeOutputSampleRate( 311 base::android::AttachCurrentThread(), 312 j_audio_manager_.obj()); 313 } 314 315 bool AudioManagerAndroid::IsAudioLowLatencySupported() { 316 return Java_AudioManagerAndroid_isAudioLowLatencySupported( 317 base::android::AttachCurrentThread(), 318 j_audio_manager_.obj()); 319 } 320 321 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { 322 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( 323 base::android::AttachCurrentThread(), 324 j_audio_manager_.obj()); 325 } 326 327 } // namespace media 328