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( | |
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. |
bulach
2014/02/05 19:29:39
what is the calling thread? we obviously try to av
henrika (OOO until Aug 14)
2014/02/05 21:47:30
Right now the calling threads are a device manager
DaleCurtis
2014/02/05 21:50:13
I suspect you can completely remove the IO thread
bulach
2014/02/06 02:06:56
yeah, let's separate the issues here.. :)
1) I'm h
henrika (OOO until Aug 14)
2014/02/06 08:58:57
Calls to GetAudioInputDeviceNames (7 occurrences)
tommi (sloooow) - chröme
2014/02/06 13:52:58
I looked into this and from what I can tell there
henrika (OOO until Aug 14)
2014/02/13 15:00:09
Now only called on audio thread. Modified.
| |
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 // TODO(henrika): improve documentation regarding the threading model. |
99 // We are on the audio thread here once the MediaStreamDeviceThread is | |
100 // removed and replaced by the audio thread but we also call this one from | |
101 // RenderMessageFilter::OnGetAudioHardwareConfig() on the IO thread. | |
102 CreateAndInitOnAudioThread(); | |
103 | |
106 // Use mono as preferred number of input channels on Android to save | 104 // Use mono as preferred number of input channels on Android to save |
107 // resources. Using mono also avoids a driver issue seen on Samsung | 105 // resources. Using mono also avoids a driver issue seen on Samsung |
108 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details. | 106 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details. |
107 JNIEnv* env = AttachCurrentThread(); | |
108 CHECK(env); | |
109 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; | 109 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; |
110 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize( | 110 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize( |
111 env, GetNativeOutputSampleRate(), | 111 env, GetNativeOutputSampleRate(), |
112 ChannelLayoutToChannelCount(channel_layout)); | 112 ChannelLayoutToChannelCount(channel_layout)); |
113 int effects = AudioParameters::NO_EFFECTS; | 113 int effects = AudioParameters::NO_EFFECTS; |
114 effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ? | 114 effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ? |
115 AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS; | 115 AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS; |
116 AudioParameters params( | 116 AudioParameters params( |
117 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, | 117 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, |
118 GetNativeOutputSampleRate(), 16, | 118 GetNativeOutputSampleRate(), 16, |
119 buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects); | 119 buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects); |
120 return params; | 120 return params; |
121 } | 121 } |
122 | 122 |
123 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( | 123 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( |
124 const AudioParameters& params, | 124 const AudioParameters& params, |
125 const std::string& device_id, | 125 const std::string& device_id, |
126 const std::string& input_device_id) { | 126 const std::string& input_device_id) { |
127 bool had_no_streams = HadNoAudioStreams(); | 127 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
128 CreateAndInitOnAudioThread(); | |
129 bool has_no_streams = HasNoAudioStreams(); | |
128 AudioOutputStream* stream = | 130 AudioOutputStream* stream = |
129 AudioManagerBase::MakeAudioOutputStream(params, std::string(), | 131 AudioManagerBase::MakeAudioOutputStream(params, std::string(), |
130 std::string()); | 132 std::string()); |
131 | 133 |
132 // The audio manager for Android creates streams intended for real-time | 134 // The audio manager for Android creates streams intended for real-time |
133 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION. | 135 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION. |
134 // If a Bluetooth headset is used, the audio stream will use the SCO | 136 // If a Bluetooth headset is used, the audio stream will use the SCO |
135 // channel and therefore have a limited bandwidth (8-16kHz). | 137 // channel and therefore have a limited bandwidth (8-16kHz). |
136 if (stream && had_no_streams) | 138 if (stream && has_no_streams) |
137 SetCommunicationAudioModeOn(true); | 139 SetCommunicationAudioModeOn(true); |
138 | 140 |
139 { | 141 { |
140 base::AutoLock lock(streams_lock_); | 142 base::AutoLock lock(streams_lock_); |
141 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); | 143 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); |
142 } | 144 } |
143 | 145 |
144 return stream; | 146 return stream; |
145 } | 147 } |
146 | 148 |
147 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( | 149 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( |
148 const AudioParameters& params, const std::string& device_id) { | 150 const AudioParameters& params, const std::string& device_id) { |
149 bool had_no_streams = HadNoAudioStreams(); | 151 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
152 CreateAndInitOnAudioThread(); | |
153 bool has_no_streams = HasNoAudioStreams(); | |
150 AudioInputStream* stream = | 154 AudioInputStream* stream = |
151 AudioManagerBase::MakeAudioInputStream(params, device_id); | 155 AudioManagerBase::MakeAudioInputStream(params, device_id); |
152 | 156 |
153 // The audio manager for Android creates streams intended for real-time | 157 // The audio manager for Android creates streams intended for real-time |
154 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION. | 158 // 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 | 159 // If a Bluetooth headset is used, the audio stream will use the SCO |
156 // channel and therefore have a limited bandwidth (8kHz). | 160 // channel and therefore have a limited bandwidth (8kHz). |
157 if (stream && had_no_streams) | 161 if (stream && has_no_streams) |
158 SetCommunicationAudioModeOn(true); | 162 SetCommunicationAudioModeOn(true); |
159 return stream; | 163 return stream; |
160 } | 164 } |
161 | 165 |
162 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { | 166 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) { |
163 AudioManagerBase::ReleaseOutputStream(stream); | 167 AudioManagerBase::ReleaseOutputStream(stream); |
164 | 168 |
165 // Restore the audio mode which was used before the first communication- | 169 // Restore the audio mode which was used before the first communication- |
166 // mode stream was created. | 170 // mode stream was created. |
167 if (HadNoAudioStreams()) | 171 if (HasNoAudioStreams()) |
168 SetCommunicationAudioModeOn(false); | 172 SetCommunicationAudioModeOn(false); |
169 base::AutoLock lock(streams_lock_); | 173 base::AutoLock lock(streams_lock_); |
170 streams_.erase(static_cast<OpenSLESOutputStream*>(stream)); | 174 streams_.erase(static_cast<OpenSLESOutputStream*>(stream)); |
171 } | 175 } |
172 | 176 |
173 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) { | 177 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) { |
178 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
179 DCHECK(!j_audio_manager_.is_null()); | |
174 AudioManagerBase::ReleaseInputStream(stream); | 180 AudioManagerBase::ReleaseInputStream(stream); |
175 | 181 |
176 // Restore the audio mode which was used before the first communication- | 182 // Restore the audio mode which was used before the first communication- |
177 // mode stream was created. | 183 // mode stream was created. |
178 if (HadNoAudioStreams()) | 184 if (HasNoAudioStreams()) |
179 SetCommunicationAudioModeOn(false); | 185 SetCommunicationAudioModeOn(false); |
180 } | 186 } |
181 | 187 |
182 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( | 188 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( |
183 const AudioParameters& params) { | 189 const AudioParameters& params) { |
184 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 190 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
185 return new OpenSLESOutputStream(this, params); | 191 return new OpenSLESOutputStream(this, params); |
186 } | 192 } |
187 | 193 |
188 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( | 194 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( |
189 const AudioParameters& params, | 195 const AudioParameters& params, |
190 const std::string& device_id, | 196 const std::string& device_id, |
191 const std::string& input_device_id) { | 197 const std::string& input_device_id) { |
192 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; | 198 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; |
193 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 199 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
200 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
201 CreateAndInitOnAudioThread(); | |
194 return new OpenSLESOutputStream(this, params); | 202 return new OpenSLESOutputStream(this, params); |
195 } | 203 } |
196 | 204 |
197 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( | 205 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( |
198 const AudioParameters& params, const std::string& device_id) { | 206 const AudioParameters& params, const std::string& device_id) { |
199 // TODO(henrika): add support for device selection if/when any client | 207 // TODO(henrika): add support for device selection if/when any client |
200 // needs it. | 208 // needs it. |
201 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; | 209 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; |
202 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 210 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
211 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
212 CreateAndInitOnAudioThread(); | |
203 return new OpenSLESInputStream(this, params); | 213 return new OpenSLESInputStream(this, params); |
204 } | 214 } |
205 | 215 |
206 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( | 216 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( |
207 const AudioParameters& params, const std::string& device_id) { | 217 const AudioParameters& params, const std::string& device_id) { |
208 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 218 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
209 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; | 219 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; |
220 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
221 CreateAndInitOnAudioThread(); | |
222 | |
210 // Use the device ID to select the correct input device. | 223 // Use the device ID to select the correct input device. |
211 // Note that the input device is always associated with a certain output | 224 // Note that the input device is always associated with a certain output |
212 // device, i.e., this selection does also switch the output device. | 225 // device, i.e., this selection does also switch the output device. |
213 // All input and output streams will be affected by the device selection. | 226 // All input and output streams will be affected by the device selection. |
214 if (!SetAudioDevice(device_id)) { | 227 if (!SetAudioDevice(device_id)) { |
215 LOG(ERROR) << "Unable to select audio device!"; | 228 LOG(ERROR) << "Unable to select audio device!"; |
216 return NULL; | 229 return NULL; |
217 } | 230 } |
218 | 231 |
219 if (params.effects() != AudioParameters::NO_EFFECTS) { | 232 if (params.effects() != AudioParameters::NO_EFFECTS) { |
220 // Platform effects can only be enabled through the AudioRecord path. | 233 // Platform effects can only be enabled through the AudioRecord path. |
221 // An effect should only have been requested here if recommended by | 234 // An effect should only have been requested here if recommended by |
222 // AudioManagerAndroid.shouldUse<Effect>. | 235 // AudioManagerAndroid.shouldUse<Effect>. |
223 // | 236 // |
224 // Creating this class requires Jelly Bean, which is already guaranteed by | 237 // Creating this class requires Jelly Bean, which is already guaranteed by |
225 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use | 238 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use |
226 // the effect settings as a way to select the input path. | 239 // the effect settings as a way to select the input path. |
227 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); | 240 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); |
228 DVLOG(1) << "Creating AudioRecordInputStream"; | 241 DVLOG(1) << "Creating AudioRecordInputStream"; |
229 return new AudioRecordInputStream(this, params); | 242 return new AudioRecordInputStream(this, params); |
230 } | 243 } |
231 DVLOG(1) << "Creating OpenSLESInputStream"; | 244 DVLOG(1) << "Creating OpenSLESInputStream"; |
232 return new OpenSLESInputStream(this, params); | 245 return new OpenSLESInputStream(this, params); |
233 } | 246 } |
234 | 247 |
235 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, | 248 // static |
236 int channels) { | 249 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { |
237 if (IsAudioLowLatencySupported()) { | 250 return RegisterNativesImpl(env); |
238 return GetAudioLowLatencyOutputFrameSize(); | 251 } |
239 } else { | 252 |
240 return std::max(kDefaultOutputBufferSize, | 253 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { |
241 Java_AudioManagerAndroid_getMinOutputFrameSize( | 254 GetTaskRunner()->PostTask( |
242 base::android::AttachCurrentThread(), | 255 FROM_HERE, |
243 sample_rate, channels)); | 256 base::Bind( |
244 } | 257 &AudioManagerAndroid::DoSetMuteOnAudioThread, |
258 base::Unretained(this), | |
259 muted)); | |
245 } | 260 } |
246 | 261 |
247 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters( | 262 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters( |
248 const std::string& output_device_id, | 263 const std::string& output_device_id, |
249 const AudioParameters& input_params) { | 264 const AudioParameters& input_params) { |
265 // TODO(henrika): improve documentation regarding the threading model. | |
266 // We are on the audio thread here once the MediaStreamDeviceThread is | |
267 // removed and replaced by the audio thread but we also call this one from | |
268 // RenderMessageFilter::OnGetAudioHardwareConfig() on the IO thread. | |
269 CreateAndInitOnAudioThread(); | |
270 | |
250 // TODO(tommi): Support |output_device_id|. | 271 // TODO(tommi): Support |output_device_id|. |
251 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; | 272 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; |
252 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; | 273 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
253 int sample_rate = GetNativeOutputSampleRate(); | 274 int sample_rate = GetNativeOutputSampleRate(); |
254 int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2); | 275 int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2); |
255 int bits_per_sample = 16; | 276 int bits_per_sample = 16; |
256 int input_channels = 0; | 277 int input_channels = 0; |
257 if (input_params.IsValid()) { | 278 if (input_params.IsValid()) { |
258 // Use the client's input parameters if they are valid. | 279 // Use the client's input parameters if they are valid. |
259 sample_rate = input_params.sample_rate(); | 280 sample_rate = input_params.sample_rate(); |
260 bits_per_sample = input_params.bits_per_sample(); | 281 bits_per_sample = input_params.bits_per_sample(); |
261 channel_layout = input_params.channel_layout(); | 282 channel_layout = input_params.channel_layout(); |
262 input_channels = input_params.input_channels(); | 283 input_channels = input_params.input_channels(); |
263 buffer_size = GetOptimalOutputFrameSize( | 284 buffer_size = GetOptimalOutputFrameSize( |
264 sample_rate, ChannelLayoutToChannelCount(channel_layout)); | 285 sample_rate, ChannelLayoutToChannelCount(channel_layout)); |
265 } | 286 } |
266 | 287 |
267 int user_buffer_size = GetUserBufferSize(); | 288 int user_buffer_size = GetUserBufferSize(); |
268 if (user_buffer_size) | 289 if (user_buffer_size) |
269 buffer_size = user_buffer_size; | 290 buffer_size = user_buffer_size; |
270 | 291 |
271 return AudioParameters( | 292 return AudioParameters( |
272 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, | 293 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, |
273 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); | 294 sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); |
274 } | 295 } |
275 | 296 |
276 bool AudioManagerAndroid::HadNoAudioStreams() { | 297 void AudioManagerAndroid::WillDestroyCurrentMessageLoop() { |
298 CloseOnAudioThread(); | |
299 } | |
300 | |
301 void AudioManagerAndroid::CreateAndInitOnAudioThread() { | |
302 scoped_refptr<base::SingleThreadTaskRunner> task_runner(GetTaskRunner()); | |
303 if (task_runner->BelongsToCurrentThread()) { | |
304 DoCreateAndInitOnAudioThread(NULL); | |
305 } else { | |
306 base::WaitableEvent event(false, false); | |
bulach
2014/02/05 19:29:39
yeah, as above, this is a really bad pattern, we s
henrika (OOO until Aug 14)
2014/02/05 21:47:30
I think it is a topic which we perhaps could discu
| |
307 task_runner->PostTask( | |
308 FROM_HERE, | |
309 base::Bind( | |
310 &AudioManagerAndroid::DoCreateAndInitOnAudioThread, | |
311 base::Unretained(this), | |
312 &event)); | |
313 event.Wait(); | |
314 } | |
315 } | |
316 | |
317 void AudioManagerAndroid::DoCreateAndInitOnAudioThread( | |
318 base::WaitableEvent* event) { | |
319 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
320 if (!j_audio_manager_.is_null()) { | |
321 if (event) | |
322 event->Signal(); | |
323 return; | |
324 } | |
325 | |
326 JNIEnv* env = base::android::AttachCurrentThread(); | |
327 CHECK(env); | |
328 | |
329 // Create the Android audio manager on the audio thread. | |
330 DVLOG(1) << "Creating Java part of the audio manager"; | |
331 j_audio_manager_.Reset( | |
332 Java_AudioManagerAndroid_createAudioManagerAndroid( | |
333 env, | |
334 base::android::GetApplicationContext(), | |
335 reinterpret_cast<intptr_t>(this))); | |
336 | |
337 // Prepare the list of audio devices and register receivers for device | |
338 // notifications. | |
339 Init(); | |
340 | |
341 // Ensure that we are notified when the audio thread dies. | |
342 base::MessageLoop::current()->AddDestructionObserver(this); | |
343 | |
344 if (event) | |
345 event->Signal(); | |
346 } | |
347 | |
348 void AudioManagerAndroid::CloseOnAudioThread() { | |
349 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
350 if (j_audio_manager_.is_null()) | |
351 return; | |
352 Close(); | |
353 DVLOG(1) << "Destroying Java part of the audio manager"; | |
354 j_audio_manager_.Reset(); | |
355 } | |
356 | |
357 bool AudioManagerAndroid::HasNoAudioStreams() { | |
277 return output_stream_count() == 0 && input_stream_count() == 0; | 358 return output_stream_count() == 0 && input_stream_count() == 0; |
278 } | 359 } |
279 | 360 |
280 // static | |
281 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) { | |
282 return RegisterNativesImpl(env); | |
283 } | |
284 | |
285 void AudioManagerAndroid::Init() { | 361 void AudioManagerAndroid::Init() { |
286 Java_AudioManagerAndroid_init( | 362 Java_AudioManagerAndroid_init( |
287 base::android::AttachCurrentThread(), | 363 base::android::AttachCurrentThread(), |
288 j_audio_manager_.obj()); | 364 j_audio_manager_.obj()); |
289 } | 365 } |
290 | 366 |
291 void AudioManagerAndroid::Close() { | 367 void AudioManagerAndroid::Close() { |
292 Java_AudioManagerAndroid_close( | 368 Java_AudioManagerAndroid_close( |
293 base::android::AttachCurrentThread(), | 369 base::android::AttachCurrentThread(), |
294 j_audio_manager_.obj()); | 370 j_audio_manager_.obj()); |
295 } | 371 } |
296 | 372 |
297 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { | |
298 GetTaskRunner()->PostTask( | |
299 FROM_HERE, | |
300 base::Bind( | |
301 &AudioManagerAndroid::DoSetMuteOnAudioThread, | |
302 base::Unretained(this), | |
303 muted)); | |
304 } | |
305 | |
306 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { | |
307 base::AutoLock lock(streams_lock_); | |
308 for (OutputStreams::iterator it = streams_.begin(); | |
309 it != streams_.end(); ++it) { | |
310 (*it)->SetMute(muted); | |
311 } | |
312 } | |
313 | |
314 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { | 373 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { |
315 Java_AudioManagerAndroid_setCommunicationAudioModeOn( | 374 Java_AudioManagerAndroid_setCommunicationAudioModeOn( |
316 base::android::AttachCurrentThread(), | 375 base::android::AttachCurrentThread(), |
317 j_audio_manager_.obj(), on); | 376 j_audio_manager_.obj(), on); |
318 } | 377 } |
319 | 378 |
320 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { | 379 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { |
321 JNIEnv* env = AttachCurrentThread(); | 380 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
322 | 381 |
323 // Send the unique device ID to the Java audio manager and make the | 382 // 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 | 383 // device switch. Provide an empty string to the Java audio manager |
325 // if the default device is selected. | 384 // if the default device is selected. |
385 JNIEnv* env = AttachCurrentThread(); | |
386 CHECK(env); | |
326 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( | 387 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( |
327 env, | 388 env, |
328 device_id == AudioManagerBase::kDefaultDeviceId ? | 389 device_id == AudioManagerBase::kDefaultDeviceId ? |
329 std::string() : device_id); | 390 std::string() : device_id); |
330 return Java_AudioManagerAndroid_setDevice( | 391 return Java_AudioManagerAndroid_setDevice( |
331 env, j_audio_manager_.obj(), j_device_id.obj()); | 392 env, j_audio_manager_.obj(), j_device_id.obj()); |
332 } | 393 } |
333 | 394 |
334 int AudioManagerAndroid::GetNativeOutputSampleRate() { | 395 int AudioManagerAndroid::GetNativeOutputSampleRate() { |
335 return Java_AudioManagerAndroid_getNativeOutputSampleRate( | 396 return Java_AudioManagerAndroid_getNativeOutputSampleRate( |
336 base::android::AttachCurrentThread(), | 397 base::android::AttachCurrentThread(), |
337 j_audio_manager_.obj()); | 398 j_audio_manager_.obj()); |
338 } | 399 } |
339 | 400 |
340 bool AudioManagerAndroid::IsAudioLowLatencySupported() { | 401 bool AudioManagerAndroid::IsAudioLowLatencySupported() { |
341 return Java_AudioManagerAndroid_isAudioLowLatencySupported( | 402 return Java_AudioManagerAndroid_isAudioLowLatencySupported( |
342 base::android::AttachCurrentThread(), | 403 base::android::AttachCurrentThread(), |
343 j_audio_manager_.obj()); | 404 j_audio_manager_.obj()); |
344 } | 405 } |
345 | 406 |
346 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { | 407 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { |
347 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( | 408 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( |
348 base::android::AttachCurrentThread(), | 409 base::android::AttachCurrentThread(), |
349 j_audio_manager_.obj()); | 410 j_audio_manager_.obj()); |
350 } | 411 } |
351 | 412 |
413 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, | |
414 int channels) { | |
415 if (IsAudioLowLatencySupported()) { | |
416 return GetAudioLowLatencyOutputFrameSize(); | |
417 } else { | |
418 return std::max(kDefaultOutputBufferSize, | |
419 Java_AudioManagerAndroid_getMinOutputFrameSize( | |
420 base::android::AttachCurrentThread(), | |
421 sample_rate, channels)); | |
422 } | |
423 } | |
424 | |
425 void AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread( | |
426 base::WaitableEvent* event, AudioDeviceNames* device_names) { | |
427 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
428 | |
429 // Always add default device parameters as first element. | |
430 DCHECK(device_names->empty()); | |
431 AddDefaultDevice(device_names); | |
432 | |
433 JNIEnv* env = AttachCurrentThread(); | |
434 ScopedJavaLocalRef<jobjectArray> j_device_array = | |
435 Java_AudioManagerAndroid_getAudioInputDeviceNames( | |
436 env, j_audio_manager_.obj()); | |
437 jsize len = env->GetArrayLength(j_device_array.obj()); | |
438 AudioDeviceName device; | |
439 for (jsize i = 0; i < len; ++i) { | |
440 ScopedJavaLocalRef<jobject> j_device( | |
441 env, env->GetObjectArrayElement(j_device_array.obj(), i)); | |
442 ScopedJavaLocalRef<jstring> j_device_name = | |
443 Java_AudioDeviceName_name(env, j_device.obj()); | |
444 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); | |
445 ScopedJavaLocalRef<jstring> j_device_id = | |
446 Java_AudioDeviceName_id(env, j_device.obj()); | |
447 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); | |
448 device_names->push_back(device); | |
449 } | |
450 | |
451 if (event) | |
452 event->Signal(); | |
453 } | |
454 | |
455 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { | |
456 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
457 base::AutoLock lock(streams_lock_); | |
458 for (OutputStreams::iterator it = streams_.begin(); | |
459 it != streams_.end(); ++it) { | |
460 (*it)->SetMute(muted); | |
461 } | |
462 } | |
463 | |
352 } // namespace media | 464 } // namespace media |
OLD | NEW |