Merge "Implement audio routing callbacks" into mnc-dev
This commit is contained in:
@@ -132,6 +132,7 @@ LOCAL_SRC_FILES:= \
|
||||
android_media_AudioRecord.cpp \
|
||||
android_media_AudioSystem.cpp \
|
||||
android_media_AudioTrack.cpp \
|
||||
android_media_DeviceCallback.cpp \
|
||||
android_media_JetPlayer.cpp \
|
||||
android_media_RemoteDisplay.cpp \
|
||||
android_media_ToneGenerator.cpp \
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "android_media_AudioFormat.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
#include "android_media_DeviceCallback.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -44,6 +45,7 @@ struct audio_record_fields_t {
|
||||
jmethodID postNativeEventInJava; //... event post callback method
|
||||
jfieldID nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
|
||||
jfieldID nativeCallbackCookie; // provides access to the AudioRecord callback data
|
||||
jfieldID nativeDeviceCallback; // provides access to the JNIDeviceCallback instance
|
||||
};
|
||||
struct audio_attributes_fields_t {
|
||||
jfieldID fieldRecSource; // AudioAttributes.mSource
|
||||
@@ -120,6 +122,33 @@ static void recorderCallback(int event, void* user, void *info) {
|
||||
}
|
||||
}
|
||||
|
||||
static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
JNIDeviceCallback* const cb =
|
||||
(JNIDeviceCallback*)env->GetLongField(thiz,
|
||||
javaAudioRecordFields.nativeDeviceCallback);
|
||||
return sp<JNIDeviceCallback>(cb);
|
||||
}
|
||||
|
||||
static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
|
||||
jobject thiz,
|
||||
const sp<JNIDeviceCallback>& cb)
|
||||
{
|
||||
Mutex::Autolock l(sLock);
|
||||
sp<JNIDeviceCallback> old =
|
||||
(JNIDeviceCallback*)env->GetLongField(thiz,
|
||||
javaAudioRecordFields.nativeDeviceCallback);
|
||||
if (cb.get()) {
|
||||
cb->incStrong((void*)setJniDeviceCallback);
|
||||
}
|
||||
if (old != 0) {
|
||||
old->decStrong((void*)setJniDeviceCallback);
|
||||
}
|
||||
env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
|
||||
return old;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
@@ -593,9 +622,63 @@ static jboolean android_media_AudioRecord_setInputDevice(
|
||||
JNIEnv *env, jobject thiz, jint device_id) {
|
||||
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == 0) {
|
||||
return 0;
|
||||
}
|
||||
return lpRecorder->setInputDevice(device_id) == NO_ERROR;
|
||||
}
|
||||
|
||||
static jint android_media_AudioRecord_getRoutedDeviceId(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (jint)lpRecorder->getRoutedDeviceId();
|
||||
}
|
||||
|
||||
static void android_media_AudioRecord_enableDeviceCallback(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == 0) {
|
||||
return;
|
||||
}
|
||||
sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
|
||||
if (cb != 0) {
|
||||
return;
|
||||
}
|
||||
audiorecord_callback_cookie *cookie =
|
||||
(audiorecord_callback_cookie *)env->GetLongField(thiz,
|
||||
javaAudioRecordFields.nativeCallbackCookie);
|
||||
if (cookie == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
|
||||
javaAudioRecordFields.postNativeEventInJava);
|
||||
status_t status = lpRecorder->addAudioDeviceCallback(cb);
|
||||
if (status == NO_ERROR) {
|
||||
setJniDeviceCallback(env, thiz, cb);
|
||||
}
|
||||
}
|
||||
|
||||
static void android_media_AudioRecord_disableDeviceCallback(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == 0) {
|
||||
return;
|
||||
}
|
||||
sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
|
||||
if (cb != 0) {
|
||||
lpRecorder->removeAudioDeviceCallback(cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
static JNINativeMethod gMethods[] = {
|
||||
@@ -628,12 +711,17 @@ static JNINativeMethod gMethods[] = {
|
||||
{"native_get_min_buff_size",
|
||||
"(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
|
||||
{"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
|
||||
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
|
||||
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
|
||||
{"native_disableDeviceCallback", "()V",
|
||||
(void *)android_media_AudioRecord_disableDeviceCallback},
|
||||
};
|
||||
|
||||
// field names found in android/media/AudioRecord.java
|
||||
#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
|
||||
#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME "mNativeRecorderInJavaObj"
|
||||
#define JAVA_NATIVECALLBACKINFO_FIELD_NAME "mNativeCallbackCookie"
|
||||
#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME "mNativeDeviceCallback"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int register_android_media_AudioRecord(JNIEnv *env)
|
||||
@@ -641,6 +729,7 @@ int register_android_media_AudioRecord(JNIEnv *env)
|
||||
javaAudioRecordFields.postNativeEventInJava = NULL;
|
||||
javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
|
||||
javaAudioRecordFields.nativeCallbackCookie = NULL;
|
||||
javaAudioRecordFields.nativeDeviceCallback = NULL;
|
||||
|
||||
|
||||
// Get the AudioRecord class
|
||||
@@ -658,6 +747,9 @@ int register_android_media_AudioRecord(JNIEnv *env)
|
||||
javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
|
||||
|
||||
javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
|
||||
audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
|
||||
|
||||
// Get the AudioAttributes class and fields
|
||||
jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
|
||||
javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
|
||||
|
||||
@@ -937,7 +937,8 @@ static jint convertAudioPortFromNative(JNIEnv *env,
|
||||
} else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
|
||||
ALOGV("convertAudioPortFromNative is a mix");
|
||||
*jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
|
||||
jHandle, nAudioPort->role, jDeviceName,
|
||||
jHandle, nAudioPort->ext.mix.handle,
|
||||
nAudioPort->role, jDeviceName,
|
||||
jSamplingRates, jChannelMasks,
|
||||
jFormats, jGains);
|
||||
} else {
|
||||
@@ -1670,7 +1671,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
|
||||
jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
|
||||
gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
|
||||
gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
|
||||
"(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
|
||||
"(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
|
||||
|
||||
jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
|
||||
gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "android_media_AudioFormat.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
#include "android_media_PlaybackSettings.h"
|
||||
#include "android_media_DeviceCallback.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -79,6 +80,7 @@ class AudioTrackJniStorage {
|
||||
sp<MemoryHeapBase> mMemHeap;
|
||||
sp<MemoryBase> mMemBase;
|
||||
audiotrack_callback_cookie mCallbackData;
|
||||
sp<JNIDeviceCallback> mDeviceCallback;
|
||||
|
||||
AudioTrackJniStorage() {
|
||||
mCallbackData.audioTrack_class = 0;
|
||||
@@ -977,6 +979,51 @@ static jboolean android_media_AudioTrack_setOutputDevice(
|
||||
return lpTrack->setOutputDevice(device_id) == NO_ERROR;
|
||||
}
|
||||
|
||||
static jint android_media_AudioTrack_getRoutedDeviceId(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
if (lpTrack == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return (jint)lpTrack->getRoutedDeviceId();
|
||||
}
|
||||
|
||||
static void android_media_AudioTrack_enableDeviceCallback(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
if (lpTrack == NULL) {
|
||||
return;
|
||||
}
|
||||
AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
|
||||
thiz, javaAudioTrackFields.jniData);
|
||||
if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
|
||||
return;
|
||||
}
|
||||
pJniStorage->mDeviceCallback =
|
||||
new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
|
||||
javaAudioTrackFields.postNativeEventInJava);
|
||||
lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
|
||||
}
|
||||
|
||||
static void android_media_AudioTrack_disableDeviceCallback(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
if (lpTrack == NULL) {
|
||||
return;
|
||||
}
|
||||
AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
|
||||
thiz, javaAudioTrackFields.jniData);
|
||||
if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
|
||||
return;
|
||||
}
|
||||
lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
|
||||
pJniStorage->mDeviceCallback.clear();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
static JNINativeMethod gMethods[] = {
|
||||
@@ -1030,6 +1077,9 @@ static JNINativeMethod gMethods[] = {
|
||||
"(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
|
||||
{"native_setOutputDevice", "(I)Z",
|
||||
(void *)android_media_AudioTrack_setOutputDevice},
|
||||
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
|
||||
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
|
||||
{"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
|
||||
};
|
||||
|
||||
|
||||
|
||||
82
core/jni/android_media_DeviceCallback.cpp
Normal file
82
core/jni/android_media_DeviceCallback.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#define LOG_TAG "AudioDeviceCallback-JNI"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <JNIHelp.h>
|
||||
#include <JniConstants.h>
|
||||
#include "core_jni_helpers.h"
|
||||
#include <media/AudioSystem.h>
|
||||
|
||||
#include "android_media_DeviceCallback.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace android;
|
||||
|
||||
JNIDeviceCallback::JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
|
||||
jmethodID postEventFromNative)
|
||||
{
|
||||
|
||||
// Hold onto the AudioTrack/AudioRecord class for use in calling the static method
|
||||
// that posts events to the application thread.
|
||||
jclass clazz = env->GetObjectClass(thiz);
|
||||
if (clazz == NULL) {
|
||||
return;
|
||||
}
|
||||
mClass = (jclass)env->NewGlobalRef(clazz);
|
||||
|
||||
// We use a weak reference so the AudioTrack/AudioRecord object can be garbage collected.
|
||||
// The reference is only used as a proxy for callbacks.
|
||||
mObject = env->NewGlobalRef(weak_thiz);
|
||||
|
||||
mPostEventFromNative = postEventFromNative;
|
||||
}
|
||||
|
||||
JNIDeviceCallback::~JNIDeviceCallback()
|
||||
{
|
||||
// remove global references
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
env->DeleteGlobalRef(mObject);
|
||||
env->DeleteGlobalRef(mClass);
|
||||
}
|
||||
|
||||
void JNIDeviceCallback::onAudioDeviceUpdate(audio_io_handle_t audioIo,
|
||||
audio_port_handle_t deviceId)
|
||||
{
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
if (env == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ALOGV("%s audioIo %d deviceId %d", __FUNCTION__, audioIo, deviceId);
|
||||
env->CallStaticVoidMethod(mClass,
|
||||
mPostEventFromNative,
|
||||
mObject,
|
||||
AUDIO_NATIVE_EVENT_ROUTING_CHANGE, deviceId, 0, NULL);
|
||||
if (env->ExceptionCheck()) {
|
||||
ALOGW("An exception occurred while notifying an event.");
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
47
core/jni/android_media_DeviceCallback.h
Normal file
47
core/jni/android_media_DeviceCallback.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_MEDIA_DEVICE_CALLBACK_H
|
||||
#define ANDROID_MEDIA_DEVICE_CALLBACK_H
|
||||
|
||||
#include <system/audio.h>
|
||||
#include <media/AudioSystem.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// keep in sync with AudioSystem.java
|
||||
#define AUDIO_NATIVE_EVENT_ROUTING_CHANGE 1000
|
||||
|
||||
class JNIDeviceCallback: public AudioSystem::AudioDeviceCallback
|
||||
{
|
||||
public:
|
||||
JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz, jmethodID postEventFromNative);
|
||||
~JNIDeviceCallback();
|
||||
|
||||
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
|
||||
audio_port_handle_t deviceId);
|
||||
|
||||
private:
|
||||
void sendEvent(int event);
|
||||
|
||||
jclass mClass; // Reference to AudioTrack/AudioRecord class
|
||||
jobject mObject; // Weak ref to AudioTrack/AudioRecord Java object to call on
|
||||
jmethodID mPostEventFromNative; // postEventFromNative method ID.
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEDIA_DEVICE_CALLBACK_H
|
||||
@@ -83,6 +83,16 @@ public class AudioDevicePort extends AudioPort {
|
||||
if (o == null || !(o instanceof AudioDevicePort)) {
|
||||
return false;
|
||||
}
|
||||
AudioDevicePort other = (AudioDevicePort)o;
|
||||
if (mType != other.type()) {
|
||||
return false;
|
||||
}
|
||||
if (mAddress == null && other.address() != null) {
|
||||
return false;
|
||||
}
|
||||
if (!mAddress.equals(other.address())) {
|
||||
return false;
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public class AudioDevicesManager {
|
||||
* @param flags A set of bitflags specifying the criteria to test.
|
||||
* @see {@link LIST_DEVICES_OUTPUTS} and {@link LIST_DEVICES_INPUTS}
|
||||
**/
|
||||
private boolean checkFlags(AudioDevicePort port, int flags) {
|
||||
private static boolean checkFlags(AudioDevicePort port, int flags) {
|
||||
return port.role() == AudioPort.ROLE_SINK && (flags & LIST_DEVICES_OUTPUTS) != 0 ||
|
||||
port.role() == AudioPort.ROLE_SOURCE && (flags & LIST_DEVICES_INPUTS) != 0;
|
||||
}
|
||||
@@ -110,8 +110,21 @@ public class AudioDevicesManager {
|
||||
* @return A (possibly zero-length) array of AudioDeviceInfo objects.
|
||||
*/
|
||||
public AudioDeviceInfo[] listDevices(int flags) {
|
||||
return listDevicesStatic(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
|
||||
* connected to the system and meeting the criteria specified in the <code>flags</code>
|
||||
* parameter.
|
||||
* @param flags A set of bitflags specifying the criteria to test.
|
||||
* @see {@link LIST_DEVICES_OUTPUTS}, {@link LIST_DEVICES_INPUTS} and {@link LIST_DEVICES_ALL}.
|
||||
* @return A (possibly zero-length) array of AudioDeviceInfo objects.
|
||||
* @hide
|
||||
*/
|
||||
public static AudioDeviceInfo[] listDevicesStatic(int flags) {
|
||||
ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
|
||||
int status = mAudioManager.listAudioDevicePorts(ports);
|
||||
int status = AudioManager.listAudioDevicePorts(ports);
|
||||
if (status != AudioManager.SUCCESS) {
|
||||
// fail and bail!
|
||||
return new AudioDeviceInfo[0];
|
||||
|
||||
@@ -3401,7 +3401,7 @@ public class AudioManager {
|
||||
* @param ports An AudioPort ArrayList where the list will be returned.
|
||||
* @hide
|
||||
*/
|
||||
public int listAudioPorts(ArrayList<AudioPort> ports) {
|
||||
public static int listAudioPorts(ArrayList<AudioPort> ports) {
|
||||
return updateAudioPortCache(ports, null);
|
||||
}
|
||||
|
||||
@@ -3410,7 +3410,7 @@ public class AudioManager {
|
||||
* @see listAudioPorts(ArrayList<AudioPort>)
|
||||
* @hide
|
||||
*/
|
||||
public int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
|
||||
public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
|
||||
ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
|
||||
int status = updateAudioPortCache(ports, null);
|
||||
if (status == SUCCESS) {
|
||||
@@ -3447,7 +3447,7 @@ public class AudioManager {
|
||||
* patch[0] contains the newly created patch
|
||||
* @hide
|
||||
*/
|
||||
public int createAudioPatch(AudioPatch[] patch,
|
||||
public static int createAudioPatch(AudioPatch[] patch,
|
||||
AudioPortConfig[] sources,
|
||||
AudioPortConfig[] sinks) {
|
||||
return AudioSystem.createAudioPatch(patch, sources, sinks);
|
||||
@@ -3464,7 +3464,7 @@ public class AudioManager {
|
||||
* - {@link #ERROR} if patch cannot be released for any other reason.
|
||||
* @hide
|
||||
*/
|
||||
public int releaseAudioPatch(AudioPatch patch) {
|
||||
public static int releaseAudioPatch(AudioPatch patch) {
|
||||
return AudioSystem.releaseAudioPatch(patch);
|
||||
}
|
||||
|
||||
@@ -3473,7 +3473,7 @@ public class AudioManager {
|
||||
* @param patches An AudioPatch array where the list will be returned.
|
||||
* @hide
|
||||
*/
|
||||
public int listAudioPatches(ArrayList<AudioPatch> patches) {
|
||||
public static int listAudioPatches(ArrayList<AudioPatch> patches) {
|
||||
return updateAudioPortCache(null, patches);
|
||||
}
|
||||
|
||||
@@ -3482,7 +3482,7 @@ public class AudioManager {
|
||||
* AudioGain.buildConfig()
|
||||
* @hide
|
||||
*/
|
||||
public int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
|
||||
public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
|
||||
if (port == null || gain == null) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
@@ -20,16 +20,21 @@ package android.media;
|
||||
* The AudioMixPort is a specialized type of AudioPort
|
||||
* describing an audio mix or stream at an input or output stream of the audio
|
||||
* framework.
|
||||
* In addition to base audio port attributes, the mix descriptor contains:
|
||||
* - the unique audio I/O handle assigned by AudioFlinger to this mix.
|
||||
* @see AudioPort
|
||||
* @hide
|
||||
*/
|
||||
|
||||
public class AudioMixPort extends AudioPort {
|
||||
|
||||
AudioMixPort(AudioHandle handle, int role, String deviceName,
|
||||
private final int mIoHandle;
|
||||
|
||||
AudioMixPort(AudioHandle handle, int ioHandle, int role, String deviceName,
|
||||
int[] samplingRates, int[] channelMasks,
|
||||
int[] formats, AudioGain[] gains) {
|
||||
super(handle, role, deviceName, samplingRates, channelMasks, formats, gains);
|
||||
mIoHandle = ioHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,11 +46,23 @@ public class AudioMixPort extends AudioPort {
|
||||
return new AudioMixPortConfig(this, samplingRate, channelMask, format, gain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
|
||||
*/
|
||||
public int ioHandle() {
|
||||
return mIoHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof AudioMixPort)) {
|
||||
return false;
|
||||
}
|
||||
AudioMixPort other = (AudioMixPort)o;
|
||||
if (mIoHandle != other.ioHandle()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,14 @@ public class AudioPort {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the system unique device ID.
|
||||
*/
|
||||
public int id() {
|
||||
return mHandle.id();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the audio port role
|
||||
*/
|
||||
|
||||
@@ -116,11 +116,6 @@ public class AudioRecord
|
||||
*/
|
||||
private static final int NATIVE_EVENT_NEW_POS = 3;
|
||||
|
||||
/**
|
||||
* Event id denotes when the routing changes.
|
||||
*/
|
||||
private final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;
|
||||
|
||||
private final static String TAG = "android.media.AudioRecord";
|
||||
|
||||
/** @hide */
|
||||
@@ -161,6 +156,12 @@ public class AudioRecord
|
||||
@SuppressWarnings("unused")
|
||||
private long mNativeCallbackCookie;
|
||||
|
||||
/**
|
||||
* Accessed by native methods: provides access to the JNIDeviceCallback instance.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private long mNativeDeviceCallback;
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Member variables
|
||||
@@ -1205,6 +1206,17 @@ public class AudioRecord
|
||||
* Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
|
||||
*/
|
||||
public AudioDeviceInfo getRoutedDevice() {
|
||||
int deviceId = native_getRoutedDeviceId();
|
||||
if (deviceId == 0) {
|
||||
return null;
|
||||
}
|
||||
AudioDeviceInfo[] devices =
|
||||
AudioDevicesManager.listDevicesStatic(AudioDevicesManager.LIST_DEVICES_INPUTS);
|
||||
for (int i = 0; i < devices.length; i++) {
|
||||
if (devices[i].getId() == deviceId) {
|
||||
return devices[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1224,6 +1236,9 @@ public class AudioRecord
|
||||
android.os.Handler handler) {
|
||||
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
|
||||
synchronized (mRoutingChangeListeners) {
|
||||
if (mRoutingChangeListeners.size() == 0) {
|
||||
native_enableDeviceCallback();
|
||||
}
|
||||
mRoutingChangeListeners.put(
|
||||
listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
|
||||
}
|
||||
@@ -1238,6 +1253,9 @@ public class AudioRecord
|
||||
synchronized (mRoutingChangeListeners) {
|
||||
if (mRoutingChangeListeners.containsKey(listener)) {
|
||||
mRoutingChangeListeners.remove(listener);
|
||||
if (mRoutingChangeListeners.size() == 0) {
|
||||
native_disableDeviceCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1271,7 +1289,7 @@ public class AudioRecord
|
||||
return;
|
||||
}
|
||||
switch(msg.what) {
|
||||
case NATIVE_EVENT_ROUTING_CHANGE:
|
||||
case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
|
||||
if (listener != null) {
|
||||
listener.onAudioRecordRouting(record);
|
||||
}
|
||||
@@ -1299,10 +1317,11 @@ public class AudioRecord
|
||||
synchronized (mRoutingChangeListeners) {
|
||||
values = mRoutingChangeListeners.values();
|
||||
}
|
||||
AudioManager.resetAudioPortGeneration();
|
||||
for(NativeRoutingEventHandlerDelegate delegate : values) {
|
||||
Handler handler = delegate.getHandler();
|
||||
if (handler != null) {
|
||||
handler.sendEmptyMessage(NATIVE_EVENT_ROUTING_CHANGE);
|
||||
handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1341,10 +1360,14 @@ public class AudioRecord
|
||||
return false;
|
||||
}
|
||||
|
||||
mPreferredDevice = deviceInfo;
|
||||
int preferredDeviceId = mPreferredDevice != null ? deviceInfo.getId() : 0;
|
||||
|
||||
return native_setInputDevice(preferredDeviceId);
|
||||
int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
|
||||
boolean status = native_setInputDevice(preferredDeviceId);
|
||||
if (status == true) {
|
||||
synchronized (this) {
|
||||
mPreferredDevice = deviceInfo;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1352,7 +1375,9 @@ public class AudioRecord
|
||||
* is not guarenteed to correspond to the actual device being used for recording.
|
||||
*/
|
||||
public AudioDeviceInfo getPreferredInputDevice() {
|
||||
return mPreferredDevice;
|
||||
synchronized (this) {
|
||||
return mPreferredDevice;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
@@ -1435,6 +1460,11 @@ public class AudioRecord
|
||||
return;
|
||||
}
|
||||
|
||||
if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
|
||||
recorder.broadcastRoutingChange();
|
||||
return;
|
||||
}
|
||||
|
||||
if (recorder.mEventHandler != null) {
|
||||
Message m =
|
||||
recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
|
||||
@@ -1486,7 +1516,9 @@ public class AudioRecord
|
||||
int sampleRateInHz, int channelCount, int audioFormat);
|
||||
|
||||
private native final boolean native_setInputDevice(int deviceId);
|
||||
|
||||
private native final int native_getRoutedDeviceId();
|
||||
private native final void native_enableDeviceCallback();
|
||||
private native final void native_disableDeviceCallback();
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Utility methods
|
||||
|
||||
@@ -721,5 +721,11 @@ public class AudioSystem
|
||||
(1 << STREAM_RING) |
|
||||
(1 << STREAM_NOTIFICATION) |
|
||||
(1 << STREAM_SYSTEM);
|
||||
|
||||
/**
|
||||
* Event posted by AudioTrack and AudioRecord JNI (JNIDeviceCallback) when routing changes.
|
||||
* Keep in sync with core/jni/android_media_DeviceCallback.h.
|
||||
*/
|
||||
final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;
|
||||
}
|
||||
|
||||
|
||||
@@ -178,12 +178,6 @@ public class AudioTrack
|
||||
*/
|
||||
private static final int NATIVE_EVENT_NEW_POS = 4;
|
||||
|
||||
/**
|
||||
* Event id denotes when the routing changes.
|
||||
*/
|
||||
private final static int NATIVE_EVENT_ROUTING_CHANGE = 1000;
|
||||
|
||||
|
||||
private final static String TAG = "android.media.AudioTrack";
|
||||
|
||||
|
||||
@@ -2057,11 +2051,14 @@ public class AudioTrack
|
||||
if (deviceInfo != null && !deviceInfo.isSink()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPreferredDevice = deviceInfo;
|
||||
int preferredDeviceId = mPreferredDevice != null ? deviceInfo.getId() : 0;
|
||||
|
||||
return native_setOutputDevice(preferredDeviceId);
|
||||
int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
|
||||
boolean status = native_setOutputDevice(preferredDeviceId);
|
||||
if (status == true) {
|
||||
synchronized (this) {
|
||||
mPreferredDevice = deviceInfo;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2069,7 +2066,9 @@ public class AudioTrack
|
||||
* is not guaranteed to correspond to the actual device being used for playback.
|
||||
*/
|
||||
public AudioDeviceInfo getPreferredOutputDevice() {
|
||||
return mPreferredDevice;
|
||||
synchronized (this) {
|
||||
return mPreferredDevice;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -2079,6 +2078,17 @@ public class AudioTrack
|
||||
* Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
|
||||
*/
|
||||
public AudioDeviceInfo getRoutedDevice() {
|
||||
int deviceId = native_getRoutedDeviceId();
|
||||
if (deviceId == 0) {
|
||||
return null;
|
||||
}
|
||||
AudioDeviceInfo[] devices =
|
||||
AudioDevicesManager.listDevicesStatic(AudioDevicesManager.LIST_DEVICES_OUTPUTS);
|
||||
for (int i = 0; i < devices.length; i++) {
|
||||
if (devices[i].getId() == deviceId) {
|
||||
return devices[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2098,6 +2108,9 @@ public class AudioTrack
|
||||
android.os.Handler handler) {
|
||||
if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
|
||||
synchronized (mRoutingChangeListeners) {
|
||||
if (mRoutingChangeListeners.size() == 0) {
|
||||
native_enableDeviceCallback();
|
||||
}
|
||||
mRoutingChangeListeners.put(
|
||||
listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
|
||||
}
|
||||
@@ -2113,6 +2126,9 @@ public class AudioTrack
|
||||
if (mRoutingChangeListeners.containsKey(listener)) {
|
||||
mRoutingChangeListeners.remove(listener);
|
||||
}
|
||||
if (mRoutingChangeListeners.size() == 0) {
|
||||
native_disableDeviceCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2124,10 +2140,11 @@ public class AudioTrack
|
||||
synchronized (mRoutingChangeListeners) {
|
||||
values = mRoutingChangeListeners.values();
|
||||
}
|
||||
AudioManager.resetAudioPortGeneration();
|
||||
for(NativeRoutingEventHandlerDelegate delegate : values) {
|
||||
Handler handler = delegate.getHandler();
|
||||
if (handler != null) {
|
||||
handler.sendEmptyMessage(NATIVE_EVENT_ROUTING_CHANGE);
|
||||
handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2240,7 +2257,7 @@ public class AudioTrack
|
||||
return;
|
||||
}
|
||||
switch(msg.what) {
|
||||
case NATIVE_EVENT_ROUTING_CHANGE:
|
||||
case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
|
||||
if (listener != null) {
|
||||
listener.onAudioTrackRouting(track);
|
||||
}
|
||||
@@ -2273,6 +2290,10 @@ public class AudioTrack
|
||||
return;
|
||||
}
|
||||
|
||||
if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
|
||||
track.broadcastRoutingChange();
|
||||
return;
|
||||
}
|
||||
NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate;
|
||||
if (delegate != null) {
|
||||
Handler handler = delegate.getHandler();
|
||||
@@ -2281,7 +2302,6 @@ public class AudioTrack
|
||||
handler.sendMessage(m);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2362,6 +2382,9 @@ public class AudioTrack
|
||||
private native final int native_setAuxEffectSendLevel(float level);
|
||||
|
||||
private native final boolean native_setOutputDevice(int deviceId);
|
||||
private native final int native_getRoutedDeviceId();
|
||||
private native final void native_enableDeviceCallback();
|
||||
private native final void native_disableDeviceCallback();
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Utility methods
|
||||
|
||||
Reference in New Issue
Block a user