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 \
#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
+#include "android_media_DeviceCallback.h"
// ----------------------------------------------------------------------------
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
}
}
+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)
{
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[] = {
{"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)
javaAudioRecordFields.postNativeEventInJava = NULL;
javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
javaAudioRecordFields.nativeCallbackCookie = NULL;
+ javaAudioRecordFields.nativeDeviceCallback = NULL;
// Get the AudioRecord class
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");
} 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 {
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);
#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
#include "android_media_PlaybackSettings.h"
+#include "android_media_DeviceCallback.h"
// ----------------------------------------------------------------------------
sp<MemoryHeapBase> mMemHeap;
sp<MemoryBase> mMemBase;
audiotrack_callback_cookie mCallbackData;
+ sp<JNIDeviceCallback> mDeviceCallback;
AudioTrackJniStorage() {
mCallbackData.audioTrack_class = 0;
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[] = {
"(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},
};
--- /dev/null
+/*
+ * 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();
+ }
+}
+
--- /dev/null
+/*
+ * 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
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);
}
* @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;
}
* @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];
* @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);
}
* @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) {
* 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);
* - {@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);
}
* @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);
}
* 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;
}
* 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;
}
/**
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);
}
}
/**
+ * Get the system unique device ID.
+ */
+ public int id() {
+ return mHandle.id();
+ }
+
+
+ /**
* Get the audio port role
*/
public int role() {
*/
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 */
@SuppressWarnings("unused")
private long mNativeCallbackCookie;
+ /**
+ * Accessed by native methods: provides access to the JNIDeviceCallback instance.
+ */
+ @SuppressWarnings("unused")
+ private long mNativeDeviceCallback;
+
//---------------------------------------------------------
// Member variables
* 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;
}
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));
}
synchronized (mRoutingChangeListeners) {
if (mRoutingChangeListeners.containsKey(listener)) {
mRoutingChangeListeners.remove(listener);
+ if (mRoutingChangeListeners.size() == 0) {
+ native_disableDeviceCallback();
+ }
}
}
}
return;
}
switch(msg.what) {
- case NATIVE_EVENT_ROUTING_CHANGE:
+ case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
if (listener != null) {
listener.onAudioRecordRouting(record);
}
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);
}
}
}
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;
}
/**
* is not guarenteed to correspond to the actual device being used for recording.
*/
public AudioDeviceInfo getPreferredInputDevice() {
- return mPreferredDevice;
+ synchronized (this) {
+ return mPreferredDevice;
+ }
}
//---------------------------------------------------------
return;
}
+ if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
+ recorder.broadcastRoutingChange();
+ return;
+ }
+
if (recorder.mEventHandler != null) {
Message m =
recorder.mEventHandler.obtainMessage(what, arg1, arg2, obj);
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
(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;
}
*/
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";
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;
}
/**
* is not guaranteed to correspond to the actual device being used for playback.
*/
public AudioDeviceInfo getPreferredOutputDevice() {
- return mPreferredDevice;
+ synchronized (this) {
+ return mPreferredDevice;
+ }
}
//--------------------------------------------------------------------------
* 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;
}
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));
}
if (mRoutingChangeListeners.containsKey(listener)) {
mRoutingChangeListeners.remove(listener);
}
+ if (mRoutingChangeListeners.size() == 0) {
+ native_disableDeviceCallback();
+ }
}
}
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);
}
}
}
return;
}
switch(msg.what) {
- case NATIVE_EVENT_ROUTING_CHANGE:
+ case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
if (listener != null) {
listener.onAudioTrackRouting(track);
}
return;
}
+ if (what == AudioSystem.NATIVE_EVENT_ROUTING_CHANGE) {
+ track.broadcastRoutingChange();
+ return;
+ }
NativePositionEventHandlerDelegate delegate = track.mEventHandlerDelegate;
if (delegate != null) {
Handler handler = delegate.getHandler();
handler.sendMessage(m);
}
}
-
}
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