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