Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/android/audio_manager_android.h" | 5 #include "media/audio/android/audio_manager_android.h" |
| 6 | 6 |
| 7 #include "base/android/build_info.h" | 7 #include "base/android/build_info.h" |
| 8 #include "base/android/jni_array.h" | 8 #include "base/android/jni_array.h" |
| 9 #include "base/android/jni_string.h" | 9 #include "base/android/jni_string.h" |
| 10 #include "base/android/scoped_java_ref.h" | 10 #include "base/android/scoped_java_ref.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop/message_loop.h" | |
| 12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 13 #include "jni/AudioManagerAndroid_jni.h" | 14 #include "jni/AudioManagerAndroid_jni.h" |
| 14 #include "media/audio/android/audio_record_input.h" | 15 #include "media/audio/android/audio_record_input.h" |
| 15 #include "media/audio/android/opensles_input.h" | 16 #include "media/audio/android/opensles_input.h" |
| 16 #include "media/audio/android/opensles_output.h" | 17 #include "media/audio/android/opensles_output.h" |
| 17 #include "media/audio/audio_manager.h" | 18 #include "media/audio/audio_manager.h" |
| 18 #include "media/audio/audio_parameters.h" | 19 #include "media/audio/audio_parameters.h" |
| 19 #include "media/audio/fake_audio_input_stream.h" | 20 #include "media/audio/fake_audio_input_stream.h" |
| 20 #include "media/base/channel_layout.h" | 21 #include "media/base/channel_layout.h" |
| 21 | 22 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 40 static const int kDefaultInputBufferSize = 1024; | 41 static const int kDefaultInputBufferSize = 1024; |
| 41 static const int kDefaultOutputBufferSize = 2048; | 42 static const int kDefaultOutputBufferSize = 2048; |
| 42 | 43 |
| 43 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { | 44 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { |
| 44 return new AudioManagerAndroid(audio_log_factory); | 45 return new AudioManagerAndroid(audio_log_factory); |
| 45 } | 46 } |
| 46 | 47 |
| 47 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory) | 48 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory) |
| 48 : AudioManagerBase(audio_log_factory) { | 49 : AudioManagerBase(audio_log_factory) { |
| 49 SetMaxOutputStreamsAllowed(kMaxOutputStreams); | 50 SetMaxOutputStreamsAllowed(kMaxOutputStreams); |
| 50 | |
| 51 j_audio_manager_.Reset( | |
|
tommi (sloooow) - chröme
2014/02/04 14:30:12
yay!
henrika (OOO until Aug 14)
2014/02/05 09:45:57
thx
| |
| 52 Java_AudioManagerAndroid_createAudioManagerAndroid( | |
| 53 base::android::AttachCurrentThread(), | |
| 54 base::android::GetApplicationContext(), | |
| 55 reinterpret_cast<intptr_t>(this))); | |
| 56 Init(); | |
| 57 } | 51 } |
| 58 | 52 |
| 59 AudioManagerAndroid::~AudioManagerAndroid() { | 53 AudioManagerAndroid::~AudioManagerAndroid() { |
| 60 Close(); | |
| 61 Shutdown(); | 54 Shutdown(); |
| 55 // Verify that WillDestroyCurrentMessageLoop() has been called. | |
| 56 DCHECK(j_audio_manager_.is_null()); | |
| 62 } | 57 } |
| 63 | 58 |
| 64 bool AudioManagerAndroid::HasAudioOutputDevices() { | 59 bool AudioManagerAndroid::HasAudioOutputDevices() { |
| 65 return true; | 60 return true; |
| 66 } | 61 } |
| 67 | 62 |
| 68 bool AudioManagerAndroid::HasAudioInputDevices() { | 63 bool AudioManagerAndroid::HasAudioInputDevices() { |
| 69 return true; | 64 return true; |
| 70 } | 65 } |
| 71 | 66 |
| 72 void AudioManagerAndroid::GetAudioInputDeviceNames( | 67 void AudioManagerAndroid::GetAudioInputDeviceNames( |
| 73 AudioDeviceNames* device_names) { | 68 AudioDeviceNames* device_names) { |
| 74 // Always add default device parameters as first element. | 69 CreateAndInitOnAudioThread(); |
| 75 DCHECK(device_names->empty()); | |
| 76 AddDefaultDevice(device_names); | |
| 77 | 70 |
| 78 JNIEnv* env = AttachCurrentThread(); | 71 // Get list of available audio devices and use the audio thread to reduce |
| 79 ScopedJavaLocalRef<jobjectArray> j_device_array = | 72 // the number of calling threads to the Java layer. Also, ensure that the |
| 80 Java_AudioManagerAndroid_getAudioInputDeviceNames( | 73 // calling thread sees this function call as synchronous. |
| 81 env, j_audio_manager_.obj()); | 74 scoped_refptr<base::SingleThreadTaskRunner> task_runner(GetTaskRunner()); |
| 82 jsize len = env->GetArrayLength(j_device_array.obj()); | 75 if (task_runner->BelongsToCurrentThread()) { |
| 83 AudioDeviceName device; | 76 GetAudioInputDeviceNamesOnAudioThread(NULL, device_names); |
| 84 for (jsize i = 0; i < len; ++i) { | 77 } else { |
| 85 ScopedJavaLocalRef<jobject> j_device( | 78 base::WaitableEvent event(false, false); |
| 86 env, env->GetObjectArrayElement(j_device_array.obj(), i)); | 79 task_runner->PostTask( |
| 87 ScopedJavaLocalRef<jstring> j_device_name = | 80 FROM_HERE, |
| 88 Java_AudioDeviceName_name(env, j_device.obj()); | 81 base::Bind( |
| 89 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); | 82 &AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread, |
| 90 ScopedJavaLocalRef<jstring> j_device_id = | 83 base::Unretained(this), |
| 91 Java_AudioDeviceName_id(env, j_device.obj()); | 84 &event, |
| 92 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); | 85 device_names)); |
| 93 device_names->push_back(device); | 86 event.Wait(); |
| 94 } | 87 } |
| 95 } | 88 } |
| 96 | 89 |
| 97 void AudioManagerAndroid::GetAudioOutputDeviceNames( | 90 void AudioManagerAndroid::GetAudioOutputDeviceNames( |
| 98 AudioDeviceNames* device_names) { | 91 AudioDeviceNames* device_names) { |
| 99 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). | 92 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). |
| 100 AddDefaultDevice(device_names); | 93 AddDefaultDevice(device_names); |
| 101 } | 94 } |
| 102 | 95 |
| 103 AudioParameters AudioManagerAndroid::GetInputStreamParameters( | 96 AudioParameters AudioManagerAndroid::GetInputStreamParameters( |
| 104 const std::string& device_id) { | 97 const std::string& device_id) { |
| 105 JNIEnv* env = AttachCurrentThread(); | 98 CreateAndInitOnAudioThread(); |
| 99 | |
| 106 // Use mono as preferred number of input channels on Android to save | 100 // Use mono as preferred number of input channels on Android to save |
| 107 // resources. Using mono also avoids a driver issue seen on Samsung | 101 // resources. Using mono also avoids a driver issue seen on Samsung |
| 108 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details. | 102 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details. |
| 103 // TODO(henrika): do we nee a requirement to call the rest of this method | |
|
tommi (sloooow) - chröme
2014/02/04 14:30:12
typo
I assume this with regards to Dale's questio
henrika (OOO until Aug 14)
2014/02/05 09:45:57
Done.
| |
| 104 // on the audio thread? | |
| 105 JNIEnv* env = AttachCurrentThread(); | |
| 106 CHECK(env); | |
| 109 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; | 107 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; |
| 110 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize( | 108 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize( |
| 111 env, GetNativeOutputSampleRate(), | 109 env, GetNativeOutputSampleRate(), |
| 112 ChannelLayoutToChannelCount(channel_layout)); | 110 ChannelLayoutToChannelCount(channel_layout)); |
| 113 int effects = AudioParameters::NO_EFFECTS; | 111 int effects = AudioParameters::NO_EFFECTS; |
| 114 effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ? | 112 effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ? |
| 115 AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS; | 113 AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS; |
| 116 AudioParameters params( | 114 AudioParameters params( |
| 117 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, | 115 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, |
| 118 GetNativeOutputSampleRate(), 16, | 116 GetNativeOutputSampleRate(), 16, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 139 { | 137 { |
| 140 base::AutoLock lock(streams_lock_); | 138 base::AutoLock lock(streams_lock_); |
| 141 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); | 139 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); |
| 142 } | 140 } |
| 143 | 141 |
| 144 return stream; | 142 return stream; |
| 145 } | 143 } |
| 146 | 144 |
| 147 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( | 145 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( |
| 148 const AudioParameters& params, const std::string& device_id) { | 146 const AudioParameters& params, const std::string& device_id) { |
| 147 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 148 CreateAndInitOnAudioThread(); | |
| 149 bool had_no_streams = HadNoAudioStreams(); | 149 bool had_no_streams = HadNoAudioStreams(); |
| 150 AudioInputStream* stream = | 150 AudioInputStream* stream = |
| 151 AudioManagerBase::MakeAudioInputStream(params, device_id); | 151 AudioManagerBase::MakeAudioInputStream(params, device_id); |
| 152 | 152 |
| 153 // The audio manager for Android creates streams intended for real-time | 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. | 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 | 155 // If a Bluetooth headset is used, the audio stream will use the SCO |
| 156 // channel and therefore have a limited bandwidth (8kHz). | 156 // channel and therefore have a limited bandwidth (8kHz). |
| 157 if (stream && had_no_streams) | 157 if (stream && had_no_streams) |
| 158 SetCommunicationAudioModeOn(true); | 158 SetCommunicationAudioModeOn(true); |
| 159 return stream; | 159 return stream; |
| 160 } | 160 } |
| 161 | 161 |
| 162 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { | 162 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { |
| 163 AudioManagerBase::ReleaseOutputStream(stream); | 163 AudioManagerBase::ReleaseOutputStream(stream); |
| 164 | 164 |
| 165 // Restore the audio mode which was used before the first communication- | 165 // Restore the audio mode which was used before the first communication- |
| 166 // mode stream was created. | 166 // mode stream was created. |
| 167 if (HadNoAudioStreams()) | 167 if (HadNoAudioStreams()) |
| 168 SetCommunicationAudioModeOn(false); | 168 SetCommunicationAudioModeOn(false); |
| 169 base::AutoLock lock(streams_lock_); | 169 base::AutoLock lock(streams_lock_); |
| 170 streams_.erase(static_cast<OpenSLESOutputStream*>(stream)); | 170 streams_.erase(static_cast<OpenSLESOutputStream*>(stream)); |
| 171 } | 171 } |
| 172 | 172 |
| 173 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) { | 173 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) { |
| 174 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 175 DCHECK(!j_audio_manager_.is_null()); | |
| 174 AudioManagerBase::ReleaseInputStream(stream); | 176 AudioManagerBase::ReleaseInputStream(stream); |
| 175 | 177 |
| 176 // Restore the audio mode which was used before the first communication- | 178 // Restore the audio mode which was used before the first communication- |
| 177 // mode stream was created. | 179 // mode stream was created. |
| 178 if (HadNoAudioStreams()) | 180 if (HadNoAudioStreams()) |
| 179 SetCommunicationAudioModeOn(false); | 181 SetCommunicationAudioModeOn(false); |
| 180 } | 182 } |
| 181 | 183 |
| 182 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( | 184 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( |
| 183 const AudioParameters& params) { | 185 const AudioParameters& params) { |
| 184 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 186 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
| 185 return new OpenSLESOutputStream(this, params); | 187 return new OpenSLESOutputStream(this, params); |
| 186 } | 188 } |
| 187 | 189 |
| 188 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( | 190 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( |
| 189 const AudioParameters& params, | 191 const AudioParameters& params, |
| 190 const std::string& device_id, | 192 const std::string& device_id, |
| 191 const std::string& input_device_id) { | 193 const std::string& input_device_id) { |
| 192 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; | 194 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; |
| 193 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 195 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| 194 return new OpenSLESOutputStream(this, params); | 196 return new OpenSLESOutputStream(this, params); |
| 195 } | 197 } |
| 196 | 198 |
| 197 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( | 199 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( |
| 198 const AudioParameters& params, const std::string& device_id) { | 200 const AudioParameters& params, const std::string& device_id) { |
| 199 // TODO(henrika): add support for device selection if/when any client | 201 // TODO(henrika): add support for device selection if/when any client |
| 200 // needs it. | 202 // needs it. |
| 201 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; | 203 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; |
| 202 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 204 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
| 205 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 206 CreateAndInitOnAudioThread(); | |
| 203 return new OpenSLESInputStream(this, params); | 207 return new OpenSLESInputStream(this, params); |
| 204 } | 208 } |
| 205 | 209 |
| 206 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( | 210 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( |
| 207 const AudioParameters& params, const std::string& device_id) { | 211 const AudioParameters& params, const std::string& device_id) { |
| 208 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 212 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| 209 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; | 213 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; |
| 214 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 215 CreateAndInitOnAudioThread(); | |
| 216 | |
| 210 // Use the device ID to select the correct input device. | 217 // Use the device ID to select the correct input device. |
| 211 // Note that the input device is always associated with a certain output | 218 // Note that the input device is always associated with a certain output |
| 212 // device, i.e., this selection does also switch the output device. | 219 // device, i.e., this selection does also switch the output device. |
| 213 // All input and output streams will be affected by the device selection. | 220 // All input and output streams will be affected by the device selection. |
| 214 if (!SetAudioDevice(device_id)) { | 221 if (!SetAudioDevice(device_id)) { |
| 215 LOG(ERROR) << "Unable to select audio device!"; | 222 LOG(ERROR) << "Unable to select audio device!"; |
| 216 return NULL; | 223 return NULL; |
| 217 } | 224 } |
| 218 | 225 |
| 219 if (params.effects() != AudioParameters::NO_EFFECTS) { | 226 if (params.effects() != AudioParameters::NO_EFFECTS) { |
| 220 // Platform effects can only be enabled through the AudioRecord path. | 227 // Platform effects can only be enabled through the AudioRecord path. |
| 221 // An effect should only have been requested here if recommended by | 228 // An effect should only have been requested here if recommended by |
| 222 // AudioManagerAndroid.shouldUse<Effect>. | 229 // AudioManagerAndroid.shouldUse<Effect>. |
| 223 // | 230 // |
| 224 // Creating this class requires Jelly Bean, which is already guaranteed by | 231 // Creating this class requires Jelly Bean, which is already guaranteed by |
| 225 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use | 232 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use |
| 226 // the effect settings as a way to select the input path. | 233 // the effect settings as a way to select the input path. |
| 227 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); | 234 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); |
| 228 DVLOG(1) << "Creating AudioRecordInputStream"; | 235 DVLOG(1) << "Creating AudioRecordInputStream"; |
| 229 return new AudioRecordInputStream(this, params); | 236 return new AudioRecordInputStream(this, params); |
| 230 } | 237 } |
| 231 DVLOG(1) << "Creating OpenSLESInputStream"; | 238 DVLOG(1) << "Creating OpenSLESInputStream"; |
| 232 return new OpenSLESInputStream(this, params); | 239 return new OpenSLESInputStream(this, params); |
| 233 } | 240 } |
| 234 | 241 |
| 242 void AudioManagerAndroid::WillDestroyCurrentMessageLoop() { | |
| 243 CloseOnAudioThread(); | |
| 244 } | |
| 245 | |
| 235 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, | 246 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, |
| 236 int channels) { | 247 int channels) { |
| 237 if (IsAudioLowLatencySupported()) { | 248 if (IsAudioLowLatencySupported()) { |
| 238 return GetAudioLowLatencyOutputFrameSize(); | 249 return GetAudioLowLatencyOutputFrameSize(); |
| 239 } else { | 250 } else { |
| 240 return std::max(kDefaultOutputBufferSize, | 251 return std::max(kDefaultOutputBufferSize, |
| 241 Java_AudioManagerAndroid_getMinOutputFrameSize( | 252 Java_AudioManagerAndroid_getMinOutputFrameSize( |
| 242 base::android::AttachCurrentThread(), | 253 base::android::AttachCurrentThread(), |
| 243 sample_rate, channels)); | 254 sample_rate, channels)); |
| 244 } | 255 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 266 | 277 |
| 267 int user_buffer_size = GetUserBufferSize(); | 278 int user_buffer_size = GetUserBufferSize(); |
| 268 if (user_buffer_size) | 279 if (user_buffer_size) |
| 269 buffer_size = user_buffer_size; | 280 buffer_size = user_buffer_size; |
| 270 | 281 |
| 271 return AudioParameters( | 282 return AudioParameters( |
| 272 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, | 283 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, |
| 273 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); | 284 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); |
| 274 } | 285 } |
| 275 | 286 |
| 276 bool AudioManagerAndroid::HadNoAudioStreams() { | 287 bool AudioManagerAndroid::HadNoAudioStreams() { |
|
tommi (sloooow) - chröme
2014/02/04 14:30:12
This should be called HasNoAudioStreams. "Had" is
henrika (OOO until Aug 14)
2014/02/05 09:45:57
Will fix, nop. Just FYI, it was changed based on c
| |
| 277 return output_stream_count() == 0 && input_stream_count() == 0; | 288 return output_stream_count() == 0 && input_stream_count() == 0; |
| 278 } | 289 } |
| 279 | 290 |
| 280 // static | 291 // static |
| 281 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { | 292 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { |
| 282 return RegisterNativesImpl(env); | 293 return RegisterNativesImpl(env); |
| 283 } | 294 } |
| 284 | 295 |
| 296 void AudioManagerAndroid::CreateAndInitOnAudioThread() { | |
| 297 scoped_refptr<base::SingleThreadTaskRunner> task_runner(GetTaskRunner()); | |
| 298 if (task_runner->BelongsToCurrentThread()) { | |
| 299 DoCreateAndInitOnAudioThread(NULL); | |
| 300 } else { | |
| 301 base::WaitableEvent event(false, false); | |
| 302 task_runner->PostTask( | |
| 303 FROM_HERE, | |
| 304 base::Bind( | |
| 305 &AudioManagerAndroid::DoCreateAndInitOnAudioThread, | |
| 306 base::Unretained(this), | |
| 307 &event)); | |
| 308 event.Wait(); | |
| 309 } | |
| 310 } | |
| 311 | |
| 312 void AudioManagerAndroid::DoCreateAndInitOnAudioThread( | |
| 313 base::WaitableEvent* event) { | |
| 314 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 315 if (!j_audio_manager_.is_null()) | |
| 316 return; | |
| 317 | |
| 318 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 319 CHECK(env); | |
| 320 | |
| 321 // Create the Android audio manager on the audio thread. | |
| 322 j_audio_manager_.Reset( | |
| 323 Java_AudioManagerAndroid_createAudioManagerAndroid( | |
| 324 env, | |
| 325 base::android::GetApplicationContext(), | |
| 326 reinterpret_cast<intptr_t>(this))); | |
| 327 | |
| 328 // Prepare the list of audio devices and register receivers for device | |
| 329 // notifications. | |
| 330 Init(); | |
| 331 | |
| 332 // Ensure that we are notified when the audio thread dies. | |
| 333 base::MessageLoop::current()->AddDestructionObserver(this); | |
| 334 | |
| 335 if (event) | |
| 336 event->Signal(); | |
| 337 } | |
| 338 | |
| 285 void AudioManagerAndroid::Init() { | 339 void AudioManagerAndroid::Init() { |
| 286 Java_AudioManagerAndroid_init( | 340 Java_AudioManagerAndroid_init( |
| 287 base::android::AttachCurrentThread(), | 341 base::android::AttachCurrentThread(), |
| 288 j_audio_manager_.obj()); | 342 j_audio_manager_.obj()); |
| 289 } | 343 } |
| 290 | 344 |
| 291 void AudioManagerAndroid::Close() { | 345 void AudioManagerAndroid::Close() { |
| 292 Java_AudioManagerAndroid_close( | 346 Java_AudioManagerAndroid_close( |
| 293 base::android::AttachCurrentThread(), | 347 base::android::AttachCurrentThread(), |
| 294 j_audio_manager_.obj()); | 348 j_audio_manager_.obj()); |
| 295 } | 349 } |
| 296 | 350 |
| 297 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { | 351 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { |
| 298 GetTaskRunner()->PostTask( | 352 GetTaskRunner()->PostTask( |
| 299 FROM_HERE, | 353 FROM_HERE, |
| 300 base::Bind( | 354 base::Bind( |
| 301 &AudioManagerAndroid::DoSetMuteOnAudioThread, | 355 &AudioManagerAndroid::DoSetMuteOnAudioThread, |
| 302 base::Unretained(this), | 356 base::Unretained(this), |
| 303 muted)); | 357 muted)); |
| 304 } | 358 } |
| 305 | 359 |
| 306 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { | 360 void AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread( |
| 307 base::AutoLock lock(streams_lock_); | 361 base::WaitableEvent* event, AudioDeviceNames* device_names) { |
| 308 for (OutputStreams::iterator it = streams_.begin(); | 362 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 309 it != streams_.end(); ++it) { | 363 |
| 310 (*it)->SetMute(muted); | 364 // Always add default device parameters as first element. |
| 365 DCHECK(device_names->empty()); | |
| 366 AddDefaultDevice(device_names); | |
| 367 | |
| 368 JNIEnv* env = AttachCurrentThread(); | |
| 369 ScopedJavaLocalRef<jobjectArray> j_device_array = | |
| 370 Java_AudioManagerAndroid_getAudioInputDeviceNames( | |
| 371 env, j_audio_manager_.obj()); | |
| 372 jsize len = env->GetArrayLength(j_device_array.obj()); | |
| 373 AudioDeviceName device; | |
| 374 for (jsize i = 0; i < len; ++i) { | |
| 375 ScopedJavaLocalRef<jobject> j_device( | |
| 376 env, env->GetObjectArrayElement(j_device_array.obj(), i)); | |
| 377 ScopedJavaLocalRef<jstring> j_device_name = | |
| 378 Java_AudioDeviceName_name(env, j_device.obj()); | |
| 379 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); | |
| 380 ScopedJavaLocalRef<jstring> j_device_id = | |
| 381 Java_AudioDeviceName_id(env, j_device.obj()); | |
| 382 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); | |
| 383 device_names->push_back(device); | |
| 311 } | 384 } |
| 385 | |
| 386 if (event) | |
| 387 event->Signal(); | |
| 312 } | 388 } |
| 313 | 389 |
| 314 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { | 390 void AudioManagerAndroid::CloseOnAudioThread() { |
| 315 Java_AudioManagerAndroid_setCommunicationAudioModeOn( | 391 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 316 base::android::AttachCurrentThread(), | 392 if (j_audio_manager_.is_null()) |
| 317 j_audio_manager_.obj(), on); | 393 return; |
| 394 Close(); | |
| 395 j_audio_manager_.Reset(); | |
| 318 } | 396 } |
| 319 | 397 |
| 320 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { | 398 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { |
| 321 JNIEnv* env = AttachCurrentThread(); | 399 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 322 | 400 |
| 323 // Send the unique device ID to the Java audio manager and make the | 401 // Send the unique device ID to the Java audio manager and make the |
| 324 // device switch. Provide an empty string to the Java audio manager | 402 // device switch. Provide an empty string to the Java audio manager |
| 325 // if the default device is selected. | 403 // if the default device is selected. |
| 404 JNIEnv* env = AttachCurrentThread(); | |
| 405 CHECK(env); | |
| 326 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( | 406 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( |
| 327 env, | 407 env, |
| 328 device_id == AudioManagerBase::kDefaultDeviceId ? | 408 device_id == AudioManagerBase::kDefaultDeviceId ? |
| 329 std::string() : device_id); | 409 std::string() : device_id); |
| 330 return Java_AudioManagerAndroid_setDevice( | 410 return Java_AudioManagerAndroid_setDevice( |
| 331 env, j_audio_manager_.obj(), j_device_id.obj()); | 411 env, j_audio_manager_.obj(), j_device_id.obj()); |
| 332 } | 412 } |
| 333 | 413 |
| 414 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { | |
| 415 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 416 base::AutoLock lock(streams_lock_); | |
| 417 for (OutputStreams::iterator it = streams_.begin(); | |
| 418 it != streams_.end(); ++it) { | |
| 419 (*it)->SetMute(muted); | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { | |
| 424 Java_AudioManagerAndroid_setCommunicationAudioModeOn( | |
| 425 base::android::AttachCurrentThread(), | |
| 426 j_audio_manager_.obj(), on); | |
| 427 } | |
| 428 | |
| 334 int AudioManagerAndroid::GetNativeOutputSampleRate() { | 429 int AudioManagerAndroid::GetNativeOutputSampleRate() { |
| 335 return Java_AudioManagerAndroid_getNativeOutputSampleRate( | 430 return Java_AudioManagerAndroid_getNativeOutputSampleRate( |
| 336 base::android::AttachCurrentThread(), | 431 base::android::AttachCurrentThread(), |
| 337 j_audio_manager_.obj()); | 432 j_audio_manager_.obj()); |
| 338 } | 433 } |
| 339 | 434 |
| 340 bool AudioManagerAndroid::IsAudioLowLatencySupported() { | 435 bool AudioManagerAndroid::IsAudioLowLatencySupported() { |
| 341 return Java_AudioManagerAndroid_isAudioLowLatencySupported( | 436 return Java_AudioManagerAndroid_isAudioLowLatencySupported( |
| 342 base::android::AttachCurrentThread(), | 437 base::android::AttachCurrentThread(), |
| 343 j_audio_manager_.obj()); | 438 j_audio_manager_.obj()); |
| 344 } | 439 } |
| 345 | 440 |
| 346 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { | 441 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { |
| 347 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( | 442 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( |
| 348 base::android::AttachCurrentThread(), | 443 base::android::AttachCurrentThread(), |
| 349 j_audio_manager_.obj()); | 444 j_audio_manager_.obj()); |
| 350 } | 445 } |
| 351 | 446 |
| 352 } // namespace media | 447 } // namespace media |
| OLD | NEW |