This source file includes following definitions.
- AddDefaultDevice
- CreateAudioManager
- communication_mode_is_on_
- HasAudioOutputDevices
- HasAudioInputDevices
- GetAudioInputDeviceNames
- GetAudioOutputDeviceNames
- GetInputStreamParameters
- MakeAudioOutputStream
- MakeAudioInputStream
- ReleaseOutputStream
- ReleaseInputStream
- MakeLinearOutputStream
- MakeLowLatencyOutputStream
- MakeLinearInputStream
- MakeLowLatencyInputStream
- RegisterAudioManager
- SetMute
- GetPreferredOutputStreamParameters
- HasNoAudioInputStreams
- InitializeOnAudioThread
- ShutdownOnAudioThread
- SetCommunicationAudioModeOn
- SetAudioDevice
- GetNativeOutputSampleRate
- IsAudioLowLatencySupported
- GetAudioLowLatencyOutputFrameSize
- GetOptimalOutputFrameSize
- DoSetMuteOnAudioThread
#include "media/audio/android/audio_manager_android.h"
#include "base/android/build_info.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "jni/AudioManagerAndroid_jni.h"
#include "media/audio/android/audio_record_input.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/fake_audio_input_stream.h"
#include "media/base/channel_layout.h"
using base::android::AppendJavaStringArrayToStringVector;
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
namespace media {
static void AddDefaultDevice(AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
device_names->push_front(
AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
AudioManagerBase::kDefaultDeviceId));
}
static const int kMaxOutputStreams = 10;
static const int kDefaultInputBufferSize = 1024;
static const int kDefaultOutputBufferSize = 2048;
AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
return new AudioManagerAndroid(audio_log_factory);
}
AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
: AudioManagerBase(audio_log_factory),
communication_mode_is_on_(false) {
SetMaxOutputStreamsAllowed(kMaxOutputStreams);
GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
&AudioManagerAndroid::InitializeOnAudioThread,
base::Unretained(this)));
}
AudioManagerAndroid::~AudioManagerAndroid() {
GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
&AudioManagerAndroid::ShutdownOnAudioThread, base::Unretained(this)));
Shutdown();
}
bool AudioManagerAndroid::HasAudioOutputDevices() {
return true;
}
bool AudioManagerAndroid::HasAudioInputDevices() {
return true;
}
void AudioManagerAndroid::GetAudioInputDeviceNames(
AudioDeviceNames* device_names) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DCHECK(device_names->empty());
AddDefaultDevice(device_names);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobjectArray> j_device_array =
Java_AudioManagerAndroid_getAudioInputDeviceNames(
env, j_audio_manager_.obj());
jsize len = env->GetArrayLength(j_device_array.obj());
AudioDeviceName device;
for (jsize i = 0; i < len; ++i) {
ScopedJavaLocalRef<jobject> j_device(
env, env->GetObjectArrayElement(j_device_array.obj(), i));
ScopedJavaLocalRef<jstring> j_device_name =
Java_AudioDeviceName_name(env, j_device.obj());
ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
ScopedJavaLocalRef<jstring> j_device_id =
Java_AudioDeviceName_id(env, j_device.obj());
ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
device_names->push_back(device);
}
}
void AudioManagerAndroid::GetAudioOutputDeviceNames(
AudioDeviceNames* device_names) {
AddDefaultDevice(device_names);
}
AudioParameters AudioManagerAndroid::GetInputStreamParameters(
const std::string& device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
JNIEnv* env = AttachCurrentThread();
ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
env, GetNativeOutputSampleRate(),
ChannelLayoutToChannelCount(channel_layout));
int effects = AudioParameters::NO_EFFECTS;
effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ?
AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS;
AudioParameters params(
AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0,
GetNativeOutputSampleRate(), 16,
buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects);
return params;
}
AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
const AudioParameters& params,
const std::string& device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
AudioOutputStream* stream =
AudioManagerBase::MakeAudioOutputStream(params, std::string());
streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
return stream;
}
AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
bool has_no_input_streams = HasNoAudioInputStreams();
AudioInputStream* stream =
AudioManagerBase::MakeAudioInputStream(params, device_id);
if (stream && has_no_input_streams) {
communication_mode_is_on_ = true;
SetCommunicationAudioModeOn(true);
}
return stream;
}
void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
AudioManagerBase::ReleaseOutputStream(stream);
streams_.erase(static_cast<OpenSLESOutputStream*>(stream));
}
void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DCHECK(!j_audio_manager_.is_null());
AudioManagerBase::ReleaseInputStream(stream);
if (HasNoAudioInputStreams()) {
communication_mode_is_on_ = false;
SetCommunicationAudioModeOn(false);
}
}
AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
const AudioParameters& params) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
return new OpenSLESOutputStream(this, params, SL_ANDROID_STREAM_MEDIA);
}
AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
const AudioParameters& params,
const std::string& device_id) {
DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
const SLint32 stream_type = communication_mode_is_on_ ?
SL_ANDROID_STREAM_VOICE : SL_ANDROID_STREAM_MEDIA;
return new OpenSLESOutputStream(this, params, stream_type);
}
AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) {
DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
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(GetTaskRunner()->BelongsToCurrentThread());
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
if (!SetAudioDevice(device_id)) {
LOG(ERROR) << "Unable to select audio device!";
return NULL;
}
if (params.effects() != AudioParameters::NO_EFFECTS) {
DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16);
DVLOG(1) << "Creating AudioRecordInputStream";
return new AudioRecordInputStream(this, params);
}
DVLOG(1) << "Creating OpenSLESInputStream";
return new OpenSLESInputStream(this, params);
}
bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
return RegisterNativesImpl(env);
}
void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(
&AudioManagerAndroid::DoSetMuteOnAudioThread,
base::Unretained(this),
muted));
}
AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
const std::string& output_device_id,
const AudioParameters& input_params) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
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()) {
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, AudioParameters::NO_EFFECTS);
}
bool AudioManagerAndroid::HasNoAudioInputStreams() {
return input_stream_count() == 0;
}
void AudioManagerAndroid::InitializeOnAudioThread() {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DVLOG(2) << "Creating Java part of the audio manager";
j_audio_manager_.Reset(
Java_AudioManagerAndroid_createAudioManagerAndroid(
base::android::AttachCurrentThread(),
base::android::GetApplicationContext(),
reinterpret_cast<intptr_t>(this)));
Java_AudioManagerAndroid_init(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
void AudioManagerAndroid::ShutdownOnAudioThread() {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DVLOG(2) << "Destroying Java part of the audio manager";
Java_AudioManagerAndroid_close(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
j_audio_manager_.Reset();
}
void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
Java_AudioManagerAndroid_setCommunicationAudioModeOn(
base::android::AttachCurrentThread(),
j_audio_manager_.obj(), on);
}
bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
env,
device_id == AudioManagerBase::kDefaultDeviceId ?
std::string() : device_id);
return Java_AudioManagerAndroid_setDevice(
env, j_audio_manager_.obj(), j_device_id.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());
}
int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
int channels) {
if (IsAudioLowLatencySupported())
return GetAudioLowLatencyOutputFrameSize();
return std::max(kDefaultOutputBufferSize,
Java_AudioManagerAndroid_getMinOutputFrameSize(
base::android::AttachCurrentThread(),
sample_rate, channels));
}
void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
for (OutputStreams::iterator it = streams_.begin();
it != streams_.end(); ++it) {
(*it)->SetMute(muted);
}
}
}