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