TunableTvView.java revision b47a0ad3227b940175fa4ecfe5c4113da72c8237
1d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leepackage com.android.tv.ui;
2900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
3900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Choimport android.content.Context;
49035590d94d136a020e499ce720b9d2cf1f6f45cJae Seoimport android.media.tv.TvInputInfo;
59035590d94d136a020e499ce720b9d2cf1f6f45cJae Seoimport android.media.tv.TvView;
6900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Choimport android.util.AttributeSet;
7900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Choimport android.util.Log;
8900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Choimport android.view.SurfaceHolder;
9b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kangimport android.view.SurfaceView;
10900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
11d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leeimport com.android.tv.data.Channel;
1221abb13274f379e69c3c86d51e493122cccca345Dongwon Kangimport com.android.tv.data.StreamInfo;
13d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leeimport com.android.tv.util.TvInputManagerHelper;
14d422754c0cc8475d6e2c8c079ed2ee2e96213edbChulwoo Leeimport com.android.tv.util.Utils;
15900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
1621abb13274f379e69c3c86d51e493122cccca345Dongwon Kangpublic class TunableTvView extends TvView implements StreamInfo {
17900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private static final boolean DEBUG = true;
18900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private static final String TAG = "TunableTvView";
19900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
20900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private static final int DELAY_FOR_SURFACE_RELEASE = 300;
21900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
22900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private float mVolume;
23900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private long mChannelId = Channel.INVALID_ID;
24900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private TvInputManagerHelper mInputManagerHelper;
25900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private boolean mStarted;
26900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private TvInputInfo mInputInfo;
27900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private OnTuneListener mOnTuneListener;
2821abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    private int mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN;
29e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    private int mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN;
30e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    private boolean mHasClosedCaption = false;
31b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang    private SurfaceView mSurface;
32900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
33900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
34900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        @Override
35900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
36900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
37900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        @Override
38900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        public void surfaceCreated(SurfaceHolder holder) { }
39900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
40900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        @Override
41900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        public void surfaceDestroyed(SurfaceHolder holder) {
42900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            // TODO: It is a hack to wait to release a surface at TIS. If there is a way to
43900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            // know when the surface is released at TIS, we don't need this hack.
44900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            try {
45900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                if (DEBUG) Log.d(TAG, "Sleep to wait destroying a surface");
46900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                Thread.sleep(DELAY_FOR_SURFACE_RELEASE);
47900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                if (DEBUG) Log.d(TAG, "Wake up from sleeping");
48900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            } catch (InterruptedException e) {
49900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                e.printStackTrace();
50900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            }
51900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
52900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    };
53900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
549bb548ba08d7e222f276287fead545c6a11704d8Jae Seo    private final TvInputListener mListener =
559bb548ba08d7e222f276287fead545c6a11704d8Jae Seo            new TvInputListener() {
56900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                @Override
579bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                public void onError(String inputId, int errorCode) {
589bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                    if (errorCode == TvView.ERROR_BUSY) {
599bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        Log.w(TAG, "Failed to bind an input");
60900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                        long channelId = mChannelId;
61900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                        mChannelId = Channel.INVALID_ID;
62900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                        mInputInfo = null;
63900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                        if (mOnTuneListener != null) {
64900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                            mOnTuneListener.onTuned(false, channelId);
65900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                            mOnTuneListener = null;
66900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                        }
679bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                    } else if (errorCode == TvView.ERROR_TV_INPUT_DISCONNECTED) {
689bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        Log.w(TAG, "Session is released by crash");
699bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        long channelId = mChannelId;
709bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        mChannelId = Channel.INVALID_ID;
719bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        mInputInfo = null;
729bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        if (mOnTuneListener != null) {
739bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                            mOnTuneListener.onUnexpectedStop(channelId);
749bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                            mOnTuneListener = null;
759bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                        }
76900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                    }
77900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                }
78900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
79900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                @Override
809bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                public void onVideoStreamChanged(String inputId, int width, int height,
81fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                        boolean interlaced) {
8221abb13274f379e69c3c86d51e493122cccca345Dongwon Kang                    mVideoFormat = Utils.getVideoDefinitionLevelFromSize(width, height);
8321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang                    if (mOnTuneListener != null) {
8421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang                        mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
8521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang                    }
8621abb13274f379e69c3c86d51e493122cccca345Dongwon Kang                }
87fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang
88fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                @Override
899bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                public void onAudioStreamChanged(String inputId, int channelCount) {
90fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                    mAudioChannelCount = channelCount;
91fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                    if (mOnTuneListener != null) {
92fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                        mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
93fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                    }
94fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                }
95fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang
96fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                @Override
979bb548ba08d7e222f276287fead545c6a11704d8Jae Seo                public void onClosedCaptionStreamChanged(String inputId, boolean hasClosedCaption) {
98fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                    mHasClosedCaption = hasClosedCaption;
99fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                    if (mOnTuneListener != null) {
100fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                        mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
101fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                    }
102fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang                }
103900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            };
104900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
105900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public TunableTvView(Context context) {
106900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        this(context, null, 0);
107900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
108900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
109900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public TunableTvView(Context context, AttributeSet attrs) {
110900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        this(context, attrs, 0);
111900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
112900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
113900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public TunableTvView(Context context, AttributeSet attrs, int defStyleAttr) {
114900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        super(context, attrs, defStyleAttr);
115b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang        for (int i = 0; i < getChildCount(); ++i) {
116b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang            if (getChildAt(i) instanceof SurfaceView) {
117b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang                mSurface = (SurfaceView) getChildAt(i);
118b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang                mSurface.getHolder().addCallback(mSurfaceHolderCallback);
119b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang                return;
120b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang            }
121b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang        }
122b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang        throw new RuntimeException("TvView does not have SurfaceView.");
123900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
124900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
125900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public void start(TvInputManagerHelper tvInputManagerHelper) {
126900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mInputManagerHelper = tvInputManagerHelper;
127900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (mStarted) {
128900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            return;
129900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
130900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mStarted = true;
131900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
132900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
133900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public void stop() {
134900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (!mStarted) {
135900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            return;
136900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
137900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mStarted = false;
1389bb548ba08d7e222f276287fead545c6a11704d8Jae Seo        reset();
139900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mChannelId = Channel.INVALID_ID;
140900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mInputInfo = null;
141900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mOnTuneListener = null;
142900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
143900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
144900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public boolean isPlaying() {
145900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        return mStarted;
146900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
147900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
148900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public boolean tuneTo(long channelId, OnTuneListener listener) {
149900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (!mStarted) {
150900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            throw new IllegalStateException("TvView isn't started");
151900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
152900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (DEBUG) Log.d(TAG, "tuneTo " + channelId);
15321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN;
154e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN;
155e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        mHasClosedCaption = false;
156900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        String inputId = Utils.getInputIdForChannel(getContext(), channelId);
157900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        TvInputInfo inputInfo = mInputManagerHelper.getTvInputInfo(inputId);
158900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (inputInfo == null || !mInputManagerHelper.isAvailable(inputInfo)) {
159900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            return false;
160900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
161900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mOnTuneListener = listener;
162900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mChannelId = channelId;
163900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (!inputInfo.equals(mInputInfo)) {
1649bb548ba08d7e222f276287fead545c6a11704d8Jae Seo            reset();
165900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            // TODO: It is a hack to wait to release a surface at TIS. If there is a way to
166900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            // know when the surface is released at TIS, we don't need this hack.
167900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            try {
168900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                Thread.sleep(DELAY_FOR_SURFACE_RELEASE);
169900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            } catch (InterruptedException e) {
170900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho                e.printStackTrace();
171900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            }
172900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            mInputInfo = inputInfo;
1739bb548ba08d7e222f276287fead545c6a11704d8Jae Seo        }
1749bb548ba08d7e222f276287fead545c6a11704d8Jae Seo        setTvInputListener(mListener);
1759bb548ba08d7e222f276287fead545c6a11704d8Jae Seo        tune(mInputInfo.getId(), Utils.getChannelUri(mChannelId));
1769bb548ba08d7e222f276287fead545c6a11704d8Jae Seo        if (mOnTuneListener != null) {
1779bb548ba08d7e222f276287fead545c6a11704d8Jae Seo            // TODO: Add a callback for tune complete and call onTuned when it was successful.
1789bb548ba08d7e222f276287fead545c6a11704d8Jae Seo            mOnTuneListener.onTuned(true, mChannelId);
179900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
180900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        return true;
181900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
182900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
183900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public TvInputInfo getCurrentTvInputInfo() {
184900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        return mInputInfo;
185900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
186900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
187900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public long getCurrentChannelId() {
188900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        return mChannelId;
189900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
190900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
191b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang    public void setPip(boolean isPip) {
192b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang        mSurface.setZOrderMediaOverlay(isPip);
193b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang    }
194b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang
195561696c364ee330f4316544f1f85498393883526Jae Seo    @Override
196561696c364ee330f4316544f1f85498393883526Jae Seo    public void setStreamVolume(float volume) {
197900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        if (!mStarted) {
198900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho            throw new IllegalStateException("TvView isn't started");
199900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        }
200561696c364ee330f4316544f1f85498393883526Jae Seo        if (DEBUG)
201561696c364ee330f4316544f1f85498393883526Jae Seo            Log.d(TAG, "setStreamVolume " + volume);
202900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        mVolume = volume;
203561696c364ee330f4316544f1f85498393883526Jae Seo        super.setStreamVolume(volume);
204900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
205900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho
206900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    public interface OnTuneListener {
207900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        void onTuned(boolean success, long channelId);
208900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho        void onUnexpectedStop(long channelId);
20921abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        void onStreamInfoChanged(StreamInfo info);
21021abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    }
21121abb13274f379e69c3c86d51e493122cccca345Dongwon Kang
21221abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    @Override
21321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang    public int getVideoDefinitionLevel() {
21421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang        return mVideoFormat;
215900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho    }
216e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang
217e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    @Override
218e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    public int getAudioChannelCount() {
219e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        return mAudioChannelCount;
220e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    }
221e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang
222e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    @Override
223e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    public boolean hasClosedCaption() {
224e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang        return mHasClosedCaption;
225e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang    }
226900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho}
227