audio_manager_android.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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/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"
15
16namespace media {
17
18static void AddDefaultDevice(AudioDeviceNames* device_names) {
19  DCHECK(device_names->empty());
20  device_names->push_front(
21      AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
22                      AudioManagerBase::kDefaultDeviceId));
23}
24
25// Maximum number of output streams that can be open simultaneously.
26static const int kMaxOutputStreams = 10;
27
28static const int kAudioModeNormal = 0x00000000;
29static const int kAudioModeInCommunication = 0x00000003;
30
31static const int kDefaultInputBufferSize = 1024;
32static const int kDefaultOutputBufferSize = 2048;
33
34AudioManager* CreateAudioManager() {
35  return new AudioManagerAndroid();
36}
37
38AudioManagerAndroid::AudioManagerAndroid() {
39  SetMaxOutputStreamsAllowed(kMaxOutputStreams);
40
41  j_audio_manager_.Reset(
42      Java_AudioManagerAndroid_createAudioManagerAndroid(
43          base::android::AttachCurrentThread(),
44          base::android::GetApplicationContext()));
45}
46
47AudioManagerAndroid::~AudioManagerAndroid() {
48  Shutdown();
49}
50
51bool AudioManagerAndroid::HasAudioOutputDevices() {
52  return true;
53}
54
55bool AudioManagerAndroid::HasAudioInputDevices() {
56  return true;
57}
58
59void AudioManagerAndroid::GetAudioInputDeviceNames(
60    AudioDeviceNames* device_names) {
61  AddDefaultDevice(device_names);
62}
63
64void AudioManagerAndroid::GetAudioOutputDeviceNames(
65    AudioDeviceNames* device_names) {
66  AddDefaultDevice(device_names);
67}
68
69AudioParameters AudioManagerAndroid::GetInputStreamParameters(
70    const std::string& device_id) {
71  // Use mono as preferred number of input channels on Android to save
72  // resources. Using mono also avoids a driver issue seen on Samsung
73  // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
74  ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
75  int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
76      base::android::AttachCurrentThread(), GetNativeOutputSampleRate(),
77      ChannelLayoutToChannelCount(channel_layout));
78
79  return AudioParameters(
80      AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
81      GetNativeOutputSampleRate(), 16,
82      buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size);
83}
84
85AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
86    const AudioParameters& params,
87    const std::string& device_id,
88    const std::string& input_device_id) {
89  AudioOutputStream* stream =
90      AudioManagerBase::MakeAudioOutputStream(params, std::string(),
91          std::string());
92  if (stream && output_stream_count() == 1) {
93    SetAudioMode(kAudioModeInCommunication);
94    RegisterHeadsetReceiver();
95  }
96  return stream;
97}
98
99AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
100    const AudioParameters& params, const std::string& device_id) {
101  AudioInputStream* stream =
102      AudioManagerBase::MakeAudioInputStream(params, device_id);
103  return stream;
104}
105
106void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
107  AudioManagerBase::ReleaseOutputStream(stream);
108  if (!output_stream_count()) {
109    UnregisterHeadsetReceiver();
110    SetAudioMode(kAudioModeNormal);
111  }
112}
113
114void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
115  AudioManagerBase::ReleaseInputStream(stream);
116}
117
118AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
119    const AudioParameters& params) {
120  DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
121  return new OpenSLESOutputStream(this, params);
122}
123
124AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
125    const AudioParameters& params,
126    const std::string& device_id,
127    const std::string& input_device_id) {
128  DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
129  DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
130  return new OpenSLESOutputStream(this, params);
131}
132
133AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
134    const AudioParameters& params, const std::string& device_id) {
135  DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
136  return new OpenSLESInputStream(this, params);
137}
138
139AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
140    const AudioParameters& params, const std::string& device_id) {
141  DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
142  return new OpenSLESInputStream(this, params);
143}
144
145int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
146                                                   int channels) {
147  if (IsAudioLowLatencySupported()) {
148    return GetAudioLowLatencyOutputFrameSize();
149  } else {
150    return std::max(kDefaultOutputBufferSize,
151                    Java_AudioManagerAndroid_getMinOutputFrameSize(
152                        base::android::AttachCurrentThread(),
153                        sample_rate, channels));
154  }
155}
156
157AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
158    const std::string& output_device_id,
159    const AudioParameters& input_params) {
160  // TODO(tommi): Support |output_device_id|.
161  DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
162  ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
163  int sample_rate = GetNativeOutputSampleRate();
164  int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
165  int bits_per_sample = 16;
166  int input_channels = 0;
167  if (input_params.IsValid()) {
168    // Use the client's input parameters if they are valid.
169    sample_rate = input_params.sample_rate();
170    bits_per_sample = input_params.bits_per_sample();
171    channel_layout = input_params.channel_layout();
172    input_channels = input_params.input_channels();
173    buffer_size = GetOptimalOutputFrameSize(
174        sample_rate, ChannelLayoutToChannelCount(channel_layout));
175  }
176
177  int user_buffer_size = GetUserBufferSize();
178  if (user_buffer_size)
179    buffer_size = user_buffer_size;
180
181  return AudioParameters(
182      AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
183      sample_rate, bits_per_sample, buffer_size);
184}
185
186// static
187bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
188  return RegisterNativesImpl(env);
189}
190
191void AudioManagerAndroid::SetAudioMode(int mode) {
192  Java_AudioManagerAndroid_setMode(
193      base::android::AttachCurrentThread(),
194      j_audio_manager_.obj(), mode);
195}
196
197void AudioManagerAndroid::RegisterHeadsetReceiver() {
198  Java_AudioManagerAndroid_registerHeadsetReceiver(
199      base::android::AttachCurrentThread(),
200      j_audio_manager_.obj());
201}
202
203void AudioManagerAndroid::UnregisterHeadsetReceiver() {
204  Java_AudioManagerAndroid_unregisterHeadsetReceiver(
205      base::android::AttachCurrentThread(),
206      j_audio_manager_.obj());
207}
208
209int AudioManagerAndroid::GetNativeOutputSampleRate() {
210  return Java_AudioManagerAndroid_getNativeOutputSampleRate(
211      base::android::AttachCurrentThread(),
212      j_audio_manager_.obj());
213}
214
215bool AudioManagerAndroid::IsAudioLowLatencySupported() {
216  return Java_AudioManagerAndroid_isAudioLowLatencySupported(
217      base::android::AttachCurrentThread(),
218      j_audio_manager_.obj());
219}
220
221int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
222  return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
223      base::android::AttachCurrentThread(),
224      j_audio_manager_.obj());
225}
226
227}  // namespace media
228