OSDN Git Service

TvInputHardware: Integration with audio framework changes
authorWonsik Kim <wonsik@google.com>
Tue, 27 May 2014 01:38:21 +0000 (10:38 +0900)
committerWonsik Kim <wonsik@google.com>
Thu, 19 Jun 2014 01:35:33 +0000 (10:35 +0900)
TvInputHardwareManager detects AudioPort specified by tv_input and
connect source to sink via AudioManager.createAudioPatch().

Bug: 15177175
Change-Id: I2252eb0df2d8287889ed28cc7d76dc1a659fd08b

media/java/android/media/AudioManager.java
media/java/android/media/AudioSystem.java
media/java/android/media/tv/TvInputHardwareInfo.java
services/core/java/com/android/server/tv/TvInputHal.java
services/core/java/com/android/server/tv/TvInputHardwareManager.java
services/core/jni/com_android_server_tv_TvInputHal.cpp

index 2f1e11e..3238498 100644 (file)
@@ -2534,6 +2534,9 @@ public class AudioManager {
     // 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,
      *  such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
index 9fbcd18..63ed10c 100644 (file)
@@ -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;
index 4beb960..5a45c7b 100644 (file)
@@ -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;
+        }
     }
 }
index 34168a8..1535e7a 100644 (file)
@@ -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);
             }
         });
     }
index d72ed9e..1146f0f 100644 (file)
 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<TvInputHardwareInfo> mInfoList = new ArrayList<TvInputHardwareInfo>();
     private final Context mContext;
     private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
+    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<AudioPort> devicePorts = new ArrayList<AudioPort>();
+                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
index afe629d..9a651e2 100644 (file)
@@ -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,
+            "<init>", "()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;
 }