11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/* 21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project 31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License. 61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at 71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software 111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and 141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License. 151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner.tvinput; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log; 201abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.SparseArray; 211abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.SparseBooleanArray; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.TunerHal; 2465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.ts.TsParser; 2565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.data.PsiData; 2665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.tuner.data.PsipData; 276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.tuner.data.TunerChannel; 286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.tuner.data.nano.Track.AtscAudioTrack; 296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; 301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList; 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.HashSet; 331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.List; 341abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Set; 351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Detects channels and programs that are emerged or changed while parsing ATSC PSIP information. 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 391abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class EventDetector { 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final String TAG = "EventDetector"; 411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private static final boolean DEBUG = false; 4265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public static final int ALL_PROGRAM_NUMBERS = -1; 431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 44ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final TunerHal mTunerHal; 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private TsParser mTsParser; 471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final Set<Integer> mPidSet = new HashSet<>(); 481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // To prevent channel duplication 501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final Set<Integer> mVctProgramNumberSet = new HashSet<>(); 516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private final Set<Integer> mSdtProgramNumberSet = new HashSet<>(); 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final SparseArray<TunerChannel> mChannelMap = new SparseArray<>(); 531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final SparseBooleanArray mVctCaptionTracksFound = new SparseBooleanArray(); 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final SparseBooleanArray mEitCaptionTracksFound = new SparseBooleanArray(); 556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private final List<EventListener> mEventListeners = new ArrayList<>(); 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private int mFrequency; 571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private String mModulation; 5865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private int mProgramNumber = ALL_PROGRAM_NUMBERS; 591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 6065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final TsParser.TsOutputListener mTsOutputListener = new TsParser.TsOutputListener() { 611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 6265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onPatDetected(List<PsiData.PatItem> items) { 6365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (PsiData.PatItem i : items) { 64d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko if (mProgramNumber == ALL_PROGRAM_NUMBERS || mProgramNumber == i.getProgramNo()) { 6565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mTunerHal.addPidFilter(i.getPmtPid(), TunerHal.FILTER_TYPE_OTHER); 6665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void onEitPidDetected(int pid) { 721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko startListening(pid); 731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 7665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onEitItemParsed(PsipData.VctItem channel, List<PsipData.EitItem> items) { 771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko TunerChannel tunerChannel = mChannelMap.get(channel.getProgramNumber()); 781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) { 791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, "onEitItemParsed tunerChannel:" + tunerChannel + " " 801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko + channel.getProgramNumber()); 811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int channelSourceId = channel.getSourceId(); 831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Source id 0 is useful for cases where a cable operator wishes to define a channel for 851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // which no EPG data is currently available. 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // We don't handle such a case. 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (channelSourceId == 0) { 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // If at least a one caption track have been found in EIT items for the given channel, 921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // we starts to interpret the zero tracks as a clearance of the caption tracks. 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko boolean captionTracksFound = mEitCaptionTracksFound.get(channelSourceId); 9465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (PsipData.EitItem item : items) { 951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (captionTracksFound) { 961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko break; 971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko List<AtscCaptionTrack> captionTracks = item.getCaptionTracks(); 991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (captionTracks != null && !captionTracks.isEmpty()) { 1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko captionTracksFound = true; 1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mEitCaptionTracksFound.put(channelSourceId, captionTracksFound); 1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (captionTracksFound) { 10565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (PsipData.EitItem item : items) { 1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko item.setHasCaptionTrack(); 1071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (tunerChannel != null && !mEventListeners.isEmpty()) { 1106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (EventListener eventListener : mEventListeners) { 1116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko eventListener.onEventDetected(tunerChannel, items); 1126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void onEttPidDetected(int pid) { 1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko startListening(pid); 1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 12265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onAllVctItemsParsed() { 1236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!mEventListeners.isEmpty()) { 1246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (EventListener eventListener : mEventListeners) { 1256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko eventListener.onChannelScanDone(); 1266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 12765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 12865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 12965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 13065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Override 13165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onVctItemParsed(PsipData.VctItem channel, List<PsiData.PmtItem> pmtItems) { 1321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (DEBUG) { 1331abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, "onVctItemParsed VCT " + channel); 1341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko Log.d(TAG, " PMT " + pmtItems); 1351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // Merges the audio and caption tracks located in PMT items into the tracks of the given 1381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // tuner channel. 1391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko TunerChannel tunerChannel = new TunerChannel(channel, pmtItems); 1401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko List<AtscAudioTrack> audioTracks = new ArrayList<>(); 1411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko List<AtscCaptionTrack> captionTracks = new ArrayList<>(); 14265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (PsiData.PmtItem pmtItem : pmtItems) { 1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (pmtItem.getAudioTracks() != null) { 1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko audioTracks.addAll(pmtItem.getAudioTracks()); 1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (pmtItem.getCaptionTracks() != null) { 1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko captionTracks.addAll(pmtItem.getCaptionTracks()); 1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int channelProgramNumber = channel.getProgramNumber(); 1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // If at least a one caption track have been found in VCT items for the given channel, 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // we starts to interpret the zero tracks as a clearance of the caption tracks. 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko boolean captionTracksFound = mVctCaptionTracksFound.get(channelProgramNumber) 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko || !captionTracks.isEmpty(); 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mVctCaptionTracksFound.put(channelProgramNumber, captionTracksFound); 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (captionTracksFound) { 1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko tunerChannel.setHasCaptionTrack(); 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko tunerChannel.setAudioTracks(audioTracks); 1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko tunerChannel.setCaptionTracks(captionTracks); 1621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko tunerChannel.setFrequency(mFrequency); 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko tunerChannel.setModulation(mModulation); 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelMap.put(tunerChannel.getProgramNumber(), tunerChannel); 1651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko boolean found = mVctProgramNumberSet.contains(channelProgramNumber); 1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!found) { 1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mVctProgramNumberSet.add(channelProgramNumber); 1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!mEventListeners.isEmpty()) { 1706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (EventListener eventListener : mEventListeners) { 1716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko eventListener.onChannelDetected(tunerChannel, !found); 1726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 1766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko @Override 1776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void onSdtItemParsed(PsipData.SdtItem channel, List<PsiData.PmtItem> pmtItems) { 1786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (DEBUG) { 1796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Log.d(TAG, "onSdtItemParsed SDT " + channel); 1806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Log.d(TAG, " PMT " + pmtItems); 1816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 1836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // Merges the audio and caption tracks located in PMT items into the tracks of the given 1846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // tuner channel. 1856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko TunerChannel tunerChannel = new TunerChannel(channel, pmtItems); 1866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko List<AtscAudioTrack> audioTracks = new ArrayList<>(); 1876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko List<AtscCaptionTrack> captionTracks = new ArrayList<>(); 1886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (PsiData.PmtItem pmtItem : pmtItems) { 1896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (pmtItem.getAudioTracks() != null) { 1906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko audioTracks.addAll(pmtItem.getAudioTracks()); 1916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (pmtItem.getCaptionTracks() != null) { 1936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko captionTracks.addAll(pmtItem.getCaptionTracks()); 1946ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int channelProgramNumber = channel.getServiceId(); 1976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tunerChannel.setAudioTracks(audioTracks); 1986ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tunerChannel.setCaptionTracks(captionTracks); 1996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tunerChannel.setFrequency(mFrequency); 2006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko tunerChannel.setModulation(mModulation); 2016ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mChannelMap.put(tunerChannel.getProgramNumber(), tunerChannel); 2026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko boolean found = mSdtProgramNumberSet.contains(channelProgramNumber); 2036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!found) { 2046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mSdtProgramNumberSet.add(channelProgramNumber); 2056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2066ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!mEventListeners.isEmpty()) { 2076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko for (EventListener eventListener : mEventListeners) { 2086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko eventListener.onChannelDetected(tunerChannel, !found); 2096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 2101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }; 2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Listener for detecting ATSC TV channels and receiving EPG data. 2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 2171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public interface EventListener { 2181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 2201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Fired when new information of an ATSC TV channel arrived. 2211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 2221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param channel an ATSC TV channel 2231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param channelArrivedAtFirstTime tells whether this channel arrived at first time 2241abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 2251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime); 2261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 2281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Fired when new program events of an ATSC TV channel arrived. 2291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 2301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param channel an ATSC TV channel 2311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * @param items a list of EIT items that were received 2321abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 23365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko void onEventDetected(TunerChannel channel, List<PsipData.EitItem> items); 23465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 23565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko /** 23665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Fired when information of all detectable ATSC TV channels in current frequency arrived. 23765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */ 23865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko void onChannelScanDone(); 2391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 24165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko /** 24265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Creates a detector for ATSC TV channles and program information. 2436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * 24465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param usbTunerInteface {@link TunerHal} 24565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */ 2466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public EventDetector(TunerHal usbTunerInteface) { 247ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mTunerHal = usbTunerInteface; 2481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void reset() { 2516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // TODO: Use TsParser.reset() 2526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko int deliverySystemType = mTunerHal.getDeliverySystemType(); 2536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTsParser = 2546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko new TsParser( 2556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTsOutputListener, 2566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko TunerHal.isDvbDeliverySystem(mTunerHal.getDeliverySystemType())); 2571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mPidSet.clear(); 2581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mVctProgramNumberSet.clear(); 2596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mSdtProgramNumberSet.clear(); 2601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mVctCaptionTracksFound.clear(); 2611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mEitCaptionTracksFound.clear(); 2621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mChannelMap.clear(); 2631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 26565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko /** 26665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Starts detecting channel and program information. 26765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * 26865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param frequency The frequency to listen to. 26965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param modulation The modulation type. 27065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param programNumber The program number if this is for handling tune request. For scanning 27165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * purpose, supply {@link #ALL_PROGRAM_NUMBERS}. 27265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */ 27365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void startDetecting(int frequency, String modulation, int programNumber) { 2741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko reset(); 2751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mFrequency = frequency; 2761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mModulation = modulation; 27765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mProgramNumber = programNumber; 2781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private void startListening(int pid) { 2811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mPidSet.contains(pid)) { 2821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 2831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mPidSet.add(pid); 285ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko mTunerHal.addPidFilter(pid, TunerHal.FILTER_TYPE_OTHER); 2861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 28865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko /** 28965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Feeds ATSC TS stream to detect channel and program information. 29065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param data buffer for ATSC TS stream 29165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param startOffset the offset where buffer starts 29265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @param length The length of available data 29365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */ 2941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void feedTSStream(byte[] data, int startOffset, int length) { 2951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mPidSet.isEmpty()) { 2961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko startListening(TsParser.ATSC_SI_BASE_PID); 2971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mTsParser != null) { 2991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mTsParser.feedTSData(data, startOffset, length); 3001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 30365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko /** 30465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * Retrieves the channel information regardless of being well-formed. 30565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko * @return {@link List} of {@link TunerChannel} 30665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko */ 30765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public List<TunerChannel> getMalFormedChannels() { 30865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return mTsParser.getMalFormedChannels(); 3091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 3106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 3116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 3126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Registers an EventListener. 3136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * @param eventListener the listener to be registered 3146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 3156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void registerListener(EventListener eventListener) { 3166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (mTsParser != null) { 3176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // Resets the version numbers so that the new listener can receive the EIT items. 3186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // Otherwise, each EIT session is handled only once unless there is a new version. 3196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mTsParser.resetDataVersions(); 3206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mEventListeners.add(eventListener); 3226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko 3246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko /** 3256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Unregisters an EventListener. 3266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * @param eventListener the listener to be unregistered 3276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */ 3286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void unregisterListener(EventListener eventListener) { 3296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko boolean removed = mEventListeners.remove(eventListener); 3306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (!removed && DEBUG) { 3316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko Log.d(TAG, "Cannot unregister a non-registered listener!"); 3326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 3341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 335