diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 2f1e11efb0f77..323849830dd3b 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2533,6 +2533,9 @@ public class AudioManager { // class is not used by other parts of the framework, which instead use definitions and methods // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. + /** @hide + * The audio device code for representing "no device." */ + public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE; /** @hide * The audio output device code for the small speaker at the front of the device used * when placing calls. Does not refer to an in-ear headphone without attached microphone, diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 9fbcd186bdd75..63ed10c3fcf57 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -225,6 +225,7 @@ public class AudioSystem // audio device definitions: must be kept in sync with values in system/core/audio.h // + public static final int DEVICE_NONE = 0x0; // reserved bits public static final int DEVICE_BIT_IN = 0x80000000; public static final int DEVICE_BIT_DEFAULT = 0x40000000; diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java index 4beb9607232d4..5a45c7bd52dc2 100644 --- a/media/java/android/media/tv/TvInputHardwareInfo.java +++ b/media/java/android/media/tv/TvInputHardwareInfo.java @@ -16,6 +16,7 @@ package android.media.tv; +import android.media.AudioManager; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -56,14 +57,11 @@ public final class TvInputHardwareInfo implements Parcelable { private int mDeviceId; private int mType; - // TODO: Add audio port & audio address for audio service. + private int mAudioType; + private String mAudioAddress; // TODO: Add HDMI handle for HDMI service. - public TvInputHardwareInfo() { } - - public TvInputHardwareInfo(int deviceId, int type) { - mDeviceId = deviceId; - mType = type; + private TvInputHardwareInfo() { } public int getDeviceId() { @@ -74,6 +72,14 @@ public final class TvInputHardwareInfo implements Parcelable { return mType; } + public int getAudioType() { + return mAudioType; + } + + public String getAudioAddress() { + return mAudioAddress; + } + // Parcelable @Override public int describeContents() { @@ -84,10 +90,59 @@ public final class TvInputHardwareInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mDeviceId); dest.writeInt(mType); + dest.writeInt(mAudioType); + dest.writeString(mAudioAddress); } public void readFromParcel(Parcel source) { mDeviceId = source.readInt(); mType = source.readInt(); + mAudioType = source.readInt(); + mAudioAddress = source.readString(); + } + + public static final class Builder { + private Integer mDeviceId = null; + private Integer mType = null; + private int mAudioType = AudioManager.DEVICE_NONE; + private String mAudioAddress = ""; + + public Builder() { + } + + public Builder deviceId(int deviceId) { + mDeviceId = deviceId; + return this; + } + + public Builder type(int type) { + mType = type; + return this; + } + + public Builder audioType(int audioType) { + mAudioType = audioType; + return this; + } + + public Builder audioAddress(String audioAddress) { + mAudioAddress = audioAddress; + return this; + } + + public TvInputHardwareInfo build() { + if (mDeviceId == null || mType == null) { + throw new UnsupportedOperationException(); + } + + TvInputHardwareInfo info = new TvInputHardwareInfo(); + info.mDeviceId = mDeviceId; + info.mType = mType; + info.mAudioType = mAudioType; + if (info.mAudioType != AudioManager.DEVICE_NONE) { + info.mAudioAddress = mAudioAddress; + } + return info; + } } } diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java index 34168a82141a7..1535e7a9a9347 100644 --- a/services/core/java/com/android/server/tv/TvInputHal.java +++ b/services/core/java/com/android/server/tv/TvInputHal.java @@ -94,8 +94,7 @@ final class TvInputHal { } // Called from native - private void deviceAvailableFromNative(int deviceId, int type) { - final TvInputHardwareInfo info = new TvInputHardwareInfo(deviceId, type); + private void deviceAvailableFromNative(final TvInputHardwareInfo info) { mHandler.post(new Runnable() { @Override public void run() { @@ -105,23 +104,21 @@ final class TvInputHal { }); } - private void deviceUnavailableFromNative(int deviceId) { - final int id = deviceId; + private void deviceUnavailableFromNative(final int deviceId) { mHandler.post(new Runnable() { @Override public void run() { - mCallback.onDeviceUnavailable(id); + mCallback.onDeviceUnavailable(deviceId); } }); } - private void streamConfigsChangedFromNative(int deviceId) { - final int id = deviceId; + private void streamConfigsChangedFromNative(final int deviceId) { mHandler.post(new Runnable() { @Override public void run() { - retrieveStreamConfigs(id); - mCallback.onStreamConfigurationChanged(id, mStreamConfigs); + retrieveStreamConfigs(deviceId); + mCallback.onStreamConfigurationChanged(deviceId, mStreamConfigs); } }); } diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index d72ed9e3f73e2..1146f0fc3f8d9 100644 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -17,6 +17,11 @@ package com.android.server.tv; import android.content.Context; +import android.media.AudioDevicePort; +import android.media.AudioManager; +import android.media.AudioPatch; +import android.media.AudioPort; +import android.media.AudioPortConfig; import android.media.tv.ITvInputHardware; import android.media.tv.ITvInputHardwareCallback; import android.media.tv.TvInputHardwareInfo; @@ -48,11 +53,13 @@ class TvInputHardwareManager implements TvInputHal.Callback { private final List mInfoList = new ArrayList(); private final Context mContext; private final Set mActiveHdmiSources = new HashSet(); + private final AudioManager mAudioManager; private final Object mLock = new Object(); public TvInputHardwareManager(Context context) { mContext = context; + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); // TODO(hdmi): mHdmiManager = mContext.getSystemService(...); // TODO(hdmi): mHdmiClient = mHdmiManager.getTvClient(); mHal.init(); @@ -258,12 +265,48 @@ class TvInputHardwareManager implements TvInputHal.Callback { private boolean mReleased = false; private final Object mImplLock = new Object(); + private final AudioDevicePort mAudioSource; + private final AudioDevicePort mAudioSink; + private AudioPatch mAudioPatch = null; + public TvInputHardwareImpl(TvInputHardwareInfo info) { mInfo = info; + AudioDevicePort audioSource = null; + AudioDevicePort audioSink = null; + if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { + ArrayList devicePorts = new ArrayList(); + if (mAudioManager.listAudioDevicePorts(devicePorts) == AudioManager.SUCCESS) { + // Find source + for (AudioPort port : devicePorts) { + AudioDevicePort devicePort = (AudioDevicePort) port; + if (devicePort.type() == mInfo.getAudioType() && + devicePort.address().equals(mInfo.getAudioAddress())) { + audioSource = devicePort; + break; + } + } + // Find sink + // TODO: App may want to specify sink device? + int sinkDevices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); + for (AudioPort port : devicePorts) { + AudioDevicePort devicePort = (AudioDevicePort) port; + if (devicePort.type() == sinkDevices) { + audioSink = devicePort; + break; + } + } + } + } + mAudioSource = audioSource; + mAudioSink = audioSink; } public void release() { synchronized (mImplLock) { + if (mAudioPatch != null) { + mAudioManager.releaseAudioPatch(mAudioPatch); + mAudioPatch = null; + } mReleased = true; } } @@ -288,6 +331,22 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } } + if (mAudioSource != null && mAudioSink != null) { + if (surface != null) { + AudioPortConfig sourceConfig = mAudioSource.activeConfig(); + AudioPortConfig sinkConfig = mAudioSink.activeConfig(); + AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; + // TODO: build config if activeConfig() == null + mAudioManager.createAudioPatch( + audioPatchArray, + new AudioPortConfig[] { sourceConfig }, + new AudioPortConfig[] { sinkConfig }); + mAudioPatch = audioPatchArray[0]; + } else { + mAudioManager.releaseAudioPatch(mAudioPatch); + mAudioPatch = null; + } + } return mHal.setSurface(mInfo.getDeviceId(), surface, config) == TvInputHal.SUCCESS; } } @@ -299,7 +358,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { throw new IllegalStateException("Device already released."); } } - // TODO + // TODO: Use AudioGain? } @Override diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index afe629defa71f..9a651e2385437 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -54,6 +54,17 @@ static struct { jmethodID build; } gTvStreamConfigBuilderClassInfo; +static struct { + jclass clazz; + + jmethodID constructor; + jmethodID deviceId; + jmethodID type; + jmethodID audioType; + jmethodID audioAddress; + jmethodID build; +} gTvInputHardwareInfoBuilderClassInfo; + //////////////////////////////////////////////////////////////////////////////// class JTvInputHal { @@ -209,7 +220,6 @@ const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numCo return configs; } - // static void JTvInputHal::notify( tv_input_device_t* dev, tv_input_event_t* event, void* data) { @@ -232,11 +242,32 @@ void JTvInputHal::notify( void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) { JNIEnv* env = AndroidRuntime::getJNIEnv(); mConnections.add(info.device_id, Connection()); + + jobject builder = env->NewObject( + gTvInputHardwareInfoBuilderClassInfo.clazz, + gTvInputHardwareInfoBuilderClassInfo.constructor); + env->CallObjectMethod( + builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.device_id); + env->CallObjectMethod( + builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type); + env->CallObjectMethod( + builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audio_type); + if (info.audio_type != AUDIO_DEVICE_NONE) { + jstring audioAddress = env->NewStringUTF(info.audio_address); + env->CallObjectMethod( + builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress, audioAddress); + env->DeleteLocalRef(audioAddress); + } + + jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build); + env->CallVoidMethod( mThiz, gTvInputHalClassInfo.deviceAvailable, - info.device_id, - info.type); + infoObject); + + env->DeleteLocalRef(builder); + env->DeleteLocalRef(infoObject); } void JTvInputHal::onDeviceUnavailable(int deviceId) { @@ -339,7 +370,8 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) { FIND_CLASS(clazz, "com/android/server/tv/TvInputHal"); GET_METHOD_ID( - gTvInputHalClassInfo.deviceAvailable, clazz, "deviceAvailableFromNative", "(II)V"); + gTvInputHalClassInfo.deviceAvailable, clazz, + "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V"); GET_METHOD_ID( gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V"); GET_METHOD_ID( @@ -382,6 +414,36 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) { gTvStreamConfigBuilderClassInfo.clazz, "build", "()Landroid/media/tv/TvStreamConfig;"); + FIND_CLASS(gTvInputHardwareInfoBuilderClassInfo.clazz, + "android/media/tv/TvInputHardwareInfo$Builder"); + gTvInputHardwareInfoBuilderClassInfo.clazz = + jclass(env->NewGlobalRef(gTvInputHardwareInfoBuilderClassInfo.clazz)); + + GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.constructor, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "", "()V"); + GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.deviceId, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "deviceId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); + GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.type, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "type", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); + GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.audioType, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "audioType", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); + GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.audioAddress, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "audioAddress", "(Ljava/lang/String;)Landroid/media/tv/TvInputHardwareInfo$Builder;"); + GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.build, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "build", "()Landroid/media/tv/TvInputHardwareInfo;"); + return 0; }