TunableTvView.java revision 8f1ff2894363afbb6909a3a1edc1f3cbe8657c11
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; 28e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim private int mVideoWidth; 29e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim private int mVideoHeight; 3021abb13274f379e69c3c86d51e493122cccca345Dongwon Kang private int mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN; 31e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang private int mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN; 32e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang private boolean mHasClosedCaption = false; 33b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang private SurfaceView mSurface; 34900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 35900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { 36900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho @Override 37900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } 38900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 39900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho @Override 40900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public void surfaceCreated(SurfaceHolder holder) { } 41900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 42900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho @Override 43900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public void surfaceDestroyed(SurfaceHolder holder) { 44900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho // TODO: It is a hack to wait to release a surface at TIS. If there is a way to 45900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho // know when the surface is released at TIS, we don't need this hack. 46900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho try { 47900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (DEBUG) Log.d(TAG, "Sleep to wait destroying a surface"); 48900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho Thread.sleep(DELAY_FOR_SURFACE_RELEASE); 49900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (DEBUG) Log.d(TAG, "Wake up from sleeping"); 50900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } catch (InterruptedException e) { 51900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho e.printStackTrace(); 52900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 53900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 54900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho }; 55900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 569bb548ba08d7e222f276287fead545c6a11704d8Jae Seo private final TvInputListener mListener = 579bb548ba08d7e222f276287fead545c6a11704d8Jae Seo new TvInputListener() { 58900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho @Override 599bb548ba08d7e222f276287fead545c6a11704d8Jae Seo public void onError(String inputId, int errorCode) { 609bb548ba08d7e222f276287fead545c6a11704d8Jae Seo if (errorCode == TvView.ERROR_BUSY) { 619bb548ba08d7e222f276287fead545c6a11704d8Jae Seo Log.w(TAG, "Failed to bind an input"); 62900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho long channelId = mChannelId; 63900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mChannelId = Channel.INVALID_ID; 64900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mInputInfo = null; 65900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (mOnTuneListener != null) { 66900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mOnTuneListener.onTuned(false, channelId); 67900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mOnTuneListener = null; 68900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 699bb548ba08d7e222f276287fead545c6a11704d8Jae Seo } else if (errorCode == TvView.ERROR_TV_INPUT_DISCONNECTED) { 709bb548ba08d7e222f276287fead545c6a11704d8Jae Seo Log.w(TAG, "Session is released by crash"); 719bb548ba08d7e222f276287fead545c6a11704d8Jae Seo long channelId = mChannelId; 729bb548ba08d7e222f276287fead545c6a11704d8Jae Seo mChannelId = Channel.INVALID_ID; 739bb548ba08d7e222f276287fead545c6a11704d8Jae Seo mInputInfo = null; 749bb548ba08d7e222f276287fead545c6a11704d8Jae Seo if (mOnTuneListener != null) { 759bb548ba08d7e222f276287fead545c6a11704d8Jae Seo mOnTuneListener.onUnexpectedStop(channelId); 769bb548ba08d7e222f276287fead545c6a11704d8Jae Seo mOnTuneListener = null; 779bb548ba08d7e222f276287fead545c6a11704d8Jae Seo } 78900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 79900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 80900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 81900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho @Override 829bb548ba08d7e222f276287fead545c6a11704d8Jae Seo public void onVideoStreamChanged(String inputId, int width, int height, 83fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang boolean interlaced) { 848f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo if (DEBUG) { 858f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo Log.d(TAG, "onVideoStreamChanged(inputId=" + inputId + ", width=" + width 868f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo + ", height=" + height + ")"); 878f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo } 88e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim mVideoWidth = width; 89e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim mVideoHeight = height; 9021abb13274f379e69c3c86d51e493122cccca345Dongwon Kang mVideoFormat = Utils.getVideoDefinitionLevelFromSize(width, height); 918f1ff2894363afbb6909a3a1edc1f3cbe8657c11Jae Seo Utils.updateCurrentVideoResolution(getContext(), mChannelId, mVideoFormat); 9221abb13274f379e69c3c86d51e493122cccca345Dongwon Kang if (mOnTuneListener != null) { 9321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang mOnTuneListener.onStreamInfoChanged(TunableTvView.this); 9421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang } 9521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang } 96fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang 97fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang @Override 989bb548ba08d7e222f276287fead545c6a11704d8Jae Seo public void onAudioStreamChanged(String inputId, int channelCount) { 99fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang mAudioChannelCount = channelCount; 100fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang if (mOnTuneListener != null) { 101fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang mOnTuneListener.onStreamInfoChanged(TunableTvView.this); 102fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang } 103fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang } 104fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang 105fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang @Override 1069bb548ba08d7e222f276287fead545c6a11704d8Jae Seo public void onClosedCaptionStreamChanged(String inputId, boolean hasClosedCaption) { 107fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang mHasClosedCaption = hasClosedCaption; 108fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang if (mOnTuneListener != null) { 109fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang mOnTuneListener.onStreamInfoChanged(TunableTvView.this); 110fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang } 111fc4ae3d84120d40af0d1ce5da7b0b1e40003e9aaDongwon Kang } 112900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho }; 113900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 114900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public TunableTvView(Context context) { 115900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho this(context, null, 0); 116900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 117900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 118900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public TunableTvView(Context context, AttributeSet attrs) { 119900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho this(context, attrs, 0); 120900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 121900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 122900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public TunableTvView(Context context, AttributeSet attrs, int defStyleAttr) { 123900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho super(context, attrs, defStyleAttr); 124b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang for (int i = 0; i < getChildCount(); ++i) { 125b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang if (getChildAt(i) instanceof SurfaceView) { 126b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang mSurface = (SurfaceView) getChildAt(i); 127b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang mSurface.getHolder().addCallback(mSurfaceHolderCallback); 128b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang return; 129b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang } 130b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang } 131b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang throw new RuntimeException("TvView does not have SurfaceView."); 132900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 133900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 134900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public void start(TvInputManagerHelper tvInputManagerHelper) { 135900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mInputManagerHelper = tvInputManagerHelper; 136900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (mStarted) { 137900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return; 138900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 139900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mStarted = true; 140900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 141900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 142900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public void stop() { 143900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (!mStarted) { 144900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return; 145900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 146900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mStarted = false; 1479bb548ba08d7e222f276287fead545c6a11704d8Jae Seo reset(); 148900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mChannelId = Channel.INVALID_ID; 149900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mInputInfo = null; 150900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mOnTuneListener = null; 151900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 152900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 153900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public boolean isPlaying() { 154900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return mStarted; 155900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 156900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 157900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public boolean tuneTo(long channelId, OnTuneListener listener) { 158900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (!mStarted) { 159900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho throw new IllegalStateException("TvView isn't started"); 160900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 161900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (DEBUG) Log.d(TAG, "tuneTo " + channelId); 162e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim mVideoWidth = 0; 163e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim mVideoHeight = 0; 16421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN; 165e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN; 166e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang mHasClosedCaption = false; 167900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho String inputId = Utils.getInputIdForChannel(getContext(), channelId); 168900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho TvInputInfo inputInfo = mInputManagerHelper.getTvInputInfo(inputId); 169900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (inputInfo == null || !mInputManagerHelper.isAvailable(inputInfo)) { 170900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return false; 171900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 172900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mOnTuneListener = listener; 173900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mChannelId = channelId; 174900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (!inputInfo.equals(mInputInfo)) { 1759bb548ba08d7e222f276287fead545c6a11704d8Jae Seo reset(); 176900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho // TODO: It is a hack to wait to release a surface at TIS. If there is a way to 177900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho // know when the surface is released at TIS, we don't need this hack. 178900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho try { 179900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho Thread.sleep(DELAY_FOR_SURFACE_RELEASE); 180900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } catch (InterruptedException e) { 181900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho e.printStackTrace(); 182900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 183900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mInputInfo = inputInfo; 1849bb548ba08d7e222f276287fead545c6a11704d8Jae Seo } 1859bb548ba08d7e222f276287fead545c6a11704d8Jae Seo setTvInputListener(mListener); 1869bb548ba08d7e222f276287fead545c6a11704d8Jae Seo tune(mInputInfo.getId(), Utils.getChannelUri(mChannelId)); 1879bb548ba08d7e222f276287fead545c6a11704d8Jae Seo if (mOnTuneListener != null) { 1889bb548ba08d7e222f276287fead545c6a11704d8Jae Seo // TODO: Add a callback for tune complete and call onTuned when it was successful. 1899bb548ba08d7e222f276287fead545c6a11704d8Jae Seo mOnTuneListener.onTuned(true, mChannelId); 190900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 191900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return true; 192900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 193900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 19487c1cbb508c96538d1e69ba1fdf3d9f4d52710d6Jaewan Kim @Override 195900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public TvInputInfo getCurrentTvInputInfo() { 196900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return mInputInfo; 197900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 198900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 199900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public long getCurrentChannelId() { 200900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho return mChannelId; 201900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 202900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 203b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang public void setPip(boolean isPip) { 204b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang mSurface.setZOrderMediaOverlay(isPip); 205b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang } 206b47a0ad3227b940175fa4ecfe5c4113da72c8237Dongwon Kang 207561696c364ee330f4316544f1f85498393883526Jae Seo @Override 208561696c364ee330f4316544f1f85498393883526Jae Seo public void setStreamVolume(float volume) { 209900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho if (!mStarted) { 210900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho throw new IllegalStateException("TvView isn't started"); 211900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 212561696c364ee330f4316544f1f85498393883526Jae Seo if (DEBUG) 213561696c364ee330f4316544f1f85498393883526Jae Seo Log.d(TAG, "setStreamVolume " + volume); 214900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho mVolume = volume; 215561696c364ee330f4316544f1f85498393883526Jae Seo super.setStreamVolume(volume); 216900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 217900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho 218900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho public interface OnTuneListener { 219900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho void onTuned(boolean success, long channelId); 220900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho void onUnexpectedStop(long channelId); 22121abb13274f379e69c3c86d51e493122cccca345Dongwon Kang void onStreamInfoChanged(StreamInfo info); 22221abb13274f379e69c3c86d51e493122cccca345Dongwon Kang } 22321abb13274f379e69c3c86d51e493122cccca345Dongwon Kang 22421abb13274f379e69c3c86d51e493122cccca345Dongwon Kang @Override 225e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim public int getVideoWidth() { 226e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim return mVideoWidth; 227e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim } 228e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim 229e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim @Override 230e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim public int getVideoHeight() { 231e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim return mVideoHeight; 232e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim } 233e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim 234e06ded45d6e3b83e1a325e97ccd168c6d1c0d2deJaewan Kim @Override 23521abb13274f379e69c3c86d51e493122cccca345Dongwon Kang public int getVideoDefinitionLevel() { 23621abb13274f379e69c3c86d51e493122cccca345Dongwon Kang return mVideoFormat; 237900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho } 238e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang 239e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang @Override 240e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang public int getAudioChannelCount() { 241e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang return mAudioChannelCount; 242e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang } 243e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang 244e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang @Override 245e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang public boolean hasClosedCaption() { 246e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang return mHasClosedCaption; 247e51a084c2518f17cee43c86e2f9df907d1f2cafbDongwon Kang } 248900cc7509f1edf86db9ba1e4b71b7d1096769a0aYoungsang Cho} 249