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