blob: 164344aba0b4ea1159d362d96019698714f4e70b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/audio/android/audio_manager_android.h"
#include "base/logging.h"
#include "jni/AudioManagerAndroid_jni.h"
#include "media/audio/android/opensles_input.h"
#include "media/audio/android/opensles_output.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_parameters.h"
#include "media/audio/audio_util.h"
#include "media/audio/fake_audio_input_stream.h"
#include "media/base/channel_layout.h"
namespace media {
// Maximum number of output streams that can be open simultaneously.
static const int kMaxOutputStreams = 10;
static const int kAudioModeNormal = 0x00000000;
static const int kAudioModeInCommunication = 0x00000003;
static const int kDefaultInputBufferSize = 1024;
static const int kDefaultOutputBufferSize = 2048;
AudioManager* CreateAudioManager() {
return new AudioManagerAndroid();
}
AudioManagerAndroid::AudioManagerAndroid() {
SetMaxOutputStreamsAllowed(kMaxOutputStreams);
j_audio_manager_.Reset(
Java_AudioManagerAndroid_createAudioManagerAndroid(
base::android::AttachCurrentThread(),
base::android::GetApplicationContext()));
}
AudioManagerAndroid::~AudioManagerAndroid() {
Shutdown();
}
bool AudioManagerAndroid::HasAudioOutputDevices() {
return true;
}
bool AudioManagerAndroid::HasAudioInputDevices() {
return true;
}
void AudioManagerAndroid::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
device_names->push_front(
media::AudioDeviceName(kDefaultDeviceName, kDefaultDeviceId));
}
AudioParameters AudioManagerAndroid::GetInputStreamParameters(
const std::string& device_id) {
// Use mono as preferred number of input channels on Android to save
// resources. Using mono also avoids a driver issue seen on Samsung
// Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
base::android::AttachCurrentThread(), GetNativeOutputSampleRate(),
ChannelLayoutToChannelCount(channel_layout));
return AudioParameters(
AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
GetNativeOutputSampleRate(), 16,
buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size);
}
AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
const AudioParameters& params, const std::string& input_device_id) {
AudioOutputStream* stream =
AudioManagerBase::MakeAudioOutputStream(params, std::string());
if (stream && output_stream_count() == 1) {
SetAudioMode(kAudioModeInCommunication);
RegisterHeadsetReceiver();
}
return stream;
}
AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
const AudioParameters& params, const std::string& device_id) {
AudioInputStream* stream =
AudioManagerBase::MakeAudioInputStream(params, device_id);
return stream;
}
void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
AudioManagerBase::ReleaseOutputStream(stream);
if (!output_stream_count()) {
UnregisterHeadsetReceiver();
SetAudioMode(kAudioModeNormal);
}
}
void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
AudioManagerBase::ReleaseInputStream(stream);
}
AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
const AudioParameters& params) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
return new OpenSLESOutputStream(this, params);
}
AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
const AudioParameters& params, const std::string& input_device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return new OpenSLESOutputStream(this, params);
}
AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
return new OpenSLESInputStream(this, params);
}
AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return new OpenSLESInputStream(this, params);
}
int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
int channels) {
if (IsAudioLowLatencySupported()) {
return GetAudioLowLatencyOutputFrameSize();
} else {
return std::max(kDefaultOutputBufferSize,
Java_AudioManagerAndroid_getMinOutputFrameSize(
base::android::AttachCurrentThread(),
sample_rate, channels));
}
}
AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
const AudioParameters& input_params) {
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = GetNativeOutputSampleRate();
int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
int bits_per_sample = 16;
int input_channels = 0;
if (input_params.IsValid()) {
// Use the client's input parameters if they are valid.
sample_rate = input_params.sample_rate();
bits_per_sample = input_params.bits_per_sample();
channel_layout = input_params.channel_layout();
input_channels = input_params.input_channels();
buffer_size = GetOptimalOutputFrameSize(
sample_rate, ChannelLayoutToChannelCount(channel_layout));
}
int user_buffer_size = GetUserBufferSize();
if (user_buffer_size)
buffer_size = user_buffer_size;
return AudioParameters(
AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
sample_rate, bits_per_sample, buffer_size);
}
// static
bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
return RegisterNativesImpl(env);
}
void AudioManagerAndroid::SetAudioMode(int mode) {
Java_AudioManagerAndroid_setMode(
base::android::AttachCurrentThread(),
j_audio_manager_.obj(), mode);
}
void AudioManagerAndroid::RegisterHeadsetReceiver() {
Java_AudioManagerAndroid_registerHeadsetReceiver(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
void AudioManagerAndroid::UnregisterHeadsetReceiver() {
Java_AudioManagerAndroid_unregisterHeadsetReceiver(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
int AudioManagerAndroid::GetNativeOutputSampleRate() {
return Java_AudioManagerAndroid_getNativeOutputSampleRate(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
bool AudioManagerAndroid::IsAudioLowLatencySupported() {
return Java_AudioManagerAndroid_isAudioLowLatencySupported(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
} // namespace media