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.
5 #include "media/audio/android/audio_manager_android.h"
7 #include "base/logging.h"
8 #include "jni/AudioManagerAndroid_jni.h"
9 #include "media/audio/android/opensles_input.h"
10 #include "media/audio/android/opensles_output.h"
11 #include "media/audio/audio_manager.h"
12 #include "media/audio/audio_parameters.h"
13 #include "media/audio/fake_audio_input_stream.h"
14 #include "media/base/channel_layout.h"
18 static void AddDefaultDevice(AudioDeviceNames* device_names) {
19 DCHECK(device_names->empty());
20 device_names->push_front(
21 AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
22 AudioManagerBase::kDefaultDeviceId));
25 // Maximum number of output streams that can be open simultaneously.
26 static const int kMaxOutputStreams = 10;
28 static const int kAudioModeNormal = 0x00000000;
29 static const int kAudioModeInCommunication = 0x00000003;
31 static const int kDefaultInputBufferSize = 1024;
32 static const int kDefaultOutputBufferSize = 2048;
34 AudioManager* CreateAudioManager() {
35 return new AudioManagerAndroid();
38 AudioManagerAndroid::AudioManagerAndroid() {
39 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
41 j_audio_manager_.Reset(
42 Java_AudioManagerAndroid_createAudioManagerAndroid(
43 base::android::AttachCurrentThread(),
44 base::android::GetApplicationContext(),
45 reinterpret_cast<intptr_t>(this)));
48 AudioManagerAndroid::~AudioManagerAndroid() {
52 bool AudioManagerAndroid::HasAudioOutputDevices() {
56 bool AudioManagerAndroid::HasAudioInputDevices() {
60 void AudioManagerAndroid::GetAudioInputDeviceNames(
61 AudioDeviceNames* device_names) {
62 AddDefaultDevice(device_names);
65 void AudioManagerAndroid::GetAudioOutputDeviceNames(
66 AudioDeviceNames* device_names) {
67 AddDefaultDevice(device_names);
70 AudioParameters AudioManagerAndroid::GetInputStreamParameters(
71 const std::string& device_id) {
72 // Use mono as preferred number of input channels on Android to save
73 // resources. Using mono also avoids a driver issue seen on Samsung
74 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
75 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
76 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
77 base::android::AttachCurrentThread(), GetNativeOutputSampleRate(),
78 ChannelLayoutToChannelCount(channel_layout));
80 return AudioParameters(
81 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
82 GetNativeOutputSampleRate(), 16,
83 buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size);
86 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
87 const AudioParameters& params,
88 const std::string& device_id,
89 const std::string& input_device_id) {
90 AudioOutputStream* stream =
91 AudioManagerBase::MakeAudioOutputStream(params, std::string(),
93 if (stream && output_stream_count() == 1) {
94 SetAudioMode(kAudioModeInCommunication);
95 RegisterHeadsetReceiver();
99 base::AutoLock lock(streams_lock_);
100 streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
105 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
106 const AudioParameters& params, const std::string& device_id) {
107 AudioInputStream* stream =
108 AudioManagerBase::MakeAudioInputStream(params, device_id);
112 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
113 AudioManagerBase::ReleaseOutputStream(stream);
114 if (!output_stream_count()) {
115 UnregisterHeadsetReceiver();
116 SetAudioMode(kAudioModeNormal);
118 base::AutoLock lock(streams_lock_);
119 streams_.erase(static_cast<OpenSLESOutputStream*>(stream));
122 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
123 AudioManagerBase::ReleaseInputStream(stream);
126 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
127 const AudioParameters& params) {
128 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
129 return new OpenSLESOutputStream(this, params);
132 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
133 const AudioParameters& params,
134 const std::string& device_id,
135 const std::string& input_device_id) {
136 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
137 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
138 return new OpenSLESOutputStream(this, params);
141 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
142 const AudioParameters& params, const std::string& device_id) {
143 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
144 return new OpenSLESInputStream(this, params);
147 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
148 const AudioParameters& params, const std::string& device_id) {
149 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
150 return new OpenSLESInputStream(this, params);
153 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
155 if (IsAudioLowLatencySupported()) {
156 return GetAudioLowLatencyOutputFrameSize();
158 return std::max(kDefaultOutputBufferSize,
159 Java_AudioManagerAndroid_getMinOutputFrameSize(
160 base::android::AttachCurrentThread(),
161 sample_rate, channels));
165 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
166 const std::string& output_device_id,
167 const AudioParameters& input_params) {
168 // TODO(tommi): Support |output_device_id|.
169 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
170 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
171 int sample_rate = GetNativeOutputSampleRate();
172 int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
173 int bits_per_sample = 16;
174 int input_channels = 0;
175 if (input_params.IsValid()) {
176 // Use the client's input parameters if they are valid.
177 sample_rate = input_params.sample_rate();
178 bits_per_sample = input_params.bits_per_sample();
179 channel_layout = input_params.channel_layout();
180 input_channels = input_params.input_channels();
181 buffer_size = GetOptimalOutputFrameSize(
182 sample_rate, ChannelLayoutToChannelCount(channel_layout));
185 int user_buffer_size = GetUserBufferSize();
186 if (user_buffer_size)
187 buffer_size = user_buffer_size;
189 return AudioParameters(
190 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
191 sample_rate, bits_per_sample, buffer_size);
195 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
196 return RegisterNativesImpl(env);
199 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
200 GetMessageLoop()->PostTask(
203 &AudioManagerAndroid::DoSetMuteOnAudioThread,
204 base::Unretained(this),
208 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
209 base::AutoLock lock(streams_lock_);
210 for (OutputStreams::iterator it = streams_.begin();
211 it != streams_.end(); ++it) {
212 (*it)->SetMute(muted);
216 void AudioManagerAndroid::SetAudioMode(int mode) {
217 Java_AudioManagerAndroid_setMode(
218 base::android::AttachCurrentThread(),
219 j_audio_manager_.obj(), mode);
222 void AudioManagerAndroid::RegisterHeadsetReceiver() {
223 Java_AudioManagerAndroid_registerHeadsetReceiver(
224 base::android::AttachCurrentThread(),
225 j_audio_manager_.obj());
228 void AudioManagerAndroid::UnregisterHeadsetReceiver() {
229 Java_AudioManagerAndroid_unregisterHeadsetReceiver(
230 base::android::AttachCurrentThread(),
231 j_audio_manager_.obj());
234 int AudioManagerAndroid::GetNativeOutputSampleRate() {
235 return Java_AudioManagerAndroid_getNativeOutputSampleRate(
236 base::android::AttachCurrentThread(),
237 j_audio_manager_.obj());
240 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
241 return Java_AudioManagerAndroid_isAudioLowLatencySupported(
242 base::android::AttachCurrentThread(),
243 j_audio_manager_.obj());
246 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
247 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
248 base::android::AttachCurrentThread(),
249 j_audio_manager_.obj());