Home | History | Annotate | Download | only in android
      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/android/build_info.h"
      8 #include "base/android/jni_array.h"
      9 #include "base/android/jni_string.h"
     10 #include "base/android/scoped_java_ref.h"
     11 #include "base/logging.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "jni/AudioManagerAndroid_jni.h"
     14 #include "media/audio/android/audio_record_input.h"
     15 #include "media/audio/android/opensles_input.h"
     16 #include "media/audio/android/opensles_output.h"
     17 #include "media/audio/audio_manager.h"
     18 #include "media/audio/audio_parameters.h"
     19 #include "media/audio/fake_audio_input_stream.h"
     20 #include "media/base/channel_layout.h"
     21 
     22 using base::android::AppendJavaStringArrayToStringVector;
     23 using base::android::AttachCurrentThread;
     24 using base::android::ConvertJavaStringToUTF8;
     25 using base::android::ConvertUTF8ToJavaString;
     26 using base::android::ScopedJavaLocalRef;
     27 
     28 namespace media {
     29 
     30 static void AddDefaultDevice(AudioDeviceNames* device_names) {
     31   DCHECK(device_names->empty());
     32   device_names->push_front(
     33       AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
     34                       AudioManagerBase::kDefaultDeviceId));
     35 }
     36 
     37 // Maximum number of output streams that can be open simultaneously.
     38 static const int kMaxOutputStreams = 10;
     39 
     40 static const int kAudioModeNormal = 0x00000000;
     41 static const int kAudioModeInCommunication = 0x00000003;
     42 
     43 static const int kDefaultInputBufferSize = 1024;
     44 static const int kDefaultOutputBufferSize = 2048;
     45 
     46 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
     47   return new AudioManagerAndroid(audio_log_factory);
     48 }
     49 
     50 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
     51     : AudioManagerBase(audio_log_factory) {
     52   SetMaxOutputStreamsAllowed(kMaxOutputStreams);
     53 
     54   j_audio_manager_.Reset(
     55       Java_AudioManagerAndroid_createAudioManagerAndroid(
     56           base::android::AttachCurrentThread(),
     57           base::android::GetApplicationContext(),
     58           reinterpret_cast<intptr_t>(this)));
     59   Init();
     60 }
     61 
     62 AudioManagerAndroid::~AudioManagerAndroid() {
     63   Close();
     64   Shutdown();
     65 }
     66 
     67 bool AudioManagerAndroid::HasAudioOutputDevices() {
     68   return true;
     69 }
     70 
     71 bool AudioManagerAndroid::HasAudioInputDevices() {
     72   return true;
     73 }
     74 
     75 void AudioManagerAndroid::GetAudioInputDeviceNames(
     76     AudioDeviceNames* device_names) {
     77   // Always add default device parameters as first element.
     78   AddDefaultDevice(device_names);
     79 
     80   JNIEnv* env = AttachCurrentThread();
     81   ScopedJavaLocalRef<jobjectArray> j_device_array =
     82       Java_AudioManagerAndroid_getAudioInputDeviceNames(
     83           env, j_audio_manager_.obj());
     84   jsize len = env->GetArrayLength(j_device_array.obj());
     85   AudioDeviceName device;
     86   for (jsize i = 0; i < len; ++i) {
     87     ScopedJavaLocalRef<jobject> j_device(
     88         env, env->GetObjectArrayElement(j_device_array.obj(), i));
     89     ScopedJavaLocalRef<jstring> j_device_name =
     90         Java_AudioDeviceName_name(env, j_device.obj());
     91     ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
     92     ScopedJavaLocalRef<jstring> j_device_id =
     93         Java_AudioDeviceName_id(env, j_device.obj());
     94     ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
     95     device_names->push_back(device);
     96   }
     97 }
     98 
     99 void AudioManagerAndroid::GetAudioOutputDeviceNames(
    100     AudioDeviceNames* device_names) {
    101   // TODO(henrika): enumerate using GetAudioInputDeviceNames().
    102   AddDefaultDevice(device_names);
    103 }
    104 
    105 AudioParameters AudioManagerAndroid::GetInputStreamParameters(
    106     const std::string& device_id) {
    107   JNIEnv* env = AttachCurrentThread();
    108   // Use mono as preferred number of input channels on Android to save
    109   // resources. Using mono also avoids a driver issue seen on Samsung
    110   // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
    111   ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
    112   int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
    113       env, GetNativeOutputSampleRate(),
    114       ChannelLayoutToChannelCount(channel_layout));
    115   int effects = AudioParameters::NO_EFFECTS;
    116   effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ?
    117       AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS;
    118   AudioParameters params(
    119       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0,
    120       GetNativeOutputSampleRate(), 16,
    121       buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects);
    122   return params;
    123 }
    124 
    125 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
    126     const AudioParameters& params,
    127     const std::string& device_id,
    128     const std::string& input_device_id) {
    129   AudioOutputStream* stream =
    130       AudioManagerBase::MakeAudioOutputStream(params, std::string(),
    131           std::string());
    132   if (stream && output_stream_count() == 1) {
    133     SetAudioMode(kAudioModeInCommunication);
    134   }
    135 
    136   {
    137     base::AutoLock lock(streams_lock_);
    138     streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
    139   }
    140 
    141   return stream;
    142 }
    143 
    144 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
    145     const AudioParameters& params, const std::string& device_id) {
    146   AudioInputStream* stream =
    147       AudioManagerBase::MakeAudioInputStream(params, device_id);
    148   return stream;
    149 }
    150 
    151 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
    152   AudioManagerBase::ReleaseOutputStream(stream);
    153   if (!output_stream_count()) {
    154     SetAudioMode(kAudioModeNormal);
    155   }
    156   base::AutoLock lock(streams_lock_);
    157   streams_.erase(static_cast<OpenSLESOutputStream*>(stream));
    158 }
    159 
    160 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
    161   AudioManagerBase::ReleaseInputStream(stream);
    162 }
    163 
    164 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
    165     const AudioParameters& params) {
    166   DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
    167   return new OpenSLESOutputStream(this, params);
    168 }
    169 
    170 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
    171     const AudioParameters& params,
    172     const std::string& device_id,
    173     const std::string& input_device_id) {
    174   DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
    175   DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
    176   return new OpenSLESOutputStream(this, params);
    177 }
    178 
    179 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
    180     const AudioParameters& params, const std::string& device_id) {
    181   // TODO(henrika): add support for device selection if/when any client
    182   // needs it.
    183   DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
    184   DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
    185   return new OpenSLESInputStream(this, params);
    186 }
    187 
    188 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
    189     const AudioParameters& params, const std::string& device_id) {
    190   DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
    191   DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
    192   // Utilize the device ID to select the correct input device.
    193   // Note that the input device is always associated with a certain output
    194   // device, i.e., this selection does also switch the output device.
    195   // All input and output streams will be affected by the device selection.
    196   SetAudioDevice(device_id);
    197 
    198   if (params.effects() != AudioParameters::NO_EFFECTS) {
    199     // Platform effects can only be enabled through the AudioRecord path.
    200     // An effect should only have been requested here if recommended by
    201     // AudioManagerAndroid.shouldUse<Effect>.
    202     //
    203     // Creating this class requires Jelly Bean, which is already guaranteed by
    204     // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use
    205     // the effect settings as a way to select the input path.
    206     DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16);
    207     DVLOG(1) << "Creating AudioRecordInputStream";
    208     return new AudioRecordInputStream(this, params);
    209   }
    210   DVLOG(1) << "Creating OpenSLESInputStream";
    211   return new OpenSLESInputStream(this, params);
    212 }
    213 
    214 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
    215                                                    int channels) {
    216   if (IsAudioLowLatencySupported()) {
    217     return GetAudioLowLatencyOutputFrameSize();
    218   } else {
    219     return std::max(kDefaultOutputBufferSize,
    220                     Java_AudioManagerAndroid_getMinOutputFrameSize(
    221                         base::android::AttachCurrentThread(),
    222                         sample_rate, channels));
    223   }
    224 }
    225 
    226 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
    227     const std::string& output_device_id,
    228     const AudioParameters& input_params) {
    229   // TODO(tommi): Support |output_device_id|.
    230   DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
    231   ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
    232   int sample_rate = GetNativeOutputSampleRate();
    233   int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
    234   int bits_per_sample = 16;
    235   int input_channels = 0;
    236   if (input_params.IsValid()) {
    237     // Use the client's input parameters if they are valid.
    238     sample_rate = input_params.sample_rate();
    239     bits_per_sample = input_params.bits_per_sample();
    240     channel_layout = input_params.channel_layout();
    241     input_channels = input_params.input_channels();
    242     buffer_size = GetOptimalOutputFrameSize(
    243         sample_rate, ChannelLayoutToChannelCount(channel_layout));
    244   }
    245 
    246   int user_buffer_size = GetUserBufferSize();
    247   if (user_buffer_size)
    248     buffer_size = user_buffer_size;
    249 
    250   return AudioParameters(
    251       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
    252       sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS);
    253 }
    254 
    255 // static
    256 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
    257   return RegisterNativesImpl(env);
    258 }
    259 
    260 void AudioManagerAndroid::Init() {
    261   Java_AudioManagerAndroid_init(
    262       base::android::AttachCurrentThread(),
    263       j_audio_manager_.obj());
    264 }
    265 
    266 void AudioManagerAndroid::Close() {
    267   Java_AudioManagerAndroid_close(
    268       base::android::AttachCurrentThread(),
    269       j_audio_manager_.obj());
    270 }
    271 
    272 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
    273   GetMessageLoop()->PostTask(
    274       FROM_HERE,
    275       base::Bind(
    276           &AudioManagerAndroid::DoSetMuteOnAudioThread,
    277           base::Unretained(this),
    278           muted));
    279 }
    280 
    281 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
    282   base::AutoLock lock(streams_lock_);
    283   for (OutputStreams::iterator it = streams_.begin();
    284        it != streams_.end(); ++it) {
    285     (*it)->SetMute(muted);
    286   }
    287 }
    288 
    289 void AudioManagerAndroid::SetAudioMode(int mode) {
    290   Java_AudioManagerAndroid_setMode(
    291       base::android::AttachCurrentThread(),
    292       j_audio_manager_.obj(), mode);
    293 }
    294 
    295 void AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
    296   JNIEnv* env = AttachCurrentThread();
    297 
    298   // Send the unique device ID to the Java audio manager and make the
    299   // device switch. Provide an empty string to the Java audio manager
    300   // if the default device is selected.
    301   ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
    302       env,
    303       device_id == AudioManagerBase::kDefaultDeviceId ?
    304           std::string() : device_id);
    305   Java_AudioManagerAndroid_setDevice(
    306       env, j_audio_manager_.obj(), j_device_id.obj());
    307 }
    308 
    309 int AudioManagerAndroid::GetNativeOutputSampleRate() {
    310   return Java_AudioManagerAndroid_getNativeOutputSampleRate(
    311       base::android::AttachCurrentThread(),
    312       j_audio_manager_.obj());
    313 }
    314 
    315 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
    316   return Java_AudioManagerAndroid_isAudioLowLatencySupported(
    317       base::android::AttachCurrentThread(),
    318       j_audio_manager_.obj());
    319 }
    320 
    321 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
    322   return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
    323       base::android::AttachCurrentThread(),
    324       j_audio_manager_.obj());
    325 }
    326 
    327 }  // namespace media
    328