Saturday, August 15, 2015

Develop a HDMI TV Input using Android TV Framework - Part 1

This basic article is for System Developer for Android TV, provides background on what and how to develop so that a TV application(which is based on Android TV framework) can render video from a HDMI input(like Nexus Player or HDMI Media Player etc.) plugged in TV.

We can further divide this task in 2 sub-task -

[1]Develop TvInputService for HDMI Input

[2]Implement TvInput HAL for HDMI Input


Also this development is done in a SOC vendor side, i.e.

  • First sub-task will be part of System-Apps, it uses System APIs,
  • and second HAL implementation sub-task is a typical Android HAL implementation which relies on lower layer HDMI layer. 



Before this following Android Developer pages should be gone through



And obviously one must have installed a TV application(like "Live Channels" by Google) which can detect and interact to our HDMI input implementation.

Now let's start 1st part, 

Develop TvInputService for HDMI Input


Android TV framework base classes/APIs can be found in following path
/platform/frameworks/base/media/java/android/media/tv/

A TV input Service should be extended from TvInputService and hence implements all the abstract methods of it and it's inner class Session, also overrides some of methods.

public class HDMIInputService extends TvInputService
{

    private int HDMI_HW_ID = 1;
    private TvInputInfo mTvInputInfo;

    @Override
    public Session onCreateSession(String inputId)
    {
        return new HDMISession(this, inputId);
    }

    @Override
    public TvInputInfo onHardwareAdded(TvInputHardwareInfo hardwareInfo)
    {
        Context context = getApplicationContext();
        ResolveInfo ri = context.getPackageManager().resolveService(new Intent("android.media.tv.TvInputService"),          PackageManager.GET_INTENT_FILTERS | PackageManager.GET_META_DATA);
        mTvInputInfo = TvInputInfo.createTvInputInfo(context, ri, hardwareInfo, null, TvContract.buildChannelUriForPassthroughInput(Id));
        return mTvInputInfo;
    }
    @Override
    public String onHardwareRemoved(TvInputHardwareInfo hardwareInfo)
    {
        return null;
    }

    private class  HDMISession extends Session
    {

        private final Context mContext;
        private final String mInputId;
        private Surface mSurface;
        private float mVolume;
        private boolean mCaptionEnabled;
        private TvInputManager mTvInputManager;
        private TvInputManager.Hardware mHardware;
        private TvStreamConfig[] mTvStreamConfig;

        private final TvInputManager.HardwareCallback mHardwareCallback = new TvInputManager.HardwareCallback() {

            @Override
            public void onReleased() { }

            @Override
            public void onStreamConfigChanged(TvStreamConfig[] configs)
            {
                mTvStreamConfig = configs;
            }

        };

        HDMISession (Context context, String inputId)
        {
            super(context);
            mContext = context;
            mInputId = inputId;
            mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
            mHardware = mTvInputManager.acquireTvInputHardware(HDMI_HW_ID, mHardwareCallback, mTvInputInfo);
        }
        @Override
        public void onRelease() {
            mTvInputManager.releaseTvInputHardware(HDMI_HW_ID, mHardware);
        }
        @Override
        public boolean onSetSurface(Surface surface)
        {
            mSurface = surface;
            mHardware.setSurface(mSurface, mTvStreamConfig[0]);
            return true;
        }
        @Override
        public void onSetStreamVolume(float volume)
        {
            mVolume = volume;
        }
        @Override
        public boolean onTune(Uri channeluri)
        {
            notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
            notifyVideoAvailable();
            return true;
        }
        @Override
        public void onSetCaptionEnabled(boolean enabled)
        {
            mCaptionEnabled = enabled;
        }        
        @Override
        public boolean onKeyUp(int keyCode, KeyEvent event) {
            return false; //if not handling, otherwise return true
        }

    }

}

To keep things simple, only minimal code is written here. This can be build as independent apk and installed. Reference can be taken from SampleTvInput here.
Now in second part, HDMI tv_input HAL will be implemented.

1 comment: