aboutsummaryrefslogtreecommitdiff
path: root/tuner/src/com/android/tv/tuner
diff options
context:
space:
mode:
Diffstat (limited to 'tuner/src/com/android/tv/tuner')
-rw-r--r--tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java (renamed from tuner/src/com/android/tv/tuner/dvb/DvbDeviceAccessor.java)2
-rw-r--r--tuner/src/com/android/tv/tuner/DvbTunerHal.java (renamed from tuner/src/com/android/tv/tuner/dvb/DvbTunerHal.java)5
-rw-r--r--tuner/src/com/android/tv/tuner/TunerHal.java85
-rw-r--r--tuner/src/com/android/tv/tuner/api/ScanChannel.java47
-rw-r--r--tuner/src/com/android/tv/tuner/api/Tuner.java15
-rw-r--r--tuner/src/com/android/tv/tuner/builtin/BuiltInTunerHalFactory.java (renamed from tuner/src/com/android/tv/tuner/dvb/DvbTunerHalFactory.java)37
-rw-r--r--tuner/src/com/android/tv/tuner/cc/CaptionLayout.java2
-rw-r--r--tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java4
-rw-r--r--tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java6
-rw-r--r--tuner/src/com/android/tv/tuner/data/Cea708Parser.java18
-rw-r--r--tuner/src/com/android/tv/tuner/data/PsiData.java4
-rw-r--r--tuner/src/com/android/tv/tuner/data/PsipData.java14
-rw-r--r--tuner/src/com/android/tv/tuner/data/SectionParser.java94
-rw-r--r--tuner/src/com/android/tv/tuner/data/TunerChannel.java342
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java129
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java27
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java7
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java40
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java49
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java3
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java9
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java5
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java40
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java67
-rw-r--r--tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java25
-rw-r--r--tuner/src/com/android/tv/tuner/features/TunerFeatures.java9
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java206
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java226
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java177
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java446
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java134
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.java250
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java62
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java122
-rw-r--r--tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java194
-rw-r--r--tuner/src/com/android/tv/tuner/modules/TunerModule.java79
-rw-r--r--tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java12
-rw-r--r--tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java1
-rw-r--r--tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java7
-rw-r--r--tuner/src/com/android/tv/tuner/setup/LineupFragment.java4
-rw-r--r--tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java119
-rw-r--r--tuner/src/com/android/tv/tuner/setup/LocationFragment.java18
-rw-r--r--tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java6
-rw-r--r--tuner/src/com/android/tv/tuner/setup/ScanFragment.java90
-rw-r--r--tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java4
-rw-r--r--tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java4
-rw-r--r--tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java15
-rw-r--r--tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java4
-rw-r--r--tuner/src/com/android/tv/tuner/source/FileTsStreamer.java25
-rw-r--r--tuner/src/com/android/tv/tuner/source/TsDataSource.java2
-rw-r--r--tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java2
-rw-r--r--tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java43
-rw-r--r--tuner/src/com/android/tv/tuner/ts/EventDetector.java22
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java78
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java49
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java126
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerSession.java28
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java28
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java10
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java165
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java156
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java15
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java41
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java34
-rw-r--r--tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java49
65 files changed, 871 insertions, 3267 deletions
diff --git a/tuner/src/com/android/tv/tuner/dvb/DvbDeviceAccessor.java b/tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java
index 8be27c91..217433d2 100644
--- a/tuner/src/com/android/tv/tuner/dvb/DvbDeviceAccessor.java
+++ b/tuner/src/com/android/tv/tuner/DvbDeviceAccessor.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.tuner.dvb;
+package com.android.tv.tuner;
import android.content.Context;
import android.media.tv.TvInputManager;
diff --git a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHal.java b/tuner/src/com/android/tv/tuner/DvbTunerHal.java
index 7f68e379..c802ebbb 100644
--- a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHal.java
+++ b/tuner/src/com/android/tv/tuner/DvbTunerHal.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.tv.tuner.dvb;
+package com.android.tv.tuner;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import com.android.tv.common.compat.TvInputConstantCompat;
-import com.android.tv.tuner.TunerHal;
-import com.android.tv.tuner.dvb.DvbDeviceAccessor.DvbDeviceInfoWrapper;
+import com.android.tv.tuner.DvbDeviceAccessor.DvbDeviceInfoWrapper;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
diff --git a/tuner/src/com/android/tv/tuner/TunerHal.java b/tuner/src/com/android/tv/tuner/TunerHal.java
index 3f469d60..dce4f4c4 100644
--- a/tuner/src/com/android/tv/tuner/TunerHal.java
+++ b/tuner/src/com/android/tv/tuner/TunerHal.java
@@ -36,7 +36,6 @@ public abstract class TunerHal implements Tuner {
private static final int DEFAULT_QAM_TUNE_TIMEOUT_MS = 4000; // Some device takes time for
@DeliverySystemType private int mDeliverySystemType;
- @DeliverySystemType private int[] mDeliverySystemTypes;
private boolean mIsStreaming;
private int mFrequency;
private String mModulation;
@@ -58,16 +57,9 @@ public abstract class TunerHal implements Tuner {
}
protected void getDeliverySystemTypeFromDevice() {
- getDeliverySystemTypesFromDevice();
- }
-
- protected void getDeliverySystemTypesFromDevice() {
if (mDeliverySystemType == DELIVERY_SYSTEM_UNDEFINED) {
mDeliverySystemType = nativeGetDeliverySystemType(getDeviceId());
}
- if (mDeliverySystemTypes == null) {
- mDeliverySystemTypes = nativeGetDeliverySystemTypes(getDeviceId());
- }
}
/**
@@ -87,34 +79,18 @@ public abstract class TunerHal implements Tuner {
protected native void nativeFinalize(long deviceId);
- @Override
- public synchronized boolean tune(
- int frequency, @ModulationType String modulation,
- String channelNumber) {
- return tuneInternal(mDeliverySystemType, frequency, modulation, channelNumber);
- }
-
- @Override
- public synchronized boolean tune(
- int deliverySystemType, int frequency, @ModulationType String modulation,
- String channelNumber) {
- return tuneInternal(deliverySystemType, frequency, modulation, channelNumber);
- }
-
/**
* Sets the tuner channel. This should be called after acquiring a tuner device.
*
- * @param deliverySystemType a system delivery type of the channel to tune to
* @param frequency a frequency of the channel to tune to
* @param modulation a modulation method of the channel to tune to
* @param channelNumber channel number when channel number is already known. Some tuner HAL may
* use channelNumber instead of frequency for tune.
* @return {@code true} if the operation was successful, {@code false} otherwise
*/
- protected boolean tuneInternal(
- int deliverySystemType, int frequency, @ModulationType String modulation,
- String channelNumber) {
-
+ @Override
+ public synchronized boolean tune(
+ int frequency, @ModulationType String modulation, String channelNumber) {
if (!isDeviceOpen()) {
Log.e(TAG, "There's no available device");
return false;
@@ -123,76 +99,40 @@ public abstract class TunerHal implements Tuner {
nativeCloseAllPidFilters(getDeviceId());
mIsStreaming = false;
}
- if (mDeliverySystemTypes != null) {
- int i;
- for (i = 0; i < mDeliverySystemTypes.length; i++) {
- if (deliverySystemType == mDeliverySystemTypes[i]) {
- break;
- }
- }
-
- if (i == mDeliverySystemTypes.length) {
- Log.e(TAG, "Unsupported delivery system type for device");
- return false;
- }
- }
// When tuning to a new channel in the same frequency, there's no need to stop current tuner
// device completely and the only thing necessary for tuning is reopening pid filters.
if (mFrequency == frequency && Objects.equals(mModulation, modulation)) {
addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
- if (Tuner.isDvbDeliverySystem(deliverySystemType)) {
+ if (Tuner.isDvbDeliverySystem(mDeliverySystemType)) {
addPidFilter(PID_DVB_SDT, FILTER_TYPE_OTHER);
addPidFilter(PID_DVB_EIT, FILTER_TYPE_OTHER);
}
mIsStreaming = true;
return true;
}
-
int timeout_ms =
modulation.equals(MODULATION_8VSB)
? DEFAULT_VSB_TUNE_TIMEOUT_MS
: DEFAULT_QAM_TUNE_TIMEOUT_MS;
-
- boolean tuneStatus;
- switch(deliverySystemType) {
- case DELIVERY_SYSTEM_UNDEFINED:
- case DELIVERY_SYSTEM_ATSC:
- tuneStatus = nativeTune(getDeviceId(), frequency, modulation, timeout_ms);
- break;
- case DELIVERY_SYSTEM_DVBT:
- case DELIVERY_SYSTEM_DVBT2:
- tuneStatus = nativeTune(getDeviceId(), deliverySystemType, frequency, modulation,
- timeout_ms);
- break;
- default:
- Log.e(TAG, "Unsupported delivery system type for device");
- return false;
- }
-
- if (tuneStatus == true) {
+ if (nativeTune(getDeviceId(), frequency, modulation, timeout_ms)) {
addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
- if (Tuner.isDvbDeliverySystem(deliverySystemType)) {
+ if (Tuner.isDvbDeliverySystem(mDeliverySystemType)) {
addPidFilter(PID_DVB_SDT, FILTER_TYPE_OTHER);
addPidFilter(PID_DVB_EIT, FILTER_TYPE_OTHER);
}
mFrequency = frequency;
mModulation = modulation;
mIsStreaming = true;
+ return true;
}
-
- return tuneStatus;
+ return false;
}
protected native boolean nativeTune(
- long deviceId, int frequency,
- @ModulationType String modulation, int timeout_ms);
-
- protected native boolean nativeTune(
- long deviceId, int deliverySystemType, int frequency,
- @ModulationType String modulation, int timeout_ms);
+ long deviceId, int frequency, @ModulationType String modulation, int timeout_ms);
/**
* Sets a pid filter. This should be set after setting a channel.
@@ -222,8 +162,6 @@ public abstract class TunerHal implements Tuner {
protected native int nativeGetDeliverySystemType(long deviceId);
- protected native int[] nativeGetDeliverySystemTypes(long deviceId);
-
protected native int nativeGetSignalStrength(long deviceId);
/**
@@ -253,11 +191,6 @@ public abstract class TunerHal implements Tuner {
return mDeliverySystemType;
}
- @Override
- public int[] getDeliverySystemTypes() {
- return mDeliverySystemTypes;
- }
-
protected native void nativeStopTune(long deviceId);
/**
diff --git a/tuner/src/com/android/tv/tuner/api/ScanChannel.java b/tuner/src/com/android/tv/tuner/api/ScanChannel.java
index 1c7a6e79..56e5493c 100644
--- a/tuner/src/com/android/tv/tuner/api/ScanChannel.java
+++ b/tuner/src/com/android/tv/tuner/api/ScanChannel.java
@@ -15,15 +15,11 @@
*/
package com.android.tv.tuner.api;
-import android.util.Log;
-import com.android.tv.tuner.data.Channel;
-
+import com.android.tv.tuner.data.nano.Channel;
/** Channel information gathered from a <em>scan</em> */
public final class ScanChannel {
- private static final String TAG = "ScanChannel";
public final int type;
- public final Channel.DeliverySystemType deliverySystemType;
public final int frequency;
public final String modulation;
public final String filename;
@@ -35,60 +31,25 @@ public final class ScanChannel {
public final Integer radioFrequencyNumber;
public static ScanChannel forTuner(
- String deliverySystemType, int frequency, String modulation,
- Integer radioFrequencyNumber) {
+ int frequency, String modulation, Integer radioFrequencyNumber) {
return new ScanChannel(
- Channel.TunerType.TYPE_TUNER_VALUE, lookupDeliveryStringToInt(deliverySystemType),
- frequency, modulation, null, radioFrequencyNumber);
+ Channel.TunerType.TYPE_TUNER, frequency, modulation, null, radioFrequencyNumber);
}
public static ScanChannel forFile(int frequency, String filename) {
- return new ScanChannel(Channel.TunerType.TYPE_FILE_VALUE,
- Channel.DeliverySystemType.DELIVERY_SYSTEM_UNDEFINED, frequency, "file:",
- filename, null);
+ return new ScanChannel(Channel.TunerType.TYPE_FILE, frequency, "file:", filename, null);
}
private ScanChannel(
int type,
- Channel.DeliverySystemType deliverySystemType,
int frequency,
String modulation,
String filename,
Integer radioFrequencyNumber) {
this.type = type;
- this.deliverySystemType = deliverySystemType;
this.frequency = frequency;
this.modulation = modulation;
this.filename = filename;
this.radioFrequencyNumber = radioFrequencyNumber;
}
-
- private static Channel.DeliverySystemType lookupDeliveryStringToInt(String deliverySystemType) {
- Channel.DeliverySystemType ret;
- switch (deliverySystemType) {
- case "A":
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_ATSC;
- break;
- case "C":
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBC;
- break;
- case "S":
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBS;
- break;
- case "S2":
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBS2;
- break;
- case "T":
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBT;
- break;
- case "T2":
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_DVBT2;
- break;
- default:
- Log.e(TAG, "Unknown delivery system type");
- ret = Channel.DeliverySystemType.DELIVERY_SYSTEM_UNDEFINED;
- break;
- }
- return ret;
- }
}
diff --git a/tuner/src/com/android/tv/tuner/api/Tuner.java b/tuner/src/com/android/tv/tuner/api/Tuner.java
index 02df3ca1..6f7e9d94 100644
--- a/tuner/src/com/android/tv/tuner/api/Tuner.java
+++ b/tuner/src/com/android/tv/tuner/api/Tuner.java
@@ -28,8 +28,6 @@ public interface Tuner extends AutoCloseable {
int FILTER_TYPE_VIDEO = 2;
int FILTER_TYPE_PCR = 3;
String MODULATION_8VSB = "8VSB";
- String MODULATION_QAM16 = "QAM16";
- String MODULATION_QAM64 = "QAM64";
String MODULATION_QAM256 = "QAM256";
int DELIVERY_SYSTEM_UNDEFINED = 0;
int DELIVERY_SYSTEM_ATSC = 1;
@@ -42,7 +40,6 @@ public interface Tuner extends AutoCloseable {
int TUNER_TYPE_USB = 2;
int TUNER_TYPE_NETWORK = 3;
int BUILT_IN_TUNER_TYPE_LINUX_DVB = 1;
- int BUILT_IN_TUNER_TYPE_ARCHER = 100;
/** Check a delivery system is for DVB or not. */
static boolean isDvbDeliverySystem(@DeliverySystemType int deliverySystemType) {
@@ -69,11 +66,6 @@ public interface Tuner extends AutoCloseable {
boolean tune(int frequency, @ModulationType String modulation, String channelNumber);
- default boolean tune(@DeliverySystemType int deliverySystemType, int frequency,
- @ModulationType String modulation, String channelNumber) {
- return tune(frequency, modulation, channelNumber);
- }
-
boolean addPidFilter(int pid, @FilterType int filterType);
void stopTune();
@@ -81,10 +73,6 @@ public interface Tuner extends AutoCloseable {
void setHasPendingTune(boolean hasPendingTune);
int getDeliverySystemType();
- default int[] getDeliverySystemTypes() {
- int[] deliverySystemTypes = {DELIVERY_SYSTEM_UNDEFINED};
- return deliverySystemTypes;
- };
int readTsStream(byte[] javaBuffer, int javaBufferSize);
@@ -96,7 +84,7 @@ public interface Tuner extends AutoCloseable {
public @interface FilterType {}
/** Modulation Type */
- @StringDef({MODULATION_8VSB, MODULATION_QAM256, MODULATION_QAM16, MODULATION_QAM64})
+ @StringDef({MODULATION_8VSB, MODULATION_QAM256})
@Retention(RetentionPolicy.SOURCE)
public @interface ModulationType {}
@@ -120,7 +108,6 @@ public interface Tuner extends AutoCloseable {
/** Built in tuner type */
@IntDef({
- BUILT_IN_TUNER_TYPE_ARCHER,
BUILT_IN_TUNER_TYPE_LINUX_DVB
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHalFactory.java b/tuner/src/com/android/tv/tuner/builtin/BuiltInTunerHalFactory.java
index 24d7e1fc..9a0be740 100644
--- a/tuner/src/com/android/tv/tuner/dvb/DvbTunerHalFactory.java
+++ b/tuner/src/com/android/tv/tuner/builtin/BuiltInTunerHalFactory.java
@@ -14,29 +14,39 @@
* limitations under the License.
*/
-package com.android.tv.tuner.dvb;
+package com.android.tv.tuner.builtin;
import android.content.Context;
import android.support.annotation.WorkerThread;
import android.util.Log;
import android.util.Pair;
-
+import com.android.tv.common.customization.CustomizationManager;
+import com.android.tv.common.feature.Model;
+import com.android.tv.tuner.DvbTunerHal;
import com.android.tv.tuner.api.Tuner;
import com.android.tv.tuner.api.TunerFactory;
+
/** TunerHal factory that creates all built in tuner types. */
-public final class DvbTunerHalFactory implements TunerFactory {
- private static final String TAG = "DvbTunerHalFactory";
+public final class BuiltInTunerHalFactory implements TunerFactory {
+ private static final String TAG = "BuiltInTunerHalFactory";
private static final boolean DEBUG = false;
- private final int mBuiltInTunerType = Tuner.BUILT_IN_TUNER_TYPE_LINUX_DVB;
+ private Integer mBuiltInTunerType;
- public static final TunerFactory INSTANCE = new DvbTunerHalFactory();
+ public static final TunerFactory INSTANCE = new BuiltInTunerHalFactory();
- private DvbTunerHalFactory() {}
+ private BuiltInTunerHalFactory() {}
@Tuner.BuiltInTunerType
private int getBuiltInTunerType(Context context) {
+ if (mBuiltInTunerType == null) {
+ mBuiltInTunerType = 0;
+ if (CustomizationManager.hasLinuxDvbBuiltInTuner(context)
+ && DvbTunerHal.getNumberOfDevices(context) > 0) {
+ mBuiltInTunerType = Tuner.BUILT_IN_TUNER_TYPE_LINUX_DVB;
+ }
+ }
return mBuiltInTunerType;
}
@@ -70,6 +80,17 @@ public final class DvbTunerHalFactory implements TunerFactory {
@Override
@WorkerThread
public Pair<Integer, Integer> getTunerTypeAndCount(Context context) {
- return Pair.create(Tuner.TUNER_TYPE_BUILT_IN, DvbTunerHal.getNumberOfDevices(context));
+ if (useBuiltInTuner(context)) {
+ if (getBuiltInTunerType(context) == Tuner.BUILT_IN_TUNER_TYPE_LINUX_DVB) {
+ return new Pair<>(
+ Tuner.TUNER_TYPE_BUILT_IN, DvbTunerHal.getNumberOfDevices(context));
+ }
+ } else {
+ int usbTunerCount = DvbTunerHal.getNumberOfDevices(context);
+ if (usbTunerCount > 0) {
+ return new Pair<>(Tuner.TUNER_TYPE_USB, usbTunerCount);
+ }
+ }
+ return new Pair<>(null, 0);
}
}
diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java b/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java
index 62a4e157..eb9ad463 100644
--- a/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java
+++ b/tuner/src/com/android/tv/tuner/cc/CaptionLayout.java
@@ -18,7 +18,7 @@ package com.android.tv.tuner.cc;
import android.content.Context;
import android.util.AttributeSet;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.layout.ScaledLayout;
/**
diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java b/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
index 75776d6a..4a1c7c1b 100644
--- a/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
+++ b/tuner/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
@@ -27,7 +27,7 @@ import com.android.tv.tuner.data.Cea708Data.CaptionPenLocation;
import com.android.tv.tuner.data.Cea708Data.CaptionWindow;
import com.android.tv.tuner.data.Cea708Data.CaptionWindowAttr;
import com.android.tv.tuner.data.Cea708Parser;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import java.util.ArrayList;
/** Decodes and renders CEA-708. */
@@ -89,7 +89,7 @@ public class CaptionTrackRenderer implements Handler.Callback {
return;
}
if (DEBUG) {
- Log.d(TAG, "Start captionTrack " + captionTrack.getLanguage());
+ Log.d(TAG, "Start captionTrack " + captionTrack.language);
}
reset();
mCaptionLayout.setCaptionTrack(captionTrack);
diff --git a/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java b/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
index 8c699d55..13c6ff47 100644
--- a/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
+++ b/tuner/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
@@ -459,14 +459,14 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
private boolean isKoreanLanguageTrack() {
return mCaptionLayout != null
&& mCaptionLayout.getCaptionTrack() != null
- && mCaptionLayout.getCaptionTrack().hasLanguage()
- && "KOR".equalsIgnoreCase(mCaptionLayout.getCaptionTrack().getLanguage());
+ && mCaptionLayout.getCaptionTrack().language != null
+ && "KOR".compareToIgnoreCase(mCaptionLayout.getCaptionTrack().language) == 0;
}
private boolean isWideAspectRatio() {
return mCaptionLayout != null
&& mCaptionLayout.getCaptionTrack() != null
- && mCaptionLayout.getCaptionTrack().getWideAspectRatio();
+ && mCaptionLayout.getCaptionTrack().wideAspectRatio;
}
private void updateWidestChar() {
diff --git a/tuner/src/com/android/tv/tuner/data/Cea708Parser.java b/tuner/src/com/android/tv/tuner/data/Cea708Parser.java
index 7a5538c8..92834b27 100644
--- a/tuner/src/com/android/tv/tuner/data/Cea708Parser.java
+++ b/tuner/src/com/android/tv/tuner/data/Cea708Parser.java
@@ -138,7 +138,6 @@ public class Cea708Parser {
private long mLastDiscoveryLaunchedMs = SystemClock.elapsedRealtime();
private int mCommand = 0;
private int mListenServiceNumber = 0;
- private int mDtvCcPacketCalculatedSize = 0;
private boolean mDtvCcPacking = false;
private boolean mFirstServiceNumberDiscovered;
@@ -230,7 +229,6 @@ public class Cea708Parser {
mBuffer.setLength(0);
mDiscoveredNumBytes.clear();
mCommand = 0;
- mDtvCcPacketCalculatedSize = 0;
mDtvCcPacking = false;
}
@@ -286,33 +284,29 @@ public class Cea708Parser {
for (int i = 0; i < ccPacket.ccCount; ++i) {
boolean ccValid = (bytes[pos] & 0x04) != 0;
int ccType = bytes[pos] & 0x03;
+
+ // The dtvcc should be considered complete:
+ // - if either ccValid is set and ccType is 3
+ // - or ccValid is clear and ccType is 2 or 3.
if (ccValid) {
- // The dtvcc should be considered complete:
- // if ccType is 3 or if the packet size is reached.
if (ccType == CC_TYPE_DTVCC_PACKET_START) {
if (mDtvCcPacking) {
parseDtvCcPacket(mDtvCcPacket.buffer(), mDtvCcPacket.length());
mDtvCcPacket.clear();
- mDtvCcPacketCalculatedSize = 0;
}
mDtvCcPacking = true;
- int packetSize = bytes[pos + 1] & 0x3F; // last 6 bits
- if (packetSize == 0) {
- packetSize = DTVCC_MAX_PACKET_SIZE;
- }
- mDtvCcPacketCalculatedSize = packetSize * DTVCC_PACKET_SIZE_SCALE_FACTOR;
mDtvCcPacket.append(bytes[pos + 1]);
mDtvCcPacket.append(bytes[pos + 2]);
} else if (mDtvCcPacking && ccType == CC_TYPE_DTVCC_PACKET_DATA) {
mDtvCcPacket.append(bytes[pos + 1]);
mDtvCcPacket.append(bytes[pos + 2]);
}
+ } else {
if ((ccType == CC_TYPE_DTVCC_PACKET_START || ccType == CC_TYPE_DTVCC_PACKET_DATA)
- && mDtvCcPacking && mDtvCcPacket.length() == mDtvCcPacketCalculatedSize) {
+ && mDtvCcPacking) {
mDtvCcPacking = false;
parseDtvCcPacket(mDtvCcPacket.buffer(), mDtvCcPacket.length());
mDtvCcPacket.clear();
- mDtvCcPacketCalculatedSize = 0;
}
}
pos += 3;
diff --git a/tuner/src/com/android/tv/tuner/data/PsiData.java b/tuner/src/com/android/tv/tuner/data/PsiData.java
index 74f16035..9b7c2e2c 100644
--- a/tuner/src/com/android/tv/tuner/data/PsiData.java
+++ b/tuner/src/com/android/tv/tuner/data/PsiData.java
@@ -16,8 +16,8 @@
package com.android.tv.tuner.data;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import java.util.List;
/** Collection of MPEG PSI table items. */
diff --git a/tuner/src/com/android/tv/tuner/data/PsipData.java b/tuner/src/com/android/tv/tuner/data/PsipData.java
index 108ce3f2..d4af0934 100644
--- a/tuner/src/com/android/tv/tuner/data/PsipData.java
+++ b/tuner/src/com/android/tv/tuner/data/PsipData.java
@@ -20,8 +20,8 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.format.DateUtils;
import com.android.tv.common.util.StringUtils;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.util.ConvertUtils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -495,10 +495,10 @@ public class PsipData {
public String toString() {
return String.format(
Locale.US,
- "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, surroundMode:"
- + " %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, langCod2:"
- + " %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s,"
- + " language2: %s",
+ "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, "
+ + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, "
+ + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s"
+ + ", language2: %s",
mSampleRateCode,
mBsid,
mBitRateCode,
@@ -832,7 +832,7 @@ public class PsipData {
}
ArrayList<String> languages = new ArrayList<>();
for (AtscAudioTrack audioTrack : mAudioTracks) {
- languages.add(audioTrack.getLanguage());
+ languages.add(audioTrack.language);
}
return TextUtils.join(",", languages);
}
diff --git a/tuner/src/com/android/tv/tuner/data/SectionParser.java b/tuner/src/com/android/tv/tuner/data/SectionParser.java
index 3c16749e..d3dba6ba 100644
--- a/tuner/src/com/android/tv/tuner/data/SectionParser.java
+++ b/tuner/src/com/android/tv/tuner/data/SectionParser.java
@@ -24,8 +24,7 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
-import com.android.tv.common.feature.Model;
-import com.android.tv.tuner.data.Channel.AtscServiceType;
+
import com.android.tv.tuner.data.PsiData.PatItem;
import com.android.tv.tuner.data.PsiData.PmtItem;
import com.android.tv.tuner.data.PsipData.Ac3AudioDescriptor;
@@ -46,8 +45,9 @@ import com.android.tv.tuner.data.PsipData.ServiceDescriptor;
import com.android.tv.tuner.data.PsipData.ShortEventDescriptor;
import com.android.tv.tuner.data.PsipData.TsDescriptor;
import com.android.tv.tuner.data.PsipData.VctItem;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Channel;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.util.ByteArrayBuffer;
import com.android.tv.tuner.util.ConvertUtils;
import java.io.UnsupportedEncodingException;
@@ -105,7 +105,7 @@ public class SectionParser {
private static final int RATING_REGION_US_TV = 1;
private static final int RATING_REGION_KR_TV = 4;
- // The following values are defined in the TV app.
+ // The following values are defined in the live channels app.
// See https://developer.android.com/reference/android/media/tv/TvContentRating.html.
private static final String RATING_DOMAIN = "com.android.tv";
private static final String RATING_REGION_RATING_SYSTEM_US_TV = "US_TV";
@@ -916,8 +916,8 @@ public class SectionParser {
Log.d(
TAG,
String.format(
- "Found channel [%s] %s - serviceType: %d tsid: 0x%x program: %d"
- + " channel: %d-%d encrypted: %b hidden: %b, descriptors: %d",
+ "Found channel [%s] %s - serviceType: %d tsid: 0x%x program: %d "
+ + "channel: %d-%d encrypted: %b hidden: %b, descriptors: %d",
shortName,
longName,
serviceType,
@@ -929,14 +929,14 @@ public class SectionParser {
hidden,
descriptors.size()));
}
- if ((serviceType == AtscServiceType.SERVICE_TYPE_ATSC_AUDIO_VALUE
+ if (!accessControlled
+ && !hidden
+ && (serviceType == Channel.AtscServiceType.SERVICE_TYPE_ATSC_AUDIO
|| serviceType
- == AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION_VALUE
+ == Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION
|| serviceType
- == AtscServiceType
- .SERVICE_TYPE_UNASSOCIATED_SMALL_SCREEN_SERVICE_VALUE)
- && !accessControlled
- && !hidden) {
+ == Channel.AtscServiceType
+ .SERVICE_TYPE_UNASSOCIATED_SMALL_SCREEN_SERVICE)) {
// Hide hidden, encrypted, or unsupported ATSC service type channels
results.add(
new VctItem(
@@ -1212,20 +1212,16 @@ public class SectionParser {
for (TsDescriptor descriptor : descriptors) {
if (descriptor instanceof Ac3AudioDescriptor) {
Ac3AudioDescriptor audioDescriptor = (Ac3AudioDescriptor) descriptor;
- String language = null;
+ AtscAudioTrack audioTrack = new AtscAudioTrack();
if (audioDescriptor.getLanguage() != null) {
- language = audioDescriptor.getLanguage();
+ audioTrack.language = audioDescriptor.getLanguage();
}
- if (language == null) {
- language = "";
+ if (audioTrack.language == null) {
+ audioTrack.language = "";
}
- AtscAudioTrack audioTrack =
- AtscAudioTrack.newBuilder()
- .setLanguage(language)
- .setAudioType(AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED)
- .setChannelCount(audioDescriptor.getNumChannels())
- .setSampleRate(audioDescriptor.getSampleRate())
- .build();
+ audioTrack.audioType = AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED;
+ audioTrack.channelCount = audioDescriptor.getNumChannels();
+ audioTrack.sampleRate = audioDescriptor.getSampleRate();
ac3Tracks.add(audioTrack);
}
}
@@ -1258,27 +1254,26 @@ public class SectionParser {
}
int size = Math.max(ac3Tracks.size(), iso639LanguageTracks.size());
for (int i = 0; i < size; ++i) {
- AtscAudioTrack.Builder audioTrack = null;
+ AtscAudioTrack audioTrack = null;
if (i < ac3Tracks.size()) {
- audioTrack = ac3Tracks.get(i).toBuilder();
+ audioTrack = ac3Tracks.get(i);
}
if (i < iso639LanguageTracks.size()) {
if (audioTrack == null) {
- audioTrack = iso639LanguageTracks.get(i).toBuilder();
+ audioTrack = iso639LanguageTracks.get(i);
} else {
AtscAudioTrack iso639LanguageTrack = iso639LanguageTracks.get(i);
- if (!audioTrack.hasLanguage()
- || TextUtils.equals(audioTrack.getLanguage(), "")) {
- audioTrack.setLanguage(iso639LanguageTrack.getLanguage());
+ if (audioTrack.language == null || TextUtils.equals(audioTrack.language, "")) {
+ audioTrack.language = iso639LanguageTrack.language;
}
- audioTrack.setAudioType(iso639LanguageTrack.getAudioType());
+ audioTrack.audioType = iso639LanguageTrack.audioType;
}
}
- String language = ISO_LANGUAGE_CODE_MAP.get(audioTrack.getLanguage());
+ String language = ISO_LANGUAGE_CODE_MAP.get(audioTrack.language);
if (language != null) {
- audioTrack = audioTrack.setLanguage(language);
+ audioTrack.language = language;
}
- tracks.add(audioTrack.build());
+ tracks.add(audioTrack);
}
return tracks;
}
@@ -1597,16 +1592,10 @@ public class SectionParser {
return null;
}
String language = new String(data, pos, 3);
- int audioTypeInt = data[pos + 3] & 0xff;
- AtscAudioTrack.AudioType audioType = AtscAudioTrack.AudioType.forNumber(audioTypeInt);
- if (audioType == null) {
- audioType = AtscAudioTrack.AudioType.AUDIOTYPE_UNDEFINED;
- }
- AtscAudioTrack audioTrack =
- AtscAudioTrack.newBuilder()
- .setLanguage(language)
- .setAudioType(audioType)
- .build();
+ int audioType = data[pos + 3] & 0xff;
+ AtscAudioTrack audioTrack = new AtscAudioTrack();
+ audioTrack.language = language;
+ audioTrack.audioType = audioType;
audioTracks.add(audioTrack);
pos += 4;
}
@@ -1645,13 +1634,11 @@ public class SectionParser {
reserved[0] |= (byte) ((data[pos + 1] & 0xc0) >>> 6);
reserved[1] = (byte) ((data[pos + 1] & 0x3f) << 2);
pos += 2;
- AtscCaptionTrack captionTrack =
- AtscCaptionTrack.newBuilder()
- .setLanguage(language)
- .setServiceNumber(captionServiceNumber)
- .setEasyReader(easyReader)
- .setWideAspectRatio(wideAspectRatio)
- .build();
+ AtscCaptionTrack captionTrack = new AtscCaptionTrack();
+ captionTrack.language = language;
+ captionTrack.serviceNumber = captionServiceNumber;
+ captionTrack.easyReader = easyReader;
+ captionTrack.wideAspectRatio = wideAspectRatio;
services.add(captionTrack);
}
return new CaptionServiceDescriptor(services);
@@ -2088,11 +2075,6 @@ public class SectionParser {
}
private static boolean checkSanity(byte[] data) {
- // Skipping CRC checking on Archer since TS data here was modified without updating CRC
- // value. For details, see b/28616908.
- if (Model.ARCHER.isEnabled()) {
- return true;
- }
if (data.length <= 1) {
return false;
}
diff --git a/tuner/src/com/android/tv/tuner/data/TunerChannel.java b/tuner/src/com/android/tv/tuner/data/TunerChannel.java
index 5872cd55..d20c343b 100644
--- a/tuner/src/com/android/tv/tuner/data/TunerChannel.java
+++ b/tuner/src/com/android/tv/tuner/data/TunerChannel.java
@@ -20,10 +20,12 @@ import android.database.Cursor;
import android.support.annotation.NonNull;
import android.util.Log;
import com.android.tv.common.util.StringUtils;
-import com.android.tv.tuner.data.Channel.DeliverySystemType;
-import com.android.tv.tuner.data.Channel.TunerChannelProto;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Channel;
+import com.android.tv.tuner.data.nano.Channel.TunerChannelProto;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
+import com.android.tv.tuner.util.Ints;
+import com.google.protobuf.nano.MessageNano;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -53,7 +55,7 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
"Extended Parameterized Service"
};
private static final String ATSC_SERVICE_TYPE_NAME_RESERVED =
- ATSC_SERVICE_TYPE_NAMES[Channel.AtscServiceType.SERVICE_TYPE_ATSC_RESERVED_VALUE];
+ ATSC_SERVICE_TYPE_NAMES[Channel.AtscServiceType.SERVICE_TYPE_ATSC_RESERVED];
public static final int INVALID_FREQUENCY = -1;
@@ -64,128 +66,93 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
public static final int INVALID_STREAMTYPE = -1;
// @GuardedBy(this) Writing operations and toByteArray will be guarded. b/34197766
- private TunerChannelProto mProto;
+ private final TunerChannelProto mProto;
private TunerChannel(
- PsipData.VctItem channel,
- int programNumber,
- List<PsiData.PmtItem> pmtItems,
- Channel.TunerType type) {
- String shortName = "";
- String longName = "";
- String description = "";
- int tsid = 0;
- int virtualMajor = 0;
- int virtualMinor = 0;
- Channel.AtscServiceType serviceType =
- Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION;
- if (channel != null) {
- shortName = channel.getShortName();
- tsid = channel.getChannelTsid();
- programNumber = channel.getProgramNumber();
- virtualMajor = channel.getMajorChannelNumber();
- virtualMinor = channel.getMinorChannelNumber();
- Channel.AtscServiceType chanServiceType =
- Channel.AtscServiceType.forNumber(channel.getServiceType());
- if (chanServiceType != null) {
- serviceType = chanServiceType;
+ PsipData.VctItem channel, int programNumber, List<PsiData.PmtItem> pmtItems, int type) {
+ mProto = new TunerChannelProto();
+ if (channel == null) {
+ mProto.shortName = "";
+ mProto.tsid = 0;
+ mProto.programNumber = programNumber;
+ mProto.virtualMajor = 0;
+ mProto.virtualMinor = 0;
+ } else {
+ mProto.shortName = channel.getShortName();
+ if (channel.getLongName() != null) {
+ mProto.longName = channel.getLongName();
}
- longName = (channel.getLongName() != null ? channel.getLongName() : longName);
- description =
- (channel.getDescription() != null ? channel.getDescription() : description);
+ mProto.tsid = channel.getChannelTsid();
+ mProto.programNumber = channel.getProgramNumber();
+ mProto.virtualMajor = channel.getMajorChannelNumber();
+ mProto.virtualMinor = channel.getMinorChannelNumber();
+ if (channel.getDescription() != null) {
+ mProto.description = channel.getDescription();
+ }
+ mProto.serviceType = channel.getServiceType();
}
- TunerChannelProto tunerChannelProto =
- TunerChannelProto.newBuilder()
- .setShortName(shortName)
- .setTsid(tsid)
- .setProgramNumber(programNumber)
- .setVirtualMajor(virtualMajor)
- .setVirtualMinor(virtualMinor)
- .setServiceType(serviceType)
- .setLongName(longName)
- .setDescription(description)
- .build();
- initProto(pmtItems, type, tunerChannelProto);
- }
-
- private void initProto(
- List<PsiData.PmtItem> pmtItems,
- Channel.TunerType type,
- TunerChannelProto tunerChannelProto) {
- int videoPid = INVALID_PID;
- int pcrPid = 0;
- Channel.VideoStreamType videoStreamType = Channel.VideoStreamType.UNSET;
+ initProto(pmtItems, type);
+ }
+
+ private void initProto(List<PsiData.PmtItem> pmtItems, int type) {
+ mProto.type = type;
+ mProto.channelId = -1L;
+ mProto.frequency = INVALID_FREQUENCY;
+ mProto.videoPid = INVALID_PID;
+ mProto.videoStreamType = INVALID_STREAMTYPE;
List<Integer> audioPids = new ArrayList<>();
- List<Channel.AudioStreamType> audioStreamTypes = new ArrayList<>();
+ List<Integer> audioStreamTypes = new ArrayList<>();
for (PsiData.PmtItem pmt : pmtItems) {
switch (pmt.getStreamType()) {
// MPEG ES stream video types
- case Channel.VideoStreamType.MPEG1_VALUE:
- case Channel.VideoStreamType.MPEG2_VALUE:
- case Channel.VideoStreamType.H263_VALUE:
- case Channel.VideoStreamType.H264_VALUE:
- case Channel.VideoStreamType.H265_VALUE:
- videoPid = pmt.getEsPid();
- videoStreamType = Channel.VideoStreamType.forNumber(pmt.getStreamType());
+ case Channel.VideoStreamType.MPEG1:
+ case Channel.VideoStreamType.MPEG2:
+ case Channel.VideoStreamType.H263:
+ case Channel.VideoStreamType.H264:
+ case Channel.VideoStreamType.H265:
+ mProto.videoPid = pmt.getEsPid();
+ mProto.videoStreamType = pmt.getStreamType();
break;
// MPEG ES stream audio types
- case Channel.AudioStreamType.MPEG1AUDIO_VALUE:
- case Channel.AudioStreamType.MPEG2AUDIO_VALUE:
- case Channel.AudioStreamType.MPEG2AACAUDIO_VALUE:
- case Channel.AudioStreamType.MPEG4LATMAACAUDIO_VALUE:
- case Channel.AudioStreamType.A52AC3AUDIO_VALUE:
- case Channel.AudioStreamType.EAC3AUDIO_VALUE:
+ case Channel.AudioStreamType.MPEG1AUDIO:
+ case Channel.AudioStreamType.MPEG2AUDIO:
+ case Channel.AudioStreamType.MPEG2AACAUDIO:
+ case Channel.AudioStreamType.MPEG4LATMAACAUDIO:
+ case Channel.AudioStreamType.A52AC3AUDIO:
+ case Channel.AudioStreamType.EAC3AUDIO:
audioPids.add(pmt.getEsPid());
- audioStreamTypes.add(Channel.AudioStreamType.forNumber(pmt.getStreamType()));
+ audioStreamTypes.add(pmt.getStreamType());
break;
// Non MPEG ES stream types
case 0x100: // PmtItem.ES_PID_PCR:
- pcrPid = pmt.getEsPid();
+ mProto.pcrPid = pmt.getEsPid();
break;
default:
// fall out
}
}
- mProto =
- TunerChannelProto.newBuilder(tunerChannelProto)
- .setType(type)
- .setChannelId(-1L)
- .setFrequency(INVALID_FREQUENCY)
- .setVideoPid(videoPid)
- .setVideoStreamType(videoStreamType)
- .addAllAudioPids(audioPids)
- .setAudioTrackIndex(audioPids.isEmpty() ? -1 : 0)
- .addAllAudioStreamTypes(audioStreamTypes)
- .setPcrPid(pcrPid)
- .build();
+ mProto.audioPids = Ints.toArray(audioPids);
+ mProto.audioStreamTypes = Ints.toArray(audioStreamTypes);
+ mProto.audioTrackIndex = (audioPids.size() > 0) ? 0 : -1;
}
private TunerChannel(
- int programNumber,
- Channel.TunerType type,
- PsipData.SdtItem channel,
- List<PsiData.PmtItem> pmtItems) {
- String shortName = "";
- Channel.AtscServiceType serviceType =
- Channel.AtscServiceType.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION;
- if (channel != null) {
- shortName = channel.getServiceName();
- programNumber = channel.getServiceId();
- Channel.AtscServiceType chanServiceType =
- Channel.AtscServiceType.forNumber(channel.getServiceType());
- if (chanServiceType != null) {
- serviceType = chanServiceType;
- }
+ int programNumber, int type, PsipData.SdtItem channel, List<PsiData.PmtItem> pmtItems) {
+ mProto = new TunerChannelProto();
+ mProto.tsid = 0;
+ mProto.virtualMajor = 0;
+ mProto.virtualMinor = 0;
+ if (channel == null) {
+ mProto.shortName = "";
+ mProto.programNumber = programNumber;
+ } else {
+ mProto.shortName = channel.getServiceName();
+ mProto.programNumber = channel.getServiceId();
+ mProto.serviceType = channel.getServiceType();
}
- TunerChannelProto tunerChannelProto =
- TunerChannelProto.newBuilder()
- .setShortName(shortName)
- .setProgramNumber(programNumber)
- .setServiceType(serviceType)
- .build();
- initProto(pmtItems, type, tunerChannelProto);
+ initProto(pmtItems, type);
}
/** Initialize tuner channel with VCT items and PMT items. */
@@ -266,23 +233,23 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
}
public String getName() {
- return !mProto.getShortName().isEmpty() ? mProto.getShortName() : mProto.getLongName();
+ return (!mProto.shortName.isEmpty()) ? mProto.shortName : mProto.longName;
}
public String getShortName() {
- return mProto.getShortName();
+ return mProto.shortName;
}
public int getProgramNumber() {
- return mProto.getProgramNumber();
+ return mProto.programNumber;
}
public int getServiceType() {
- return mProto.getServiceType().getNumber();
+ return mProto.serviceType;
}
public String getServiceTypeName() {
- int serviceType = getServiceType();
+ int serviceType = mProto.serviceType;
if (serviceType >= 0 && serviceType < ATSC_SERVICE_TYPE_NAMES.length) {
return ATSC_SERVICE_TYPE_NAMES[serviceType];
}
@@ -290,129 +257,105 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
}
public int getVirtualMajor() {
- return mProto.getVirtualMajor();
+ return mProto.virtualMajor;
}
public int getVirtualMinor() {
- return mProto.getVirtualMinor();
- }
-
- public DeliverySystemType getDeliverySystemType() {
- return mProto.getDeliverySystemType();
+ return mProto.virtualMinor;
}
public int getFrequency() {
- return mProto.getFrequency();
+ return mProto.frequency;
}
public String getModulation() {
- return mProto.getModulation();
+ return mProto.modulation;
}
public int getTsid() {
- return mProto.getTsid();
+ return mProto.tsid;
}
public int getVideoPid() {
- return mProto.getVideoPid();
+ return mProto.videoPid;
}
public synchronized void setVideoPid(int videoPid) {
- mProto = mProto.toBuilder().setVideoPid(videoPid).build();
+ mProto.videoPid = videoPid;
}
public int getVideoStreamType() {
- return mProto.getVideoStreamType().getNumber();
+ return mProto.videoStreamType;
}
public int getAudioPid() {
- if (!mProto.hasAudioTrackIndex() || mProto.getAudioTrackIndex() == -1) {
+ if (mProto.audioTrackIndex == -1) {
return INVALID_PID;
}
- return mProto.getAudioPids(mProto.getAudioTrackIndex());
+ return mProto.audioPids[mProto.audioTrackIndex];
}
public int getAudioStreamType() {
- if (!mProto.hasAudioTrackIndex() || mProto.getAudioTrackIndex() == -1) {
+ if (mProto.audioTrackIndex == -1) {
return INVALID_STREAMTYPE;
}
- return mProto.getAudioStreamTypes(mProto.getAudioTrackIndex()).getNumber();
+ return mProto.audioStreamTypes[mProto.audioTrackIndex];
}
public List<Integer> getAudioPids() {
- return mProto.getAudioPidsList();
+ return Ints.asList(mProto.audioPids);
}
public synchronized void setAudioPids(List<Integer> audioPids) {
- mProto = mProto.toBuilder().clearAudioPids().addAllAudioPids(audioPids).build();
+ mProto.audioPids = Ints.toArray(audioPids);
}
public List<Integer> getAudioStreamTypes() {
- List<Channel.AudioStreamType> audioStreamTypes = mProto.getAudioStreamTypesList();
- List<Integer> audioStreamTypesValues = new ArrayList<>(audioStreamTypes.size());
-
- for (Channel.AudioStreamType audioStreamType : audioStreamTypes) {
- audioStreamTypesValues.add(audioStreamType.getNumber());
- }
- return audioStreamTypesValues;
+ return Ints.asList(mProto.audioStreamTypes);
}
- public synchronized void setAudioStreamTypes(List<Integer> audioStreamTypesValues) {
- List<Channel.AudioStreamType> audioStreamTypes =
- new ArrayList<>(audioStreamTypesValues.size());
-
- for (Integer audioStreamTypesValue : audioStreamTypesValues) {
- audioStreamTypes.add(Channel.AudioStreamType.forNumber(audioStreamTypesValue));
- }
- mProto =
- mProto.toBuilder()
- .clearAudioStreamTypes()
- .addAllAudioStreamTypes(audioStreamTypes)
- .build();
+ public synchronized void setAudioStreamTypes(List<Integer> audioStreamTypes) {
+ mProto.audioStreamTypes = Ints.toArray(audioStreamTypes);
}
public int getPcrPid() {
- return mProto.getPcrPid();
+ return mProto.pcrPid;
}
- public Channel.TunerType getType() {
- return mProto.getType();
+ public int getType() {
+ return mProto.type;
}
public synchronized void setFilepath(String filepath) {
- mProto = mProto.toBuilder().setFilepath(filepath == null ? "" : filepath).build();
+ mProto.filepath = filepath == null ? "" : filepath;
}
public String getFilepath() {
- return mProto.getFilepath();
+ return mProto.filepath;
}
public synchronized void setVirtualMajor(int virtualMajor) {
- mProto = mProto.toBuilder().setVirtualMajor(virtualMajor).build();
+ mProto.virtualMajor = virtualMajor;
}
public synchronized void setVirtualMinor(int virtualMinor) {
- mProto = mProto.toBuilder().setVirtualMinor(virtualMinor).build();
+ mProto.virtualMinor = virtualMinor;
}
public synchronized void setShortName(String shortName) {
- mProto = mProto.toBuilder().setShortName(shortName == null ? "" : shortName).build();
- }
-
- public synchronized void setDeliverySystemType(DeliverySystemType deliverySystemType) {
- mProto = mProto.toBuilder().setDeliverySystemType(deliverySystemType).build();
+ mProto.shortName = shortName == null ? "" : shortName;
}
public synchronized void setFrequency(int frequency) {
- mProto = mProto.toBuilder().setFrequency(frequency).build();
+ mProto.frequency = frequency;
}
public synchronized void setModulation(String modulation) {
- mProto = mProto.toBuilder().setModulation(modulation == null ? "" : modulation).build();
+ mProto.modulation = modulation == null ? "" : modulation;
}
public boolean hasVideo() {
- return mProto.hasVideoPid() && mProto.getVideoPid() != INVALID_PID;
+ return mProto.videoPid != INVALID_PID;
}
public boolean hasAudio() {
@@ -420,11 +363,11 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
}
public long getChannelId() {
- return mProto.getChannelId();
+ return mProto.channelId;
}
public synchronized void setChannelId(long channelId) {
- mProto = mProto.toBuilder().setChannelId(channelId).build();
+ mProto.channelId = channelId;
}
/**
@@ -436,11 +379,11 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
* href="https://developer.android.com/reference/android/media/tv/TvContract.Channels.html#COLUMN_LOCKED">link</a>
*/
public boolean isLocked() {
- return mProto.getLocked();
+ return mProto.locked;
}
public synchronized void setLocked(boolean locked) {
- mProto = mProto.toBuilder().setLocked(locked).build();
+ mProto.locked = locked;
}
public String getDisplayNumber() {
@@ -448,91 +391,92 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
}
public String getDisplayNumber(boolean ignoreZeroMinorNumber) {
- if (getVirtualMajor() != 0 && (getVirtualMinor() != 0 || !ignoreZeroMinorNumber)) {
+ if (mProto.virtualMajor != 0 && (mProto.virtualMinor != 0 || !ignoreZeroMinorNumber)) {
return String.format(
- "%d%c%d", getVirtualMajor(), CHANNEL_NUMBER_SEPARATOR, getVirtualMinor());
- } else if (getVirtualMajor() != 0) {
- return Integer.toString(getVirtualMajor());
+ "%d%c%d", mProto.virtualMajor, CHANNEL_NUMBER_SEPARATOR, mProto.virtualMinor);
+ } else if (mProto.virtualMajor != 0) {
+ return Integer.toString(mProto.virtualMajor);
} else {
- return Integer.toString(getProgramNumber());
+ return Integer.toString(mProto.programNumber);
}
}
public String getDescription() {
- return mProto.getDescription();
+ return mProto.description;
}
@Override
public synchronized void setHasCaptionTrack() {
- mProto = mProto.toBuilder().setHasCaptionTrack(true).build();
+ mProto.hasCaptionTrack = true;
}
@Override
public boolean hasCaptionTrack() {
- return mProto.getHasCaptionTrack();
+ return mProto.hasCaptionTrack;
}
@Override
public List<AtscAudioTrack> getAudioTracks() {
- return mProto.getAudioTracksList();
+ return Collections.unmodifiableList(Arrays.asList(mProto.audioTracks));
}
public synchronized void setAudioTracks(List<AtscAudioTrack> audioTracks) {
- mProto = mProto.toBuilder().clearAudioTracks().addAllAudioTracks(audioTracks).build();
+ mProto.audioTracks = audioTracks.toArray(new AtscAudioTrack[audioTracks.size()]);
}
@Override
public List<AtscCaptionTrack> getCaptionTracks() {
- return mProto.getCaptionTracksList();
+ return Collections.unmodifiableList(Arrays.asList(mProto.captionTracks));
}
public synchronized void setCaptionTracks(List<AtscCaptionTrack> captionTracks) {
- mProto = mProto.toBuilder().clearCaptionTracks().addAllCaptionTracks(captionTracks).build();
+ mProto.captionTracks = captionTracks.toArray(new AtscCaptionTrack[captionTracks.size()]);
}
public synchronized void selectAudioTrack(int index) {
- if (index < 0 || index >= mProto.getAudioPidsCount()) {
- index = -1;
+ if (0 <= index && index < mProto.audioPids.length) {
+ mProto.audioTrackIndex = index;
+ } else {
+ mProto.audioTrackIndex = -1;
}
- mProto = mProto.toBuilder().setAudioTrackIndex(index).build();
}
public synchronized void setRecordingProhibited(boolean recordingProhibited) {
- mProto = mProto.toBuilder().setRecordingProhibited(recordingProhibited).build();
+ mProto.recordingProhibited = recordingProhibited;
}
public boolean isRecordingProhibited() {
- return mProto.getRecordingProhibited();
+ return mProto.recordingProhibited;
}
public synchronized void setVideoFormat(String videoFormat) {
- mProto = mProto.toBuilder().setVideoFormat(videoFormat == null ? "" : videoFormat).build();
+ mProto.videoFormat = videoFormat == null ? "" : videoFormat;
}
public String getVideoFormat() {
- return mProto.getVideoFormat();
+ return mProto.videoFormat;
}
@Override
public String toString() {
- switch (getType()) {
- case TYPE_FILE:
+ switch (mProto.type) {
+ case Channel.TunerType.TYPE_FILE:
return String.format(
"{%d-%d %s} Filepath: %s, ProgramNumber %d",
- getVirtualMajor(),
- getVirtualMinor(),
- getShortName(),
- getFilepath(),
- getProgramNumber());
+ mProto.virtualMajor,
+ mProto.virtualMinor,
+ mProto.shortName,
+ mProto.filepath,
+ mProto.programNumber);
// case Channel.TunerType.TYPE_TUNER:
default:
return String.format(
"{%d-%d %s} Frequency: %d, ProgramNumber %d",
- getVirtualMajor(),
- getVirtualMinor(),
- getShortName(),
- getFrequency(),
- getProgramNumber());
+ mProto.virtualMajor,
+ mProto.virtualMinor,
+ mProto.shortName,
+ mProto.frequency,
+ mProto.programNumber);
}
}
@@ -551,9 +495,6 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
if (ret != 0) {
return ret;
}
- if (getDeliverySystemType() != channel.getDeliverySystemType()) {
- return 1;
- }
// For FileTsStreamer, file paths should be compared.
return StringUtils.compare(getFilepath(), channel.getFilepath());
}
@@ -568,21 +509,20 @@ public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracks
@Override
public int hashCode() {
- return Objects.hash(getDeliverySystemType(), getFrequency(), getProgramNumber(), getName(),
- getFilepath());
+ return Objects.hash(getFrequency(), getProgramNumber(), getName(), getFilepath());
}
// Serialization
public synchronized byte[] toByteArray() {
try {
- return mProto.toByteArray();
+ return MessageNano.toByteArray(mProto);
} catch (Exception e) {
// Retry toByteArray. b/34197766
Log.w(
TAG,
"TunerChannel or its variables are modified in multiple thread without lock",
e);
- return mProto.toByteArray();
+ return MessageNano.toByteArray(mProto);
}
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
index 2a22db17..e48cb03c 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
@@ -26,32 +26,32 @@ import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.Pair;
-
import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer;
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener;
import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer;
import com.android.tv.tuner.exoplayer.buffer.SimpleSampleBuffer;
-
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder;
+import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
+import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
+import com.google.android.exoplayer2.source.ExtractorMediaSource.EventListener;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
-import com.google.android.exoplayer2.upstream.DataSource;
+import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
-
+import com.google.android.exoplayer2.upstream.TransferListener;
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -72,6 +72,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
private final long mId;
private final Handler.Callback mSourceReaderWorker;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
private BufferManager.SampleBuffer mSampleBuffer;
private Handler mSourceReaderHandler;
@@ -88,29 +89,13 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
private Handler mOnCompletionListenerHandler;
private IOException mError;
- /**
- * Factory for {@link ExoPlayerSampleExtractor}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public ExoPlayerSampleExtractor create(
- Uri uri,
- DataSource source,
- @Nullable BufferManager bufferManager,
- PlaybackBufferListener bufferListener,
- boolean isRecording);
- }
-
- @AutoFactory(implementing = Factory.class)
public ExoPlayerSampleExtractor(
Uri uri,
- DataSource source,
- @Nullable BufferManager bufferManager,
+ final DataSource source,
+ BufferManager bufferManager,
PlaybackBufferListener bufferListener,
boolean isRecording,
- @Provided RecordingSampleBuffer.Factory recordingSampleBufferFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlagsoncurrentDvrPlaybackFlags) {
this(
uri,
source,
@@ -119,7 +104,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
isRecording,
Looper.myLooper(),
new HandlerThread("SourceReaderThread"),
- recordingSampleBufferFactory);
+ concurrentDvrPlaybackFlagsoncurrentDvrPlaybackFlags);
}
@VisibleForTesting
@@ -132,35 +117,98 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
boolean isRecording,
Looper workerLooper,
HandlerThread sourceReaderThread,
- RecordingSampleBuffer.Factory recordingSampleBufferFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) {
// It'll be used as a timeshift file chunk name's prefix.
mId = System.currentTimeMillis();
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
+
+ EventListener eventListener =
+ new EventListener() {
+ @Override
+ public void onLoadError(IOException error) {
+ mError = error;
+ }
+ };
mSourceReaderThread = sourceReaderThread;
mSourceReaderWorker =
new SourceReaderWorker(
new ExtractorMediaSource(
uri,
- /* dataSourceFactory= */ () -> source,
+ new com.google.android.exoplayer2.upstream.DataSource.Factory() {
+ @Override
+ public com.google.android.exoplayer2.upstream.DataSource
+ createDataSource() {
+ // Returns an adapter implementation for ExoPlayer V2
+ // DataSource interface.
+ return new com.google.android.exoplayer2.upstream
+ .DataSource() {
+
+ private @Nullable Uri uri;
+
+ // TODO: uncomment once this is part of the public API.
+ // @Override
+ public void addTransferListener(
+ TransferListener transferListener) {
+ // Do nothing. Unsupported in V1.
+ }
+
+ @Override
+ public long open(DataSpec dataSpec) throws IOException {
+ this.uri = dataSpec.uri;
+ return source.open(
+ new com.google.android.exoplayer.upstream
+ .DataSpec(
+ dataSpec.uri,
+ dataSpec.postBody,
+ dataSpec.absoluteStreamPosition,
+ dataSpec.position,
+ dataSpec.length,
+ dataSpec.key,
+ dataSpec.flags));
+ }
+
+ @Override
+ public int read(
+ byte[] buffer, int offset, int readLength)
+ throws IOException {
+ return source.read(buffer, offset, readLength);
+ }
+
+ @Override
+ public @Nullable Uri getUri() {
+ return uri;
+ }
+
+ @Override
+ public void close() throws IOException {
+ source.close();
+ uri = null;
+ }
+ };
+ }
+ },
new ExoPlayerExtractorsFactory(),
new Handler(workerLooper),
- /* eventListener= */ error -> mError = error));
+ eventListener));
if (isRecording) {
mSampleBuffer =
- recordingSampleBufferFactory.create(
+ new RecordingSampleBuffer(
bufferManager,
bufferListener,
false,
+ mConcurrentDvrPlaybackFlags,
RecordingSampleBuffer.BUFFER_REASON_RECORDING);
} else {
if (bufferManager == null) {
mSampleBuffer = new SimpleSampleBuffer(bufferListener);
} else {
mSampleBuffer =
- recordingSampleBufferFactory.create(
+ new RecordingSampleBuffer(
bufferManager,
bufferListener,
true,
+ mConcurrentDvrPlaybackFlags,
RecordingSampleBuffer.BUFFER_REASON_LIVE_PLAYBACK);
}
}
@@ -192,11 +240,15 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
public SourceReaderWorker(MediaSource sampleSource) {
mSampleSource = sampleSource;
mSampleSourceListener =
- (source, timeline, manifest) -> {
- // Dynamic stream change is not supported yet. b/28169263
- // For now, this will cause EOS and playback reset.
+ new MediaSource.SourceInfoRefreshListener() {
+ @Override
+ public void onSourceInfoRefreshed(
+ MediaSource source, Timeline timeline, Object manifest) {
+ // Dynamic stream change is not supported yet. b/28169263
+ // For now, this will cause EOS and playback reset.
+ }
};
- mSampleSource.prepareSource(mSampleSourceListener, null);
+ mSampleSource.prepareSource(null, false, mSampleSourceListener, null);
mDecoderInputBuffer =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
mSampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
@@ -313,8 +365,9 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
mMediaPeriod =
mSampleSource.createPeriod(
new MediaSource.MediaPeriodId(0),
- new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
- 0);
+ new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE)
+// AOSP_Comment_Out , 0
+ );
mMediaPeriod.prepare(this, 0);
try {
mMediaPeriod.maybeThrowPrepareError();
@@ -433,7 +486,7 @@ public class ExoPlayerSampleExtractor implements SampleExtractor {
sample.data.position(0);
sample.data.put(mDecoderInputBuffer.data);
sample.data.flip();
- mPendingSamples.add(Pair.create(index, sample));
+ mPendingSamples.add(new Pair<>(index, sample));
return;
}
mVideoTrackMet = true;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
index aaca043b..9749e4ba 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
@@ -17,18 +17,14 @@
package com.android.tv.tuner.exoplayer;
import android.os.Handler;
-
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener;
import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer;
-
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.MediaFormatUtil;
import com.google.android.exoplayer.SampleHolder;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -48,28 +44,16 @@ public class FileSampleExtractor implements SampleExtractor {
private final BufferManager mBufferManager;
private final PlaybackBufferListener mBufferListener;
private BufferManager.SampleBuffer mSampleBuffer;
- private final RecordingSampleBuffer.Factory mRecordingSampleBufferFactory;
-
- /**
- * Factory for {@link FileSampleExtractor}}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public FileSampleExtractor create(
- BufferManager bufferManager, PlaybackBufferListener bufferListener);
- }
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
- @AutoFactory(implementing = Factory.class)
public FileSampleExtractor(
BufferManager bufferManager,
PlaybackBufferListener bufferListener,
- @Provided RecordingSampleBuffer.Factory recordingSampleBufferFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) {
mBufferManager = bufferManager;
mBufferListener = bufferListener;
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
mTrackCount = -1;
- mRecordingSampleBufferFactory = recordingSampleBufferFactory;
}
@Override
@@ -92,10 +76,11 @@ public class FileSampleExtractor implements SampleExtractor {
mTrackFormats.add(MediaFormatUtil.createMediaFormat(trackFormat.format));
}
mSampleBuffer =
- mRecordingSampleBufferFactory.create(
+ new RecordingSampleBuffer(
mBufferManager,
mBufferListener,
true,
+ mConcurrentDvrPlaybackFlags,
RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK);
mSampleBuffer.init(ids, mTrackFormats);
return true;
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
index 67cf992c..6781c616 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
@@ -43,8 +43,7 @@ import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioTrack;
-import com.google.android.exoplayer2.upstream.DataSource;
-
+import com.google.android.exoplayer.upstream.DataSource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -148,7 +147,7 @@ public class MpegTsPlayer
*
* @param rendererBuilder the builder of track renderers
* @param handler the handler for the playback events in track renderers
- * @param sourceManager the manager for {@link TsDataSource}
+ * @param sourceManager the manager for {@link DataSource}
* @param capabilities the {@link AudioCapabilities} of the current device
* @param listener the listener for playback state changes
*/
@@ -215,7 +214,7 @@ public class MpegTsPlayer
}
/**
- * Creates renderers and {@link TsDataSource} and initializes player.
+ * Creates renderers and {@link DataSource} and initializes player.
*
* @param context a {@link Context} instance
* @param channel to play
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
index f860631c..e043907f 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
@@ -17,51 +17,33 @@
package com.android.tv.tuner.exoplayer;
import android.content.Context;
-import android.support.annotation.Nullable;
-
import com.android.tv.tuner.exoplayer.MpegTsPlayer.RendererBuilder;
import com.android.tv.tuner.exoplayer.MpegTsPlayer.RendererBuilderCallback;
import com.android.tv.tuner.exoplayer.audio.MpegTsDefaultAudioTrackRenderer;
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener;
-
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer;
-import com.google.android.exoplayer2.upstream.DataSource;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
+import com.google.android.exoplayer.upstream.DataSource;
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
/** Builder for renderer objects for {@link MpegTsPlayer}. */
public class MpegTsRendererBuilder implements RendererBuilder {
private final Context mContext;
private final BufferManager mBufferManager;
private final PlaybackBufferListener mBufferListener;
- private final MpegTsSampleExtractor.Factory mMpegTsSampleExtractorFactory;
-
- /**
- * Factory for {@link MpegTsRendererBuilder}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public MpegTsRendererBuilder create(
- Context context,
- @Nullable BufferManager bufferManager,
- PlaybackBufferListener bufferListener);
- }
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
- @AutoFactory(implementing = Factory.class)
public MpegTsRendererBuilder(
Context context,
- @Nullable BufferManager bufferManager,
+ BufferManager bufferManager,
PlaybackBufferListener bufferListener,
- @Provided MpegTsSampleExtractor.Factory mpegTsSampleExtractorFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) {
mContext = context;
mBufferManager = bufferManager;
mBufferListener = bufferListener;
- mMpegTsSampleExtractorFactory = mpegTsSampleExtractorFactory;
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
}
@Override
@@ -70,9 +52,13 @@ public class MpegTsRendererBuilder implements RendererBuilder {
// Build the video and audio renderers.
SampleExtractor extractor =
dataSource == null
- ? mMpegTsSampleExtractorFactory.create(mBufferManager, mBufferListener)
- : mMpegTsSampleExtractorFactory.create(
- dataSource, mBufferManager, mBufferListener);
+ ? new MpegTsSampleExtractor(
+ mBufferManager, mBufferListener, mConcurrentDvrPlaybackFlags)
+ : new MpegTsSampleExtractor(
+ dataSource,
+ mBufferManager,
+ mBufferListener,
+ mConcurrentDvrPlaybackFlags);
SampleSource sampleSource = new MpegTsSampleSource(extractor);
MpegTsVideoTrackRenderer videoRenderer =
new MpegTsVideoTrackRenderer(
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
index 8d3668ef..582f18c5 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
@@ -18,21 +18,16 @@ package com.android.tv.tuner.exoplayer;
import android.net.Uri;
import android.os.Handler;
-import android.support.annotation.Nullable;
-
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
import com.android.tv.tuner.exoplayer.buffer.PlaybackBufferListener;
import com.android.tv.tuner.exoplayer.buffer.SamplePool;
-
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
+import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.util.MimeTypes;
-import com.google.android.exoplayer2.upstream.DataSource;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -64,37 +59,27 @@ public final class MpegTsSampleExtractor implements SampleExtractor {
}
/**
- * Factory for {@link MpegTsSampleExtractor}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public MpegTsSampleExtractor create(
- BufferManager bufferManager, PlaybackBufferListener bufferListener);
-
- public MpegTsSampleExtractor create(
- DataSource source,
- @Nullable BufferManager bufferManager,
- PlaybackBufferListener bufferListener);
- }
-
- /**
- * Creates MpegTsSampleExtractor for a {@link DataSource}.
+ * Creates MpegTsSampleExtractor for {@link DataSource}.
*
* @param source the {@link DataSource} to extract from
* @param bufferManager the manager for reading & writing samples backed by physical storage
* @param bufferListener the {@link PlaybackBufferListener} to notify buffer storage status
+ * @param concurrentDvrPlaybackFlags
*/
- @AutoFactory(implementing = Factory.class)
public MpegTsSampleExtractor(
DataSource source,
- @Nullable BufferManager bufferManager,
+ BufferManager bufferManager,
PlaybackBufferListener bufferListener,
- @Provided ExoPlayerSampleExtractor.Factory exoPlayerSampleExtractorFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) {
+
mSampleExtractor =
- exoPlayerSampleExtractorFactory.create(
- Uri.EMPTY, source, bufferManager, bufferListener, false);
+ new ExoPlayerSampleExtractor(
+ Uri.EMPTY,
+ source,
+ bufferManager,
+ bufferListener,
+ false,
+ concurrentDvrPlaybackFlags);
init();
}
@@ -105,12 +90,12 @@ public final class MpegTsSampleExtractor implements SampleExtractor {
* @param bufferListener the {@link PlaybackBufferListener} to notify buffer storage status
* change
*/
- @AutoFactory(implementing = Factory.class)
public MpegTsSampleExtractor(
BufferManager bufferManager,
PlaybackBufferListener bufferListener,
- @Provided FileSampleExtractor.Factory fileSampleExtractorFactory) {
- mSampleExtractor = fileSampleExtractorFactory.create(bufferManager, bufferListener);
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) {
+ mSampleExtractor =
+ new FileSampleExtractor(bufferManager, bufferListener, concurrentDvrPlaybackFlags);
init();
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java b/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java
index fb88e5b7..bab74c9d 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/audio/MpegTsDefaultAudioTrackRenderer.java
@@ -246,7 +246,6 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me
mSource.seekToUs(positionUs);
AUDIO_TRACK.reset();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
- // b/21824483 workaround
// resetSessionId() will create a new framework AudioTrack instead of reusing old one.
AUDIO_TRACK.resetSessionId();
}
@@ -285,7 +284,6 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me
// Ensure playback stops, after EoS was notified.
// Sometimes MediaCodecTrackRenderer does not fetch EoS timely
// after EoS was notified here long before.
- // see b/21909113
long diff = SystemClock.elapsedRealtime() - mEndOfStreamMs;
if (diff >= KEEP_ALIVE_AFTER_EOS_DURATION_MS && !mIsStopped) {
throw new ExoPlaybackException("Much time has elapsed after EoS");
@@ -594,7 +592,6 @@ public class MpegTsDefaultAudioTrackRenderer extends TrackRenderer implements Me
}
mCurrentPositionUs = Math.max(mPresentationTimeUs, mCurrentPositionUs);
} else {
- // TODO: Remove this workaround when b/22023809 is resolved.
if (mPreviousPositionUs
> audioTrackCurrentPositionUs + BACKWARD_AUDIO_TRACK_MOVE_THRESHOLD_US) {
Log.e(
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
index b8d85230..c32540c1 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
@@ -23,13 +23,10 @@ import android.support.annotation.VisibleForTesting;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
-
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.CommonUtils;
import com.android.tv.tuner.exoplayer.SampleExtractor;
-
import com.google.android.exoplayer.SampleHolder;
-
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -403,13 +400,13 @@ public class BufferManager {
SampleChunk sampleChunk =
mSampleChunkCreator.createSampleChunk(
samplePool, file, positionUs, mChunkCallback);
- map.put(positionUs, Pair.create(sampleChunk, 0));
+ map.put(positionUs, new Pair(sampleChunk, 0));
if (updateIndexFile) {
mStorageManager.updateIndexFile(id, map.size(), positionUs, sampleChunk, 0);
}
return sampleChunk;
} else {
- map.put(positionUs, Pair.create(currentChunk, currentOffset));
+ map.put(positionUs, new Pair(currentChunk, currentOffset));
if (updateIndexFile) {
mStorageManager.updateIndexFile(
id, map.size(), positionUs, currentChunk, currentOffset);
@@ -450,7 +447,7 @@ public class BufferManager {
chunk);
basePositionUs = position.basePositionUs;
}
- map.put(position.positionUs, Pair.create(chunk, position.offset));
+ map.put(position.positionUs, new Pair(chunk, position.offset));
}
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
index 0e1cbe9f..f19756ec 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
@@ -19,7 +19,8 @@ package com.android.tv.tuner.exoplayer.buffer;
import android.media.MediaFormat;
import android.util.Log;
import android.util.Pair;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
+import com.google.protobuf.nano.MessageNano;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -368,7 +369,7 @@ public class DvrStorageManager implements BufferManager.StorageManager {
META_FILE_TYPE_CAPTION + ((i == 0) ? META_FILE_SUFFIX : (i + META_FILE_SUFFIX));
File file = new File(getBufferDir(), fileName);
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
- track.writeTo(out);
+ out.write(MessageNano.toByteArray(track));
} catch (Exception e) {
Log.e(TAG, "Fail to write caption info to files", e);
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
index df2cd2e6..d95642c2 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
@@ -20,18 +20,14 @@ import android.os.ConditionVariable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.util.Log;
-
import com.android.tv.tuner.exoplayer.MpegTsPlayer;
import com.android.tv.tuner.exoplayer.SampleExtractor;
-
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.util.Assertions;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -73,7 +69,7 @@ public class RecordingSampleBuffer
private final BufferManager mBufferManager;
private final PlaybackBufferListener mBufferListener;
private final @BufferReason int mBufferReason;
- private final SampleChunkIoHelper.Factory mSampleChunkIoHelperFactory;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
private int mTrackCount;
private boolean[] mTrackSelected;
@@ -102,42 +98,28 @@ public class RecordingSampleBuffer
};
/**
- * Factory for {@link RecordingSampleBuffer}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public RecordingSampleBuffer create(
- BufferManager bufferManager,
- PlaybackBufferListener bufferListener,
- boolean enableTrickplay,
- @BufferReason int bufferReason);
- }
-
- /**
* Creates {@link BufferManager.SampleBuffer} with cached I/O backed by physical storage (e.g.
* trickplay,recording,recorded-playback).
*
* @param bufferManager the manager of {@link SampleChunk}
* @param bufferListener the listener for buffer I/O event
* @param enableTrickplay {@code true} when trickplay should be enabled
+ * @param concurrentDvrPlaybackFlags
* @param bufferReason the reason for caching samples {@link BufferReason}
*/
- @AutoFactory(implementing = Factory.class)
public RecordingSampleBuffer(
BufferManager bufferManager,
PlaybackBufferListener bufferListener,
boolean enableTrickplay,
- @BufferReason int bufferReason,
- @Provided SampleChunkIoHelper.Factory sampleChunkIoHelperFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ @BufferReason int bufferReason) {
mBufferManager = bufferManager;
mBufferListener = bufferListener;
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
if (bufferListener != null) {
bufferListener.onBufferStateChanged(enableTrickplay);
}
mBufferReason = bufferReason;
- mSampleChunkIoHelperFactory = sampleChunkIoHelperFactory;
}
@Override
@@ -150,8 +132,14 @@ public class RecordingSampleBuffer
mTrackSelected = new boolean[mTrackCount];
mReadSampleQueues = new ArrayList<>();
mSampleChunkIoHelper =
- mSampleChunkIoHelperFactory.create(
- ids, mediaFormats, mBufferReason, mBufferManager, mSamplePool, mIoCallback);
+ new SampleChunkIoHelper(
+ ids,
+ mediaFormats,
+ mBufferReason,
+ mBufferManager,
+ mSamplePool,
+ mIoCallback,
+ mConcurrentDvrPlaybackFlags);
for (int i = 0; i < mTrackCount; ++i) {
mReadSampleQueues.add(i, new SampleQueue(mSamplePool));
}
diff --git a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java b/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
index 82bf0df8..f4d3bf8e 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
@@ -24,17 +24,12 @@ import android.os.Message;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.flags.DvrFlags;
import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer.BufferReason;
-
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.util.MimeTypes;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -69,7 +64,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
private final BufferManager mBufferManager;
private final SamplePool mSamplePool;
private final IoCallback mIoCallback;
- private final DvrFlags mDvrFlags;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
private Handler mIoHandler;
private final ConcurrentLinkedQueue<SampleHolder> mReadSampleBuffers[];
@@ -118,22 +113,6 @@ public class SampleChunkIoHelper implements Handler.Callback {
}
/**
- * Factory for {@link SampleChunkIoHelper}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public SampleChunkIoHelper create(
- List<String> ids,
- List<MediaFormat> mediaFormats,
- @BufferReason int bufferReason,
- BufferManager bufferManager,
- SamplePool samplePool,
- IoCallback ioCallback);
- }
-
- /**
* Creates {@link SampleChunk} I/O handler.
*
* @param ids track names
@@ -142,8 +121,8 @@ public class SampleChunkIoHelper implements Handler.Callback {
* @param bufferManager manager of {@link SampleChunk} collections
* @param samplePool allocator for a sample
* @param ioCallback listeners for I/O events
+ * @param concurrentDvrPlaybackFlags
*/
- @AutoFactory(implementing = Factory.class)
public SampleChunkIoHelper(
List<String> ids,
List<MediaFormat> mediaFormats,
@@ -151,7 +130,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
BufferManager bufferManager,
SamplePool samplePool,
IoCallback ioCallback,
- @Provided DvrFlags dvrFlags) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags) {
mTrackCount = ids.size();
mIds = ids;
mMediaFormats = mediaFormats;
@@ -159,7 +138,7 @@ public class SampleChunkIoHelper implements Handler.Callback {
mBufferManager = bufferManager;
mSamplePool = samplePool;
mIoCallback = ioCallback;
- mDvrFlags = dvrFlags;
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
mReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount];
mHandlerReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount];
@@ -205,7 +184,9 @@ public class SampleChunkIoHelper implements Handler.Callback {
}
try {
- if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING && mTrackCount > 0) {
+ if (mConcurrentDvrPlaybackFlags.enabled()
+ && mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING
+ && mTrackCount > 0) {
// Saves meta information for recording.
List<BufferManager.TrackFormat> audios = new ArrayList<>(mTrackCount);
List<BufferManager.TrackFormat> videos = new ArrayList<>(mTrackCount);
@@ -213,14 +194,6 @@ public class SampleChunkIoHelper implements Handler.Callback {
android.media.MediaFormat format =
mMediaFormats.get(i).getFrameworkMediaFormatV16();
format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs);
- if (mDvrFlags.storeVideoAspectRatio() &&
- mMediaFormats.get(i).pixelWidthHeightRatio > 0) {
- // MediaFormats doesn't store aspect ratio so updating the width
- // to maintain aspect ratio.
- format.setInteger(android.media.MediaFormat.KEY_WIDTH,
- (int) (mMediaFormats.get(i).width *
- mMediaFormats.get(i).pixelWidthHeightRatio));
- }
if (MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) {
audios.add(new BufferManager.TrackFormat(mIds.get(i), format));
} else if (MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) {
@@ -329,14 +302,6 @@ public class SampleChunkIoHelper implements Handler.Callback {
android.media.MediaFormat format =
mMediaFormats.get(i).getFrameworkMediaFormatV16();
format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs);
- if (mDvrFlags.storeVideoAspectRatio() &&
- mMediaFormats.get(i).pixelWidthHeightRatio > 0) {
- // MediaFormats doesn't store aspect ratio so updating the width
- // to maintain aspect ratio.
- format.setInteger(android.media.MediaFormat.KEY_WIDTH,
- (int) (mMediaFormats.get(i).width *
- mMediaFormats.get(i).pixelWidthHeightRatio));
- }
if (MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) {
audios.add(new BufferManager.TrackFormat(mIds.get(i), format));
} else if (MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) {
@@ -419,7 +384,8 @@ public class SampleChunkIoHelper implements Handler.Callback {
private void doOpenWrite(int index) throws IOException {
boolean updateIndexFile =
- (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING)
+ mConcurrentDvrPlaybackFlags.enabled()
+ && (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING)
&& (MimeTypes.isVideo(mMediaFormats.get(index).mimeType)
|| MimeTypes.isAudio(mMediaFormats.get(index).mimeType));
@@ -460,10 +426,13 @@ public class SampleChunkIoHelper implements Handler.Callback {
SampleHolder sample = mReadIoStates[index].read();
if (sample != null) {
mHandlerReadSampleBuffers[index].offer(sample);
- mReadChunkOffset[index] = mReadIoStates[index].getOffset();
- mReadChunkPositionUs[index] = sample.timeUs;
+ if (mConcurrentDvrPlaybackFlags.enabled()) {
+ mReadChunkOffset[index] = mReadIoStates[index].getOffset();
+ mReadChunkPositionUs[index] = sample.timeUs;
+ }
} else {
- if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK) {
+ if (mConcurrentDvrPlaybackFlags.enabled()
+ && mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK) {
// Update Index, to load new Samples
updateIndex(index, mReadChunkOffset[index]);
}
@@ -516,7 +485,9 @@ public class SampleChunkIoHelper implements Handler.Callback {
: mWriteIoStates[params.index].getChunk();
int currentOffset = (int) mWriteIoStates[params.index].getOffset();
boolean updateIndexFile =
- (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING)
+ mConcurrentDvrPlaybackFlags.enabled()
+ && (mBufferReason
+ == RecordingSampleBuffer.BUFFER_REASON_RECORDING)
&& (MimeTypes.isVideo(mMediaFormats.get(index).mimeType)
|| MimeTypes.isAudio(
mMediaFormats.get(index).mimeType));
diff --git a/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java b/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java
index a71352f3..12039002 100644
--- a/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java
+++ b/tuner/src/com/android/tv/tuner/exoplayer2/VideoRendererExoV2.java
@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
+import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
import java.lang.reflect.Field;
@@ -47,8 +48,8 @@ public class VideoRendererExoV2 extends MediaCodecVideoRenderer {
private static final String SOFTWARE_DECODER_NAME_PREFIX = "OMX.google.";
private static final long ALLOWED_JOINING_TIME_MS = 5000;
private static final int DROPPED_FRAMES_NOTIFICATION_THRESHOLD = 10;
- // private static final int MIN_HD_HEIGHT = 720;
- private static Field sRenderedFirstFrameField;
+ private static final int MIN_HD_HEIGHT = 720;
+ private static Field sRenderedFirstFrameField;
private final boolean mIsSwCodecEnabled;
private boolean mCodecIsSwPreferred;
@@ -107,18 +108,16 @@ public class VideoRendererExoV2 extends MediaCodecVideoRenderer {
return decoderInfos;
}
- // TODO: Uncomment once ExoPlayer v2.10.0 is released [Internal ref: b/130625979].
- // @Override
- // protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
- // Format format = formatHolder.format;
- // mCodecIsSwPreferred =
- // MimeTypes.VIDEO_MPEG2.equals(format.sampleMimeType)
- // && format.height < MIN_HD_HEIGHT;
- // super.onInputFormatChanged(format);
- // }
+ @Override
+ protected void onInputFormatChanged(Format format) throws ExoPlaybackException {
+ mCodecIsSwPreferred =
+ MimeTypes.VIDEO_MPEG2.equals(format.sampleMimeType)
+ && format.height < MIN_HD_HEIGHT;
+ super.onInputFormatChanged(format);
+ }
- @Override
- protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
+ @Override
+ protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
super.onPositionReset(positionUs, joining);
// Disabling pre-rendering of the first frame in order to avoid a frozen picture when
// starting the playback. We do this only once, when the renderer is enabled at first, since
diff --git a/tuner/src/com/android/tv/tuner/features/TunerFeatures.java b/tuner/src/com/android/tv/tuner/features/TunerFeatures.java
index 6ee5aa8c..6033a3a6 100644
--- a/tuner/src/com/android/tv/tuner/features/TunerFeatures.java
+++ b/tuner/src/com/android/tv/tuner/features/TunerFeatures.java
@@ -19,9 +19,9 @@ package com.android.tv.tuner.features;
import static com.android.tv.common.feature.FeatureUtils.OFF;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.common.feature.DeveloperPreferenceFeature;
import com.android.tv.common.feature.Feature;
import com.android.tv.common.feature.Model;
+import com.android.tv.common.feature.PropertyFeature;
import com.android.tv.common.feature.Sdk;
/**
@@ -39,11 +39,10 @@ public class TunerFeatures extends CommonFeatures {
* <p>Prefer software based codec for SD channels.
*/
public static final Feature USE_SW_CODEC_FOR_SD =
- DeveloperPreferenceFeature.create(
+ PropertyFeature.create(
"use_sw_codec_for_sd",
- // On Nexus Player, SW codec is better than HW codec in terms of picture
- // quality.
- Model.NEXUS_PLAYER.isEnabled());
+ false
+ );
/**
* Does the TvProvider on the installed device allow systems inserts to the programs table.
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java
deleted file mode 100644
index 38610dd1..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunChannelScan.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.content.Context;
-import android.media.tv.TvContract;
-import android.os.ConditionVariable;
-import android.util.Log;
-import android.util.Xml;
-import com.android.tv.tuner.api.ChannelScanListener;
-import com.android.tv.tuner.data.TunerChannel;
-import com.android.tv.tuner.ts.EventDetector.EventListener;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.regex.Pattern;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/** A helper class to perform channel scan on HDHomeRun tuner. */
-public class HdHomeRunChannelScan {
- private static final String TAG = "HdHomeRunChannelScan";
- private static final boolean DEBUG = false;
-
- private static final String LINEUP_FILENAME = "lineup.xml";
- private static final String NAME_LINEUP = "Lineup";
- private static final String NAME_PROGRAM = "Program";
- private static final String NAME_GUIDE_NUMBER = "GuideNumber";
- private static final String NAME_GUIDE_NAME = "GuideName";
- private static final String NAME_HD = "HD";
- private static final String NAME_TAGS = "Tags";
- private static final String NAME_DRM = "DRM";
-
- private final Context mContext;
- private final ChannelScanListener mEventListener;
- private final HdHomeRunTunerHal mTunerHal;
- private int mProgramCount;
-
- public HdHomeRunChannelScan(
- Context context, EventListener eventListener, HdHomeRunTunerHal hal) {
- mContext = context;
- mEventListener = eventListener;
- mTunerHal = hal;
- }
-
- public void scan(ConditionVariable conditionStopped) {
- String urlString = "http://" + mTunerHal.getIpAddress() + "/" + LINEUP_FILENAME;
- if (DEBUG) Log.d(TAG, "Reading " + urlString);
- URL url;
- HttpURLConnection connection = null;
- InputStream inputStream;
- try {
- url = new URL(urlString);
- connection = (HttpURLConnection) url.openConnection();
- connection.setReadTimeout(HdHomeRunTunerHal.READ_TIMEOUT_MS_FOR_URLCONNECTION);
- connection.setConnectTimeout(HdHomeRunTunerHal.CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION);
- connection.setRequestMethod("GET");
- connection.setDoInput(true);
- connection.connect();
- inputStream = connection.getInputStream();
- } catch (IOException e) {
- Log.e(TAG, "Connection failed: " + urlString, e);
- if (connection != null) {
- connection.disconnect();
- }
- return;
- }
- if (conditionStopped.block(-1)) {
- try {
- inputStream.close();
- } catch (IOException e) {
- // Does nothing.
- }
- connection.disconnect();
- return;
- }
-
- XmlPullParser parser = Xml.newPullParser();
- try {
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- parser.setInput(inputStream, null);
- parser.nextTag();
- parser.require(XmlPullParser.START_TAG, null, NAME_LINEUP);
- while (parser.next() != XmlPullParser.END_TAG) {
- if (conditionStopped.block(-1)) {
- break;
- }
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- String name = parser.getName();
- // Starts by looking for the program tag
- if (name.equals(NAME_PROGRAM)) {
- readProgram(parser);
- } else {
- skip(parser);
- }
- }
- inputStream.close();
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Parse error", e);
- }
- connection.disconnect();
- mTunerHal.markAsScannedDevice(mContext);
- }
-
- private void readProgram(XmlPullParser parser) throws XmlPullParserException, IOException {
- parser.require(XmlPullParser.START_TAG, null, NAME_PROGRAM);
- String guideNumber = "";
- String guideName = "";
- String videoFormat = null;
- String tags = "";
- boolean recordingProhibited = false;
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- String name = parser.getName();
- if (name.equals(NAME_GUIDE_NUMBER)) {
- guideNumber = readText(parser, NAME_GUIDE_NUMBER);
- } else if (name.equals(NAME_GUIDE_NAME)) {
- guideName = readText(parser, NAME_GUIDE_NAME);
- } else if (name.equals(NAME_HD)) {
- videoFormat = TvContract.Channels.VIDEO_FORMAT_720P;
- skip(parser);
- } else if (name.equals(NAME_TAGS)) {
- tags = readText(parser, NAME_TAGS);
- } else if (name.equals(NAME_DRM)) {
- String drm = readText(parser, NAME_DRM);
- try {
- recordingProhibited = (Integer.parseInt(drm)) != 0;
- } catch (NumberFormatException e) {
- Log.e(TAG, "Load DRM property failed: illegal number: " + drm);
- // If DRM property is present, we treat it as copy-once or copy-never.
- recordingProhibited = true;
- }
- } else {
- skip(parser);
- }
- }
- if (!tags.isEmpty()) {
- // Skip encrypted channels since we don't know how to decrypt them.
- return;
- }
- int major;
- int minor = 0;
- final String separator = Character.toString(HdHomeRunTunerHal.VCHANNEL_SEPARATOR);
- if (guideNumber.contains(separator)) {
- String[] parts = guideNumber.split(Pattern.quote(separator));
- major = Integer.parseInt(parts[0]);
- minor = Integer.parseInt(parts[1]);
- } else {
- major = Integer.parseInt(guideNumber);
- }
- // Need to assign a unique program number (i.e. mProgramCount) to avoid being duplicated.
- mEventListener.onChannelDetected(
- TunerChannel.forNetwork(
- major, minor, mProgramCount++, guideName, recordingProhibited, videoFormat),
- true);
- }
-
- private String readText(XmlPullParser parser, String name)
- throws IOException, XmlPullParserException {
- String result = "";
- parser.require(XmlPullParser.START_TAG, null, name);
- if (parser.next() == XmlPullParser.TEXT) {
- result = parser.getText();
- parser.nextTag();
- }
- parser.require(XmlPullParser.END_TAG, null, name);
- if (DEBUG) Log.d(TAG, "<" + name + ">=" + result);
- return result;
- }
-
- private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- throw new IllegalStateException();
- }
- int depth = 1;
- while (depth != 0) {
- switch (parser.next()) {
- case XmlPullParser.END_TAG:
- depth--;
- break;
- case XmlPullParser.START_TAG:
- depth++;
- break;
- }
- }
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java
deleted file mode 100644
index ce7c5180..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunControlSocket.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.support.annotation.Nullable;
-import android.util.Log;
-import android.util.Pair;
-import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * A class to send/receive control commands and results to/from HDHomeRun devices via TCP sockets.
- * {@link #close()} method should be called after usage to close the TCP socket.
- */
-class HdHomeRunControlSocket implements AutoCloseable {
- private static final String TAG = "HdHomeRunControlSocket";
- private static final boolean DEBUG = false;
-
- private int mDesiredDeviceId;
- private int mDesiredDeviceIp;
- private int mActualDeviceId;
- private int mActualDeviceIp;
- private Socket mSocket;
-
- HdHomeRunControlSocket(int deviceId, int deviceIp) {
- mDesiredDeviceId = deviceId;
- mDesiredDeviceIp = deviceIp;
- mActualDeviceId = 0;
- mActualDeviceIp = 0;
- }
-
- /**
- * Gets control settings from HDHomeRun devices.
- *
- * @param name the name of the field whose value we want to get.
- */
- @Nullable
- String get(String name) {
- byte[] data = new byte[name.length() + 3];
- ByteBuffer buffer = ByteBuffer.wrap(data);
- buffer.put(HdHomeRunUtils.HDHOMERUN_TAG_GETSET_NAME);
- buffer.put((byte) (name.length() + 1));
- buffer.put(name.getBytes());
-
- // Send & Receive.
- byte[] result =
- sendAndReceive(
- data,
- HdHomeRunUtils.HDHOMERUN_TYPE_GETSET_REQUEST,
- HdHomeRunUtils.HDHOMERUN_CONTROL_RECEIVE_TIMEOUT_MS);
- if (result == null) {
- if (DEBUG) Log.d(TAG, "Cannot get result for " + name);
- return null;
- }
-
- // Response.
- buffer = ByteBuffer.wrap(result);
- while (true) {
- Pair<Byte, byte[]> tagAndValue = HdHomeRunUtils.readTaggedValue(buffer);
- if (tagAndValue == null) {
- break;
- }
- switch (tagAndValue.first) {
- case HdHomeRunUtils.HDHOMERUN_TAG_GETSET_VALUE:
- // Removes the 0 tail.
- return new String(
- Arrays.copyOfRange(
- tagAndValue.second, 0, tagAndValue.second.length - 1));
- case HdHomeRunUtils.HDHOMERUN_TAG_ERROR_MESSAGE:
- return null;
- }
- }
- return null;
- }
-
- /** Gets ID of HDHomeRun devices. */
- int getDeviceId() {
- if (!connectAndUpdateDeviceInfo()) {
- return 0;
- }
- return mActualDeviceId;
- }
-
- private boolean connectAndUpdateDeviceInfo() {
- if (mSocket != null) {
- return true;
- }
- if ((mDesiredDeviceId == 0) && (mDesiredDeviceIp == 0)) {
- if (DEBUG) Log.d(TAG, "Desired ID and IP cannot be both zero.");
- return false;
- }
- if (HdHomeRunUtils.isIpMulticast(mDesiredDeviceIp)) {
- if (DEBUG) Log.d(TAG, "IP cannot be multicast IP.");
- return false;
- }
-
- // Find device.
- List<HdHomeRunDiscoverDevice> result =
- HdHomeRunUtils.findHdHomeRunDevices(
- mDesiredDeviceIp,
- HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_WILDCARD,
- mDesiredDeviceId,
- 1);
- if (result.isEmpty()) {
- if (DEBUG) Log.d(TAG, "Cannot find device on: " + mDesiredDeviceIp);
- return false;
- }
- mActualDeviceIp = result.get(0).mIpAddress;
- mActualDeviceId = result.get(0).mDeviceId;
-
- // Create socket and initiate connection.
- mSocket = new Socket();
- try {
- mSocket.connect(
- new InetSocketAddress(
- HdHomeRunUtils.intToAddress(mActualDeviceIp),
- HdHomeRunUtils.HDHOMERUN_CONTROL_TCP_PORT),
- HdHomeRunUtils.HDHOMERUN_CONTROL_CONNECT_TIMEOUT_MS);
- } catch (IOException e) {
- if (DEBUG) Log.d(TAG, "Cannot connect to socket: " + mSocket);
- mSocket = null;
- return false;
- }
-
- // Success.
- Log.i(TAG, "Connected to socket: " + mSocket);
- return true;
- }
-
- private byte[] sendAndReceive(byte[] data, short type, int timeout) {
- byte[] sealedData = HdHomeRunUtils.sealFrame(data, type);
- for (int i = 0; i < 2; i++) {
- if (mSocket == null && !connectAndUpdateDeviceInfo()) {
- return null;
- }
- if (!send(sealedData)) {
- continue;
- }
- Pair<Short, byte[]> receivedData = receive(timeout);
- if (receivedData == null || receivedData.first == null) {
- continue;
- }
- if (receivedData.first != type + 1) {
- if (DEBUG) Log.d(TAG, "Returned type incorrect: " + receivedData.first);
- close();
- continue;
- }
- return receivedData.second;
- }
- return null;
- }
-
- private boolean send(byte[] data) {
- try {
- OutputStream out = mSocket.getOutputStream();
- mSocket.setSoTimeout(HdHomeRunUtils.HDHOMERUN_CONTROL_SEND_TIMEOUT_MS);
- out.write(data);
- } catch (IOException e) {
- if (DEBUG) Log.d(TAG, "Cannot send packet to socket: " + mSocket);
- close();
- return false;
- }
- return true;
- }
-
- private Pair<Short, byte[]> receive(int timeout) {
- byte[] receivedData = new byte[3074];
- try {
- InputStream input = mSocket.getInputStream();
- mSocket.setSoTimeout(timeout);
- int index = 0;
- long startTime = System.currentTimeMillis();
- while (System.currentTimeMillis() - startTime < timeout) {
- int length = receivedData.length - index;
- index += input.read(receivedData, index, length);
- Pair<Short, byte[]> result = HdHomeRunUtils.openFrame(receivedData, index);
- if (result != null) {
- if (result.first == HdHomeRunUtils.HDHOMERUN_TYPE_INVALID) {
- if (DEBUG) Log.d(TAG, "Returned type is invalid.");
- close();
- return null;
- }
- return result;
- }
- if (DEBUG) Log.d(TAG, "Received result is null!");
- }
- } catch (IOException e) {
- if (DEBUG) Log.d(TAG, "Cannot receive from socket: " + mSocket);
- close();
- }
- return null;
- }
-
- @Override
- public void close() {
- if (mSocket != null) {
- try {
- mSocket.close();
- } catch (IOException e) {
- // Do nothing
- }
- mSocket = null;
- }
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java
deleted file mode 100644
index dcf87cad..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDevice.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-/**
- * An HDHomeRun device detected on the network. This abstraction only contains network data
- * necessary to establish a connection with the device and does not represent a communication
- * channel with the device itself. Currently, we only support devices with HTTP streaming
- * functionality.
- */
-public class HdHomeRunDevice implements Parcelable {
- private int mIpAddress;
- private int mDeviceType;
- private int mDeviceId;
- private int mTunerIndex;
- private String mDeviceModel;
-
- /**
- * Creates {@code HdHomeRunDevice} object from a parcel.
- *
- * @param parcel The parcel to create {@code HdHomeRunDevice} object from.
- */
- public HdHomeRunDevice(Parcel parcel) {
- mIpAddress = parcel.readInt();
- mDeviceType = parcel.readInt();
- mDeviceId = parcel.readInt();
- mTunerIndex = parcel.readInt();
- mDeviceModel = parcel.readString();
- }
-
- /**
- * Creates {@code HdHomeRunDevice} object from IP address, device type, device ID and tuner
- * index.
- *
- * @param ipAddress The IP address to create {@code HdHomeRunDevice} object from.
- * @param deviceType The device type to create {@code HdHomeRunDevice} object from.
- * @param deviceId The device ID to create {@code HdHomeRunDevice} object from.
- * @param tunerIndex The tuner index to {@code HdHomeRunDevice} object from.
- */
- public HdHomeRunDevice(
- int ipAddress, int deviceType, int deviceId, int tunerIndex, String deviceModel) {
- mIpAddress = ipAddress;
- mDeviceType = deviceType;
- mDeviceId = deviceId;
- mTunerIndex = tunerIndex;
- mDeviceModel = deviceModel;
- }
-
- /**
- * Returns the IP address.
- *
- * @return the IP address of this homerun device.
- */
- public int getIpAddress() {
- return mIpAddress;
- }
-
- /**
- * Returns the device type.
- *
- * @return the type of device for this homerun device.
- */
- public int getDeviceType() {
- return mDeviceType;
- }
-
- /**
- * Returns the device ID.
- *
- * @return the device ID of this homerun device.
- */
- public int getDeviceId() {
- return mDeviceId;
- }
-
- /**
- * Returns the tuner index.
- *
- * @return the tuner index of this homerun device.
- */
- public int getTunerIndex() {
- return mTunerIndex;
- }
-
- /**
- * Returns the device model.
- *
- * @return the device model of this homerun device.
- */
- public String getDeviceModel() {
- return mDeviceModel;
- }
-
- @Override
- public String toString() {
- String ipAddress =
- ""
- + ((mIpAddress >>> 24) & 0xff)
- + "."
- + ((mIpAddress >>> 16) & 0xff)
- + "."
- + ((mIpAddress >>> 8) & 0xff)
- + "."
- + (mIpAddress & 0xff);
- return String.format("[%x-%d:%s]", mDeviceId, mTunerIndex, ipAddress);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mIpAddress);
- out.writeInt(mDeviceType);
- out.writeInt(mDeviceId);
- out.writeInt(mTunerIndex);
- out.writeString(mDeviceModel);
- }
-
- @Override
- public int hashCode() {
- int hash = 17;
- hash = hash * 31 + getIpAddress();
- hash = hash * 31 + getDeviceType();
- hash = hash * 31 + getDeviceId();
- hash = hash * 31 + getTunerIndex();
- return hash;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof HdHomeRunDevice)) {
- return false;
- }
- HdHomeRunDevice rhs = (HdHomeRunDevice) o;
- return rhs != null
- && getIpAddress() == rhs.getIpAddress()
- && getDeviceType() == rhs.getDeviceType()
- && getDeviceId() == rhs.getDeviceId()
- && getTunerIndex() == rhs.getTunerIndex()
- && TextUtils.equals(getDeviceModel(), rhs.getDeviceModel());
- }
-
- public static final Parcelable.Creator<HdHomeRunDevice> CREATOR =
- new Parcelable.Creator<HdHomeRunDevice>() {
-
- @Override
- public HdHomeRunDevice createFromParcel(Parcel in) {
- return new HdHomeRunDevice(in);
- }
-
- @Override
- public HdHomeRunDevice[] newArray(int size) {
- return new HdHomeRunDevice[size];
- }
- };
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java
deleted file mode 100644
index 85b3450e..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunDiscover.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.util.Pair;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-
-/** A class to discover HDHomeRun devices on the network with UDP broadcasting. */
-class HdHomeRunDiscover {
- private static final String TAG = "HdHomeRunDiscover";
- private static final boolean DEBUG = false;
-
- private static final int HDHOMERUN_DISCOVER_MAX_SOCK_COUNT = 16;
- private static final int HDHOMERUN_DISCOVER_RETRY_LIMIT = 2;
- private static final int HDHOMERUN_DISCOVER_TIMEOUT_MS = 500;
- private static final int HDHOMERUN_DISCOVER_RECEIVE_WAITE_TIME_MS = 10;
-
- private List<HdHomeRunDiscoverSocket> mSockets = new ArrayList<>();
-
- /** Creates a discover object. If cannot add a default socket, return {@code null}. */
- static HdHomeRunDiscover create() {
- HdHomeRunDiscover hdHomeRunDiscover = new HdHomeRunDiscover();
- // Create a routable socket (always first entry).
- if (!hdHomeRunDiscover.addSocket(0, 0)) {
- return null;
- }
- return hdHomeRunDiscover;
- }
-
- /** Closes and releases all sockets required by this discover object. */
- void close() {
- for (HdHomeRunDiscoverSocket discoverSocket : mSockets) {
- discoverSocket.close();
- }
- }
-
- /** Finds HDHomeRun devices. */
- @NonNull
- List<HdHomeRunDiscoverDevice> findDevices(
- int targetIp, int deviceType, int deviceId, int maxCount) {
- List<HdHomeRunDiscoverDevice> resultList = new ArrayList<>();
- resetLocalIpSockets();
- for (int retry = 0;
- retry < HDHOMERUN_DISCOVER_RETRY_LIMIT && resultList.isEmpty();
- retry++) {
- int localIpSent = send(targetIp, deviceType, deviceId);
- if (localIpSent == 0) {
- if (DEBUG) {
- Log.d(TAG, "Cannot send to target ip: " + HdHomeRunUtils.getIpString(targetIp));
- }
- continue;
- }
- long timeout = System.currentTimeMillis() + HDHOMERUN_DISCOVER_TIMEOUT_MS * localIpSent;
- while (System.currentTimeMillis() < timeout) {
- HdHomeRunDiscoverDevice result = new HdHomeRunDiscoverDevice();
- if (!receive(result)) {
- continue;
- }
- // Filter.
- if (deviceType != HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_WILDCARD
- && deviceType != result.mDeviceType) {
- continue;
- }
- if (deviceId != HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD
- && deviceId != result.mDeviceId) {
- continue;
- }
- if (isObsoleteDevice(deviceId)) {
- continue;
- }
- // Ensure not already in list.
- if (resultList.contains(result)) {
- continue;
- }
- // Add to list.
- resultList.add(result);
- if (resultList.size() >= maxCount) {
- break;
- }
- }
- }
- return resultList;
- }
-
- private boolean addSocket(int localIp, int subnetMask) {
- for (int i = 1; i < mSockets.size(); i++) {
- HdHomeRunDiscoverSocket discoverSocket = mSockets.get(i);
- if ((discoverSocket.mLocalIp == localIp)
- && (discoverSocket.mSubnetMask == subnetMask)) {
- discoverSocket.mDetected = true;
- return true;
- }
- }
- if (mSockets.size() >= HDHOMERUN_DISCOVER_MAX_SOCK_COUNT) {
- return false;
- }
- DatagramSocket socket;
- try {
- socket = new DatagramSocket(0, HdHomeRunUtils.intToAddress(localIp));
- socket.setBroadcast(true);
- } catch (IOException e) {
- if (DEBUG) Log.d(TAG, "Cannot create socket: " + HdHomeRunUtils.getIpString(localIp));
- return false;
- }
- // Write socket entry.
- mSockets.add(new HdHomeRunDiscoverSocket(socket, true, localIp, subnetMask));
- return true;
- }
-
- private void resetLocalIpSockets() {
- for (int i = 1; i < mSockets.size(); i++) {
- mSockets.get(i).mDetected = false;
- mSockets.get(i).mDiscoverPacketSent = false;
- }
- List<LocalIpInfo> ipInfoList = getLocalIpInfo(HDHOMERUN_DISCOVER_MAX_SOCK_COUNT);
- for (LocalIpInfo ipInfo : ipInfoList) {
- if (DEBUG) {
- Log.d(
- TAG,
- "Add local IP: "
- + HdHomeRunUtils.getIpString(ipInfo.mIpAddress)
- + ", "
- + HdHomeRunUtils.getIpString(ipInfo.mSubnetMask));
- }
- addSocket(ipInfo.mIpAddress, ipInfo.mSubnetMask);
- }
- Iterator<HdHomeRunDiscoverSocket> iterator = mSockets.iterator();
- while (iterator.hasNext()) {
- HdHomeRunDiscoverSocket discoverSocket = iterator.next();
- if (!discoverSocket.mDetected) {
- discoverSocket.close();
- iterator.remove();
- }
- }
- }
-
- private List<LocalIpInfo> getLocalIpInfo(int maxCount) {
- Enumeration<NetworkInterface> interfaces;
- try {
- interfaces = NetworkInterface.getNetworkInterfaces();
- } catch (SocketException e) {
- return Collections.emptyList();
- }
- List<LocalIpInfo> result = new ArrayList<>();
- while (interfaces.hasMoreElements()) {
- NetworkInterface networkInterface = interfaces.nextElement();
- for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
- InetAddress inetAddress = interfaceAddress.getAddress();
- if (!inetAddress.isAnyLocalAddress()
- && !inetAddress.isLinkLocalAddress()
- && !inetAddress.isLoopbackAddress()
- && !inetAddress.isMulticastAddress()) {
- LocalIpInfo localIpInfo = new LocalIpInfo();
- localIpInfo.mIpAddress = HdHomeRunUtils.addressToInt(inetAddress.getAddress());
- localIpInfo.mSubnetMask =
- (0x7fffffff >> (31 - interfaceAddress.getNetworkPrefixLength()));
- result.add(localIpInfo);
- if (result.size() >= maxCount) {
- return result;
- }
- }
- }
- }
- return result;
- }
-
- private int send(int targetIp, int deviceType, int deviceId) {
- return targetIp == 0
- ? sendWildcardIp(deviceType, deviceId)
- : sendTargetIp(targetIp, deviceType, deviceId);
- }
-
- private int sendWildcardIp(int deviceType, int deviceId) {
- int localIpSent = 0;
-
- // Send subnet broadcast using each local ip socket.
- // This will work with multiple separate 169.254.x.x interfaces.
- for (int i = 1; i < mSockets.size(); i++) {
- HdHomeRunDiscoverSocket discoverSocket = mSockets.get(i);
- int targetIp = discoverSocket.mLocalIp | ~discoverSocket.mSubnetMask;
- if (DEBUG) Log.d(TAG, "Send: " + HdHomeRunUtils.getIpString(targetIp));
- localIpSent += discoverSocket.send(targetIp, deviceType, deviceId) ? 1 : 0;
- }
- // If no local ip sockets then fall back to sending a global broadcast letting
- // the OS choose the interface.
- if (localIpSent == 0) {
- if (DEBUG) Log.d(TAG, "Send: " + HdHomeRunUtils.getIpString(0xFFFFFFFF));
- localIpSent = mSockets.get(0).send(0xFFFFFFFF, deviceType, deviceId) ? 1 : 0;
- }
- return localIpSent;
- }
-
- private int sendTargetIp(int targetIp, int deviceType, int deviceId) {
- int localIpSent = 0;
-
- // Send targeted packet from any local ip that is in the same subnet.
- // This will work with multiple separate 169.254.x.x interfaces.
- for (int i = 1; i < mSockets.size(); i++) {
- HdHomeRunDiscoverSocket discoverSocket = mSockets.get(i);
- if (discoverSocket.mSubnetMask == 0) {
- continue;
- }
- if ((targetIp & discoverSocket.mSubnetMask)
- != (discoverSocket.mLocalIp & discoverSocket.mSubnetMask)) {
- continue;
- }
- localIpSent += discoverSocket.send(targetIp, deviceType, deviceId) ? 1 : 0;
- }
- // If target IP does not match a local subnet then fall back to letting the OS choose
- // the gateway interface.
- if (localIpSent == 0) {
- localIpSent = mSockets.get(0).send(targetIp, deviceType, deviceId) ? 1 : 0;
- }
- return localIpSent;
- }
-
- private boolean receive(HdHomeRunDiscoverDevice result) {
- for (HdHomeRunDiscoverSocket discoverSocket : mSockets) {
- if (discoverSocket.mDiscoverPacketSent && discoverSocket.receive(result)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isObsoleteDevice(int deviceId) {
- switch (deviceId >> 20) {
- case 0x100: /* TECH-US/TECH3-US */
- return (deviceId < 0x10040000);
- case 0x120: /* TECH3-EU */
- return (deviceId < 0x12030000);
- case 0x101: /* HDHR-US */
- case 0x102: /* HDHR-T1-US */
- case 0x103: /* HDHR3-US */
- case 0x111: /* HDHR3-DT */
- case 0x121: /* HDHR-EU */
- case 0x122: /* HDHR3-EU */
- return true;
- default:
- return false;
- }
- }
-
- static class HdHomeRunDiscoverDevice {
- int mIpAddress;
- int mDeviceType;
- int mDeviceId;
- int mTunerCount;
- String mBaseUrl;
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof HdHomeRunDiscoverDevice) {
- HdHomeRunDiscoverDevice o = (HdHomeRunDiscoverDevice) other;
- return mIpAddress == o.mIpAddress
- && mDeviceType == o.mDeviceType
- && mDeviceId == o.mDeviceId;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int result = mIpAddress;
- result = 31 * result + mDeviceType;
- result = 31 * result + mDeviceId;
- return result;
- }
- }
-
- private static class HdHomeRunDiscoverSocket {
- DatagramSocket mSocket;
- boolean mDetected;
- boolean mDiscoverPacketSent;
- int mLocalIp;
- int mSubnetMask;
-
- private HdHomeRunDiscoverSocket(
- DatagramSocket socket, boolean detected, int localIp, int subnetMask) {
- mSocket = socket;
- mDetected = detected;
- mLocalIp = localIp;
- mSubnetMask = subnetMask;
- }
-
- private boolean send(int targetIp, int deviceType, int deviceId) {
- byte[] data = new byte[12];
- ByteBuffer buffer = ByteBuffer.wrap(data);
- buffer.put(HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_TYPE);
- buffer.put((byte) 4);
- buffer.putInt(deviceType);
- buffer.put(HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_ID);
- buffer.put((byte) 4);
- buffer.putInt(deviceId);
- data = HdHomeRunUtils.sealFrame(data, HdHomeRunUtils.HDHOMERUN_TYPE_DISCOVER_REQUEST);
- try {
- DatagramPacket packet =
- new DatagramPacket(
- data,
- data.length,
- HdHomeRunUtils.intToAddress(targetIp),
- HdHomeRunUtils.HDHOMERUN_DISCOVER_UDP_PORT);
- mSocket.send(packet);
- if (DEBUG) {
- Log.d(TAG, "Discover packet sent to: " + HdHomeRunUtils.getIpString(targetIp));
- }
- mDiscoverPacketSent = true;
- } catch (IOException e) {
- if (DEBUG) {
- Log.d(
- TAG,
- "Cannot send discover packet to socket("
- + HdHomeRunUtils.getIpString(mLocalIp)
- + ")");
- }
- mDiscoverPacketSent = false;
- }
- return mDiscoverPacketSent;
- }
-
- private boolean receive(HdHomeRunDiscoverDevice result) {
- DatagramPacket packet = new DatagramPacket(new byte[3074], 3074);
- try {
- mSocket.setSoTimeout(HDHOMERUN_DISCOVER_RECEIVE_WAITE_TIME_MS);
- mSocket.receive(packet);
- if (DEBUG) Log.d(TAG, "Received packet, size: " + packet.getLength());
- } catch (IOException e) {
- if (DEBUG) {
- Log.d(
- TAG,
- "Cannot receive from socket("
- + HdHomeRunUtils.getIpString(mLocalIp)
- + ")");
- }
- return false;
- }
-
- Pair<Short, byte[]> data =
- HdHomeRunUtils.openFrame(packet.getData(), packet.getLength());
- if (data == null
- || data.first == null
- || data.first != HdHomeRunUtils.HDHOMERUN_TYPE_DISCOVER_REPLY) {
- if (DEBUG) Log.d(TAG, "Ill-formed packet: " + Arrays.toString(packet.getData()));
- return false;
- }
- result.mIpAddress = HdHomeRunUtils.addressToInt(packet.getAddress().getAddress());
- if (DEBUG) {
- Log.d(TAG, "Get Device IP: " + HdHomeRunUtils.getIpString(result.mIpAddress));
- }
- ByteBuffer buffer = ByteBuffer.wrap(data.second);
- while (true) {
- Pair<Byte, byte[]> tagAndValue = HdHomeRunUtils.readTaggedValue(buffer);
- if (tagAndValue == null) {
- break;
- }
- switch (tagAndValue.first) {
- case HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_TYPE:
- if (tagAndValue.second.length != 4) {
- break;
- }
- result.mDeviceType = ByteBuffer.wrap(tagAndValue.second).getInt();
- if (DEBUG) Log.d(TAG, "Get Device Type: " + result.mDeviceType);
- break;
- case HdHomeRunUtils.HDHOMERUN_TAG_DEVICE_ID:
- if (tagAndValue.second.length != 4) {
- break;
- }
- result.mDeviceId = ByteBuffer.wrap(tagAndValue.second).getInt();
- if (DEBUG) Log.d(TAG, "Get Device ID: " + result.mDeviceId);
- break;
- case HdHomeRunUtils.HDHOMERUN_TAG_TUNER_COUNT:
- if (tagAndValue.second.length != 1) {
- break;
- }
- result.mTunerCount = tagAndValue.second[0];
- if (DEBUG) Log.d(TAG, "Get Tuner Count: " + result.mTunerCount);
- break;
- case HdHomeRunUtils.HDHOMERUN_TAG_BASE_URL:
- result.mBaseUrl = new String(tagAndValue.second);
- if (DEBUG) Log.d(TAG, "Get Base URL: " + result.mBaseUrl);
- break;
- default:
- break;
- }
- }
- // Fixup for old firmware.
- if (result.mTunerCount == 0) {
- switch (result.mDeviceId >> 20) {
- case 0x102:
- result.mTunerCount = 1;
- break;
- case 0x100:
- case 0x101:
- case 0x121:
- result.mTunerCount = 2;
- break;
- default:
- break;
- }
- }
- return true;
- }
-
- private void close() {
- if (mSocket != null) {
- mSocket.close();
- }
- }
- }
-
- private static class LocalIpInfo {
- int mIpAddress;
- int mSubnetMask;
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java
deleted file mode 100644
index 2928aba7..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunInterface.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-import android.util.Log;
-import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/** An interface class provides methods to access physical HDHomeRun devices. */
-@WorkerThread
-public class HdHomeRunInterface {
- private static final String TAG = "HdHomeRunInterface";
- private static final boolean DEBUG = false;
-
- private static final int FETCH_DEVICE_NAME_TRY_NUM = 2;
- private static final int MAX_DEVICES = 1;
- private static final boolean DISABLE_CABLE = false;
-
- /**
- * Scans for HDHomeRun devices on the network.
- *
- * @param deviceId The target device ID we want to find, scans for all available devices if
- * {@code null} or the given ID cannot be found.
- * @return A set of HDHomeRun devices
- */
- @NonNull
- public static Set<HdHomeRunDevice> scanDevices(Integer deviceId) {
- List<HdHomeRunDiscoverDevice> discoveredDevices = null;
- if (deviceId != null) {
- discoveredDevices =
- HdHomeRunUtils.findHdHomeRunDevices(
- 0, HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_TUNER, deviceId, 1);
- if (discoveredDevices.isEmpty()) {
- Log.i(TAG, "Can't find device with ID: " + deviceId);
- }
- }
- if (discoveredDevices == null || discoveredDevices.isEmpty()) {
- discoveredDevices =
- HdHomeRunUtils.findHdHomeRunDevices(
- 0,
- HdHomeRunUtils.HDHOMERUN_DEVICE_TYPE_TUNER,
- HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD,
- MAX_DEVICES);
- if (DEBUG) Log.d(TAG, "Found " + discoveredDevices.size() + " devices");
- }
- Set<HdHomeRunDevice> result = new HashSet<>();
- for (HdHomeRunDiscoverDevice discoveredDevice : discoveredDevices) {
- String model =
- fetchDeviceModel(discoveredDevice.mDeviceId, discoveredDevice.mIpAddress);
- if (model == null) {
- Log.e(TAG, "Fetching device model failed: " + discoveredDevice.mDeviceId);
- continue;
- } else if (DEBUG) {
- Log.d(TAG, "Fetch Device Model: " + model);
- }
- if (DISABLE_CABLE) {
- if (model != null && model.contains("cablecard")) {
- // filter out CableCARD devices
- continue;
- }
- }
- for (int i = 0; i < discoveredDevice.mTunerCount; i++) {
- result.add(
- new HdHomeRunDevice(
- discoveredDevice.mIpAddress,
- discoveredDevice.mDeviceType,
- discoveredDevice.mDeviceId,
- i,
- model));
- }
- }
- return result;
- }
-
- /**
- * Returns {@code true} if the given device IP, ID and tuner index is available for use.
- *
- * @param deviceId The target device ID, 0 denotes a wildcard match.
- * @param deviceIp The target device IP.
- * @param tunerIndex The target tuner index of the target device. This parameter is only
- * meaningful when the target device has multiple tuners.
- */
- public static boolean isDeviceAvailable(int deviceId, int deviceIp, int tunerIndex) {
- // TODO: check the lock state for the given tuner.
- if ((deviceId == 0) && (deviceIp == 0)) {
- return false;
- }
- if (HdHomeRunUtils.isIpMulticast(deviceIp)) {
- return false;
- }
- if ((deviceId == 0) || (deviceId == HdHomeRunUtils.HDHOMERUN_DEVICE_ID_WILDCARD)) {
- try (HdHomeRunControlSocket controlSock =
- new HdHomeRunControlSocket(deviceId, deviceIp)) {
- deviceId = controlSock.getDeviceId();
- }
- }
- return deviceId != 0;
- }
-
- @Nullable
- private static String fetchDeviceModel(int deviceId, int deviceIp) {
- for (int i = 0; i < FETCH_DEVICE_NAME_TRY_NUM; i++) {
- try (HdHomeRunControlSocket controlSock =
- new HdHomeRunControlSocket(deviceId, deviceIp)) {
- String model = controlSock.get("/sys/model");
- if (model != null) {
- return model;
- }
- }
- }
- return null;
- }
-
- private HdHomeRunInterface() {}
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.java
deleted file mode 100644
index 81682991..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHal.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.compat.TvInputConstantCompat;
-import com.android.tv.tuner.api.Tuner;
-import com.android.tv.tuner.data.TunerChannel;
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-
-/** Tuner implementation for HdHomeRun */
-public class HdHomeRunTunerHal implements Tuner {
- private static final String TAG = "HdHomeRunTunerHal";
- private static final boolean DEBUG = false;
-
- private static final String CABLECARD_MODEL = "cablecard";
- private static final String ATSC_MODEL = "atsc";
- private static final String DVBC_MODEL = "dvbc";
- private static final String DVBT_MODEL = "dvbt";
-
- private final HdHomeRunTunerManager mTunerManager;
- private HdHomeRunDevice mDevice;
- private BufferedInputStream mInputStream;
- private HttpURLConnection mConnection;
- private String mHttpConnectionAddress;
- private final Context mContext;
-
- @DeliverySystemType private int mDeliverySystemType = DELIVERY_SYSTEM_UNDEFINED;
-
- public static final char VCHANNEL_SEPARATOR = '.';
- public static final int CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION = 3000; // 3 sec
- public static final int READ_TIMEOUT_MS_FOR_URLCONNECTION = 10000; // 10 sec
-
- public HdHomeRunTunerHal(Context context) {
- mTunerManager = HdHomeRunTunerManager.getInstance();
- mContext = context;
- }
-
- @Override
- public boolean openFirstAvailable() {
- SoftPreconditions.checkState(mDevice == null);
- try {
- mDevice = mTunerManager.acquireDevice(mContext);
- if (mDevice != null) {
- if (mDeliverySystemType == DELIVERY_SYSTEM_UNDEFINED) {
- mDeliverySystemType = nativeGetDeliverySystemType(getDeviceId());
- }
- }
- return mDevice != null;
- } catch (Exception e) {
- Log.w(TAG, "Failed to open first available device", e);
- return false;
- }
- }
-
- @Override
- public boolean isDeviceOpen() {
- return mDevice != null;
- }
-
- @Override
- public boolean isReusable() {
- return false;
- }
-
- @Override
- public long getDeviceId() {
- return mDevice == null ? 0 : mDevice.getDeviceId();
- }
-
- @Override
- public void close() throws Exception {
- closeInputStreamAndDisconnect();
- if (mDevice != null) {
- mTunerManager.releaseDevice(mDevice);
- mDevice = null;
- }
- }
-
- @Override
- public synchronized boolean tune(
- int frequency, @ModulationType String modulation, String channelNumber) {
- if (DEBUG) {
- Log.d(
- TAG,
- "tune(frequency="
- + frequency
- + ", modulation="
- + modulation
- + ", channelNumber="
- + channelNumber
- + ")");
- }
- closeInputStreamAndDisconnect();
- if (TextUtils.isEmpty(channelNumber)) {
- return false;
- }
- channelNumber =
- channelNumber.replace(TunerChannel.CHANNEL_NUMBER_SEPARATOR, VCHANNEL_SEPARATOR);
- mHttpConnectionAddress = "http://" + getIpAddress() + ":5004/auto/v" + channelNumber;
- return connectAndOpenInputStream();
- }
-
- private boolean connectAndOpenInputStream() {
- URL url;
- try {
- url = new URL(mHttpConnectionAddress);
- } catch (MalformedURLException e) {
- Log.e(TAG, "Invalid address: " + mHttpConnectionAddress, e);
- return false;
- }
- URLConnection connection;
- try {
- connection = url.openConnection();
- connection.setConnectTimeout(CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION);
- connection.setReadTimeout(READ_TIMEOUT_MS_FOR_URLCONNECTION);
- if (connection instanceof HttpURLConnection) {
- mConnection = (HttpURLConnection) connection;
- }
- } catch (IOException e) {
- Log.e(TAG, "Connection failed: " + mHttpConnectionAddress, e);
- return false;
- }
- try {
- mInputStream = new BufferedInputStream(connection.getInputStream());
- } catch (IOException e) {
- closeInputStreamAndDisconnect();
- Log.e(TAG, "Failed to get input stream from " + mHttpConnectionAddress, e);
- return false;
- }
- if (DEBUG) Log.d(TAG, "tuning to " + mHttpConnectionAddress);
- return true;
- }
-
- @Override
- public synchronized boolean addPidFilter(int pid, @FilterType int filterType) {
- // no-op
- return true;
- }
-
- @Override
- public synchronized void stopTune() {
- closeInputStreamAndDisconnect();
- }
-
- @Override
- public synchronized int readTsStream(byte[] javaBuffer, int javaBufferSize) {
- if (mInputStream != null) {
- try {
- // Note: this call sometimes take more than 500ms, because the data is
- // streamed through network unlike connected tuner devices.
- return mInputStream.read(javaBuffer, 0, javaBufferSize);
- } catch (IOException e) {
- Log.e(TAG, "Failed to read stream", e);
- closeInputStreamAndDisconnect();
- }
- }
- if (connectAndOpenInputStream()) {
- Log.w(TAG, "Tuned by http connection again");
- } else {
- Log.e(TAG, "Tuned by http connection again failed");
- }
- return 0;
- }
-
- @Override
- public void setHasPendingTune(boolean hasPendingTune) {
- // no-op
- }
-
- protected int nativeGetDeliverySystemType(long deviceId) {
- String deviceModel = mDevice.getDeviceModel();
- if (SoftPreconditions.checkState(!TextUtils.isEmpty(deviceModel))) {
- if (deviceModel.contains(CABLECARD_MODEL) || deviceModel.contains(ATSC_MODEL)) {
- return DELIVERY_SYSTEM_ATSC;
- } else if (deviceModel.contains(DVBC_MODEL)) {
- return DELIVERY_SYSTEM_DVBC;
- } else if (deviceModel.contains(DVBT_MODEL)) {
- return DELIVERY_SYSTEM_DVBT;
- }
- }
- return DELIVERY_SYSTEM_UNDEFINED;
- }
-
- private void closeInputStreamAndDisconnect() {
- if (mInputStream != null) {
- try {
- mInputStream.close();
- } catch (IOException e) {
- Log.e(TAG, "Failed to close input stream", e);
- }
- mInputStream = null;
- }
- if (mConnection != null) {
- mConnection.disconnect();
- mConnection = null;
- }
- }
-
- /** Gets the number of tuners in a given HDHomeRun devices. */
- public static int getNumberOfDevices() {
- return HdHomeRunTunerManager.getInstance().getTunerCount();
- }
-
- /** Returns the IP address. */
- public String getIpAddress() {
- return HdHomeRunUtils.getIpString(mDevice.getIpAddress());
- }
-
- /**
- * Marks the device associated to this instance as a scanned device. Scanned device has higher
- * priority among multiple HDHomeRun devices.
- */
- public void markAsScannedDevice(Context context) {
- HdHomeRunTunerManager.markAsScannedDevice(context, mDevice);
- }
-
- @Override
- @DeliverySystemType
- public int getDeliverySystemType() {
- return Tuner.DELIVERY_SYSTEM_UNDEFINED;
- }
-
- @Override
- public int getSignalStrength() {
- return TvInputConstantCompat.SIGNAL_STRENGTH_NOT_USED;
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java
deleted file mode 100644
index 6f6b1864..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerHalFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.content.Context;
-import android.support.annotation.WorkerThread;
-import android.util.Pair;
-
-import com.android.tv.tuner.api.Tuner;
-import com.android.tv.tuner.api.TunerFactory;
-
-/** TunerHal factory that creates all built in tuner types. */
-public final class HdHomeRunTunerHalFactory implements TunerFactory {
- public static final TunerFactory INSTANCE = new HdHomeRunTunerHalFactory();
-
- private HdHomeRunTunerHalFactory() {}
- /**
- * Creates a TunerHal instance.
- *
- * @param context context for creating the TunerHal instance
- * @return the TunerHal instance
- */
- @Override
- @WorkerThread
- public synchronized Tuner createInstance(Context context) {
- Tuner tunerHal = null;
- if (tunerHal == null) {
- tunerHal = new HdHomeRunTunerHal(context);
- }
- return tunerHal.openFirstAvailable() ? tunerHal : null;
- }
-
- /**
- * Returns if tuner input service would use built-in tuners instead of USB tuners or network
- * tuners.
- */
- @Override
- public boolean useBuiltInTuner(Context context) {
- return false;
- }
-
- /** Gets the number of tuner devices currently present. */
- @Override
- @WorkerThread
- public Pair<Integer, Integer> getTunerTypeAndCount(Context context) {
- return Pair.create(Tuner.TUNER_TYPE_NETWORK, HdHomeRunTunerHal.getNumberOfDevices());
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java
deleted file mode 100644
index 9e3ea595..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunTunerManager.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.support.annotation.WorkerThread;
-import android.util.Log;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A class to manage tuner resources of HDHomeRun devices. It handles tuner resource acquisition and
- * release.
- */
-class HdHomeRunTunerManager {
- private static final String TAG = "HdHomeRunTunerManager";
- private static final boolean DEBUG = false;
-
- private static final String PREF_KEY_SCANNED_DEVICE_ID = "scanned_device_id";
-
- private static HdHomeRunTunerManager sInstance;
-
- private final Set<HdHomeRunDevice> mHdHomeRunDevices = new HashSet<>();
- private final Set<HdHomeRunDevice> mUsedDevices = new HashSet<>();
-
- private HdHomeRunTunerManager() {}
-
- /** Returns the instance of this manager. */
- public static synchronized HdHomeRunTunerManager getInstance() {
- if (sInstance == null) {
- sInstance = new HdHomeRunTunerManager();
- }
- return sInstance;
- }
-
- /** Returns number of tuners. */
- @WorkerThread
- synchronized int getTunerCount() {
- updateDevicesLocked(null);
- if (DEBUG) Log.d(TAG, "getTunerCount: " + mHdHomeRunDevices.size());
- return mHdHomeRunDevices.size();
- }
-
- /** Creates an HDHomeRun device. If there is no available one, returns {@code null}. */
- @WorkerThread
- synchronized HdHomeRunDevice acquireDevice(Context context) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- int scannedDeviceId = sp.getInt(PREF_KEY_SCANNED_DEVICE_ID, 0);
- updateDevicesLocked(scannedDeviceId == 0 ? null : scannedDeviceId);
- if (DEBUG) Log.d(TAG, "createDevice: device count = " + mHdHomeRunDevices.size());
- HdHomeRunDevice availableDevice = null;
- // Use the device used for scanning first since other devices might have different line-up.
- if (scannedDeviceId != 0) {
- for (HdHomeRunDevice device : mHdHomeRunDevices) {
- if (!mUsedDevices.contains(device) && scannedDeviceId == device.getDeviceId()) {
- if (!HdHomeRunInterface.isDeviceAvailable(
- device.getDeviceId(), device.getIpAddress(), device.getTunerIndex())) {
- if (DEBUG) Log.d(TAG, "Device not available: " + device);
- continue;
- }
- availableDevice = device;
- break;
- }
- }
- }
- if (availableDevice == null) {
- for (HdHomeRunDevice device : mHdHomeRunDevices) {
- if (!mUsedDevices.contains(device)) {
- if (!HdHomeRunInterface.isDeviceAvailable(
- device.getDeviceId(), device.getIpAddress(), device.getTunerIndex())) {
- if (DEBUG) Log.d(TAG, "Device not available: " + device);
- continue;
- }
- availableDevice = device;
- break;
- }
- }
- }
- if (availableDevice != null) {
- if (DEBUG) Log.d(TAG, "created device " + availableDevice);
- mUsedDevices.add(availableDevice);
- return availableDevice;
- }
- return null;
- }
-
- /** Releases a created device by {@link #acquireDevice(Context)}. */
- synchronized void releaseDevice(HdHomeRunDevice device) {
- if (DEBUG) Log.d(TAG, "releaseDevice: " + device);
- mUsedDevices.remove(device);
- }
-
- /**
- * Marks the device associated to this instance as a scanned device. Scanned device has higher
- * priority among multiple HDHomeRun devices.
- */
- static void markAsScannedDevice(Context context, HdHomeRunDevice device) {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- sp.edit().putInt(PREF_KEY_SCANNED_DEVICE_ID, device.getDeviceId()).apply();
- }
-
- private void updateDevicesLocked(Integer deviceId) {
- mHdHomeRunDevices.clear();
- mHdHomeRunDevices.addAll(HdHomeRunInterface.scanDevices(deviceId));
- }
-}
diff --git a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java b/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java
deleted file mode 100644
index 733fc96f..00000000
--- a/tuner/src/com/android/tv/tuner/hdhomerun/HdHomeRunUtils.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.hdhomerun;
-
-import android.support.annotation.NonNull;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.tv.tuner.hdhomerun.HdHomeRunDiscover.HdHomeRunDiscoverDevice;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.zip.CRC32;
-
-class HdHomeRunUtils {
- private static final String TAG = "HdHomeRunUtils";
- private static final boolean DEBUG = false;
-
- static final int HDHOMERUN_DEVICE_TYPE_WILDCARD = 0xFFFFFFFF;
- static final int HDHOMERUN_DEVICE_TYPE_TUNER = 0x00000001;
- static final int HDHOMERUN_DEVICE_ID_WILDCARD = 0xFFFFFFFF;
-
- static final int HDHOMERUN_DISCOVER_UDP_PORT = 65001;
- static final int HDHOMERUN_CONTROL_TCP_PORT = 65001;
-
- static final short HDHOMERUN_TYPE_INVALID = -1;
- static final short HDHOMERUN_TYPE_DISCOVER_REQUEST = 0x0002;
- static final short HDHOMERUN_TYPE_DISCOVER_REPLY = 0x0003;
- static final short HDHOMERUN_TYPE_GETSET_REQUEST = 0x0004;
- static final short HDHOMERUN_TYPE_GETSET_REPLY = 0x0005;
-
- static final byte HDHOMERUN_TAG_DEVICE_TYPE = 0x01;
- static final byte HDHOMERUN_TAG_DEVICE_ID = 0x02;
- static final byte HDHOMERUN_TAG_GETSET_NAME = 0x03;
- static final int HDHOMERUN_TAG_GETSET_VALUE = 0x04;
- static final int HDHOMERUN_TAG_ERROR_MESSAGE = 0x05;
- static final int HDHOMERUN_TAG_TUNER_COUNT = 0x10;
- static final int HDHOMERUN_TAG_BASE_URL = 0x2A;
-
- static final int HDHOMERUN_CONTROL_CONNECT_TIMEOUT_MS = 2500;
- static final int HDHOMERUN_CONTROL_SEND_TIMEOUT_MS = 2500;
- static final int HDHOMERUN_CONTROL_RECEIVE_TIMEOUT_MS = 2500;
-
- /**
- * Finds HDHomeRun devices with given IP, type, and ID.
- *
- * @param targetIp {@code 0} to find target devices with broadcasting.
- * @param deviceType The type of target devices.
- * @param deviceId The ID of target devices.
- * @param maxCount Maximum number of devices should be returned.
- */
- @NonNull
- static List<HdHomeRunDiscoverDevice> findHdHomeRunDevices(
- int targetIp, int deviceType, int deviceId, int maxCount) {
- if (isIpMulticast(targetIp)) {
- if (DEBUG) Log.d(TAG, "Target IP cannot be multicast IP.");
- return Collections.emptyList();
- }
- try {
- HdHomeRunDiscover ds = HdHomeRunDiscover.create();
- if (ds == null) {
- if (DEBUG) Log.d(TAG, "Cannot create discover object.");
- return Collections.emptyList();
- }
- List<HdHomeRunDiscoverDevice> result =
- ds.findDevices(targetIp, deviceType, deviceId, maxCount);
- ds.close();
- return result;
- } catch (Exception e) {
- Log.w(TAG, "Failed to find HdHomeRun Devices", e);
- return Collections.emptyList();
- }
- }
-
- /** Returns {@code true} if the given IP is a multi-cast IP. */
- static boolean isIpMulticast(long ip) {
- return (ip >= 0xE0000000) && (ip < 0xF0000000);
- }
-
- /** Translates a {@code byte[]} address to its integer representation. */
- static int addressToInt(byte[] address) {
- return ByteBuffer.wrap(address).order(ByteOrder.LITTLE_ENDIAN).getInt();
- }
-
- /** Translates an {@code int} address to a corresponding {@link InetAddress}. */
- static InetAddress intToAddress(int address) throws UnknownHostException {
- return InetAddress.getByAddress(
- ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(address).array());
- }
-
- /** Gets {@link String} representation of an {@code int} address. */
- static String getIpString(int ip) {
- return String.format(
- "%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff), (ip >> 16 & 0xff), (ip >> 24 & 0xff));
- }
-
- /**
- * Opens the packet returned from HDHomeRun devices to acquire the real content and verify it.
- */
- static Pair<Short, byte[]> openFrame(byte[] data, int length) {
- if (length < 4) {
- return null;
- }
- ByteBuffer buffer = ByteBuffer.wrap(data);
- short resultType = buffer.getShort();
- int dataLength = buffer.getShort() & 0xffff;
-
- if (dataLength + 8 > length) {
- // Not finished yet.
- return null;
- }
- byte[] result = new byte[dataLength];
- buffer.get(result);
- byte[] calculatedCrc = getCrcFromBytes(Arrays.copyOfRange(data, 0, dataLength + 4));
- byte[] packetCrc = new byte[4];
- buffer.get(packetCrc);
-
- if (!Arrays.equals(calculatedCrc, packetCrc)) {
- return Pair.create(HDHOMERUN_TYPE_INVALID, null);
- }
-
- return Pair.create(resultType, result);
- }
-
- /** Seals the contents in a packet to send to HDHomeRun devices. */
- static byte[] sealFrame(byte[] data, short frameType) {
- byte[] result = new byte[data.length + 8];
- ByteBuffer buffer = ByteBuffer.wrap(result);
- buffer.putShort(frameType);
- buffer.putShort((short) data.length);
- buffer.put(data);
- buffer.put(getCrcFromBytes(Arrays.copyOfRange(result, 0, data.length + 4)));
- return result;
- }
-
- /** Reads a (tag, value) pair from packets returned from HDHomeRun devices. */
- static Pair<Byte, byte[]> readTaggedValue(ByteBuffer buffer) {
- try {
- Byte tag = buffer.get();
- byte[] value = readVarLength(buffer);
- return Pair.create(tag, value);
- } catch (BufferUnderflowException e) {
- return null;
- }
- }
-
- private static byte[] readVarLength(ByteBuffer buffer) {
- short length;
- Byte lengthByte1 = buffer.get();
- if ((lengthByte1 & 0x80) != 0) {
- length = buffer.get();
- length = (short) ((length << 7) + (lengthByte1 & 0x7F));
- } else {
- length = lengthByte1;
- }
- byte[] result = new byte[length];
- buffer.get(result);
- return result;
- }
-
- private static byte[] getCrcFromBytes(byte[] data) {
- CRC32 crc32 = new CRC32();
- crc32.update(data);
- long crc = crc32.getValue();
- byte[] result = new byte[4];
- for (int offset = 0; offset < 4; offset++) {
- result[offset] = (byte) (crc & 0xFF);
- crc >>= 8;
- }
- return result;
- }
-
- private HdHomeRunUtils() {}
-}
diff --git a/tuner/src/com/android/tv/tuner/modules/TunerModule.java b/tuner/src/com/android/tv/tuner/modules/TunerModule.java
index ff86e09f..4843f383 100644
--- a/tuner/src/com/android/tv/tuner/modules/TunerModule.java
+++ b/tuner/src/com/android/tv/tuner/modules/TunerModule.java
@@ -15,86 +15,9 @@
*/
package com.android.tv.tuner.modules;
-import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractor;
-import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractorFactory;
-import com.android.tv.tuner.exoplayer.FileSampleExtractor;
-import com.android.tv.tuner.exoplayer.FileSampleExtractorFactory;
-import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder;
-import com.android.tv.tuner.exoplayer.MpegTsRendererBuilderFactory;
-import com.android.tv.tuner.exoplayer.MpegTsSampleExtractor;
-import com.android.tv.tuner.exoplayer.MpegTsSampleExtractorFactory;
-import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer;
-import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBufferFactory;
-import com.android.tv.tuner.exoplayer.buffer.SampleChunkIoHelper;
-import com.android.tv.tuner.exoplayer.buffer.SampleChunkIoHelperFactory;
import com.android.tv.tuner.source.TunerSourceModule;
-import com.android.tv.tuner.tvinput.TunerRecordingSessionFactoryImpl;
-import com.android.tv.tuner.tvinput.TunerRecordingSessionWorker;
-import com.android.tv.tuner.tvinput.TunerRecordingSessionWorkerFactory;
-import com.android.tv.tuner.tvinput.TunerSessionExoV2Factory;
-import com.android.tv.tuner.tvinput.TunerSessionV1Factory;
-import com.android.tv.tuner.tvinput.TunerSessionWorker;
-import com.android.tv.tuner.tvinput.TunerSessionWorkerExoV2;
-import com.android.tv.tuner.tvinput.TunerSessionWorkerExoV2Factory;
-import com.android.tv.tuner.tvinput.TunerSessionWorkerFactory;
-import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory;
-import com.android.tv.tuner.tvinput.factory.TunerSessionFactory;
-
-import dagger.Binds;
import dagger.Module;
-import dagger.Provides;
-
-import com.android.tv.common.flags.TunerFlags;
/** Dagger module for TV Tuners. */
@Module(includes = {TunerSingletonsModule.class, TunerSourceModule.class})
-public abstract class TunerModule {
-
- @Provides
- static TunerSessionFactory tunerSessionFactory(
- TunerFlags tunerFlags,
- TunerSessionV1Factory tunerSessionFactory,
- TunerSessionExoV2Factory tunerSessionExoV2Factory) {
- return tunerFlags.useExoplayerV2() ? tunerSessionExoV2Factory : tunerSessionFactory;
- }
-
- @Binds
- abstract TunerRecordingSessionWorker.Factory tunerRecordingSessionWorkerFactory(
- TunerRecordingSessionWorkerFactory tunerRecordingSessionWorkerFactory);
-
- @Binds
- abstract TunerSessionWorker.Factory tunerSessionWorkerFactory(
- TunerSessionWorkerFactory tunerSessionWorkerFactory);
-
- @Binds
- abstract TunerSessionWorkerExoV2.Factory tunerSessionWorkerExoV2Factory(
- TunerSessionWorkerExoV2Factory tunerSessionWorkerExoV2Factory);
-
- @Binds
- abstract TunerRecordingSessionFactory tunerRecordingSessionFactory(
- TunerRecordingSessionFactoryImpl impl);
-
- @Binds
- abstract MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory(
- MpegTsRendererBuilderFactory mpegTsRendererBuilderFactory);
-
- @Binds
- abstract MpegTsSampleExtractor.Factory mpegTsSampleExtractorFactory(
- MpegTsSampleExtractorFactory mpegTsSampleExtractorFactory);
-
- @Binds
- abstract FileSampleExtractor.Factory fileSampleExtractorFactory(
- FileSampleExtractorFactory fileSampleExtractorFactory);
-
- @Binds
- abstract RecordingSampleBuffer.Factory recordingSampleBufferFactory(
- RecordingSampleBufferFactory recordingSampleBufferFactory);
-
- @Binds
- abstract ExoPlayerSampleExtractor.Factory exoPlayerSampleExtractorFactory(
- ExoPlayerSampleExtractorFactory exoPlayerSampleExtractorFactory);
-
- @Binds
- abstract SampleChunkIoHelper.Factory sampleChunkIoHelperFactory(
- SampleChunkIoHelperFactory sampleChunkIoHelperFactory);
-}
+public class TunerModule {}
diff --git a/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java b/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java
index 05026907..44f689bf 100644
--- a/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java
+++ b/tuner/src/com/android/tv/tuner/setup/BaseTunerSetupActivity.java
@@ -75,14 +75,11 @@ public abstract class BaseTunerSetupActivity extends SetupActivity {
R.raw.ut_kr_cable_standard_center_frequencies_qam256,
R.raw.ut_kr_all,
R.raw.ut_kr_dev_cj_cable_center_frequencies_qam256,
+ R.raw.ut_euro_dvbt_all,
+ R.raw.ut_euro_dvbt_all,
R.raw.ut_euro_dvbt_all
- /* these two resource files are obsolete and removed, so comment them out
- R.raw.ut_euro_all,
- R.raw.ut_euro_all */
};
- protected final String mInputId;
-
protected ScanFragment mLastScanFragment;
protected Integer mTunerType;
protected boolean mNeedToShowPostalCodeFragment;
@@ -93,10 +90,6 @@ public abstract class BaseTunerSetupActivity extends SetupActivity {
private TunerHalCreator mTunerHalCreator;
- protected BaseTunerSetupActivity(String mInputId) {
- this.mInputId = mInputId;
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG) {
@@ -229,7 +222,6 @@ public abstract class BaseTunerSetupActivity extends SetupActivity {
args1.putInt(
ScanFragment.EXTRA_FOR_CHANNEL_SCAN_FILE, CHANNEL_MAP_SCAN_FILE[actionId]);
args1.putInt(KEY_TUNER_TYPE, mTunerType);
- args1.putString(ScanFragment.EXTRA_FOR_INPUT_ID, mInputId);
mLastScanFragment.setArguments(args1);
showFragment(mLastScanFragment, true);
return true;
diff --git a/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java b/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java
index 2e782705..43c584ed 100644
--- a/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java
+++ b/tuner/src/com/android/tv/tuner/setup/ChannelScanFileParser.java
@@ -56,7 +56,6 @@ public final class ChannelScanFileParser {
}
scanChannelList.add(
ScanChannel.forTuner(
- tokens[0],
Integer.parseInt(tokens[1]),
tokens[2],
tokens.length == 4 ? Integer.parseInt(tokens[3]) : null));
diff --git a/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java b/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
index db297426..ebe4e41e 100644
--- a/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
@@ -18,12 +18,14 @@ package com.android.tv.tuner.setup;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import androidx.leanback.widget.GuidanceStylist.Guidance;
-import androidx.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import com.android.tv.common.BuildConfig;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
import com.android.tv.tuner.R;
import java.util.List;
+import java.util.TimeZone;
/** A fragment for connection type selection. */
public class ConnectionTypeFragment extends SetupMultiPaneFragment {
@@ -65,6 +67,7 @@ public class ConnectionTypeFragment extends SetupMultiPaneFragment {
/** The content fragment of {@link ConnectionTypeFragment}. */
public static class ContentFragment extends SetupGuidedStepFragment {
+
@NonNull
@Override
public Guidance onCreateGuidance(Bundle savedInstanceState) {
diff --git a/tuner/src/com/android/tv/tuner/setup/LineupFragment.java b/tuner/src/com/android/tv/tuner/setup/LineupFragment.java
index 224237d9..41f755df 100644
--- a/tuner/src/com/android/tv/tuner/setup/LineupFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/LineupFragment.java
@@ -20,8 +20,8 @@ import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import androidx.leanback.widget.GuidanceStylist.Guidance;
-import androidx.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
import android.util.Log;
import android.view.View;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
diff --git a/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java b/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java
new file mode 100644
index 00000000..741edc78
--- /dev/null
+++ b/tuner/src/com/android/tv/tuner/setup/LiveTvTunerSetupActivity.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.tuner.setup;
+
+import android.app.FragmentManager;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.view.KeyEvent;
+import com.android.tv.common.util.PostalCodeUtils;
+import dagger.android.ContributesAndroidInjector;
+
+/** An activity that serves tuner setup process. */
+public class LiveTvTunerSetupActivity extends BaseTunerSetupActivity {
+ private static final String TAG = "LiveTvTunerSetupActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // TODO(shubang): use LocationFragment
+ if (checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ // No need to check the request result.
+ requestPermissions(
+ new String[] {android.Manifest.permission.ACCESS_COARSE_LOCATION},
+ PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
+ }
+ }
+
+ @Override
+ protected void executeGetTunerTypeAndCountAsyncTask() {
+ new AsyncTask<Void, Void, Integer>() {
+ @Override
+ protected Integer doInBackground(Void... arg0) {
+ return mTunerFactory.getTunerTypeAndCount(LiveTvTunerSetupActivity.this).first;
+ }
+
+ @Override
+ protected void onPostExecute(Integer result) {
+ if (!LiveTvTunerSetupActivity.this.isDestroyed()) {
+ mTunerType = result;
+ if (result == null) {
+ finish();
+ } else if (!mActivityStopped) {
+ showInitialFragment();
+ } else {
+ mPendingShowInitialFragment = true;
+ }
+ }
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ FragmentManager manager = getFragmentManager();
+ int count = manager.getBackStackEntryCount();
+ if (count > 0) {
+ String lastTag = manager.getBackStackEntryAt(count - 1).getName();
+ if (ScanResultFragment.class.getCanonicalName().equals(lastTag) && count >= 2) {
+ String secondLastTag = manager.getBackStackEntryAt(count - 2).getName();
+ if (ScanFragment.class.getCanonicalName().equals(secondLastTag)) {
+ // Pops fragment including ScanFragment.
+ manager.popBackStack(
+ secondLastTag, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ return true;
+ }
+ } else if (ScanFragment.class.getCanonicalName().equals(lastTag)) {
+ mLastScanFragment.finishScan(true);
+ return true;
+ }
+ }
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode == PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION) {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ try {
+ // Updating postal code takes time, therefore we should update postal code
+ // right after the permission is granted, so that the subsequent operations,
+ // especially EPG fetcher, could get the newly updated postal code.
+ PostalCodeUtils.updatePostalCode(this);
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ }
+ }
+
+ /**
+ * Exports {@link LiveTvTunerSetupActivity} for Dagger codegen to create the appropriate
+ * injector.
+ */
+ @dagger.Module
+ public abstract static class Module {
+ @ContributesAndroidInjector
+ abstract LiveTvTunerSetupActivity contributeLiveTvTunerSetupActivityInjector();
+ }
+}
diff --git a/tuner/src/com/android/tv/tuner/setup/LocationFragment.java b/tuner/src/com/android/tv/tuner/setup/LocationFragment.java
index f950405f..1234ae20 100644
--- a/tuner/src/com/android/tv/tuner/setup/LocationFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/LocationFragment.java
@@ -23,14 +23,16 @@ import android.location.Address;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
import android.util.Log;
-import androidx.leanback.widget.GuidanceStylist.Guidance;
-import androidx.leanback.widget.GuidedAction;
+
import com.android.tv.common.ui.setup.SetupActionHelper;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
import com.android.tv.common.util.LocationUtils;
import com.android.tv.tuner.R;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -38,7 +40,7 @@ import java.util.List;
/** A fragment shows the rationale of location permission */
public class LocationFragment extends SetupMultiPaneFragment {
private static final String TAG = "com.android.tv.tuner.setup.LocationFragment";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.LocationFragment";
public static final String KEY_POSTAL_CODE = "key_postal_code";
@@ -77,7 +79,8 @@ public class LocationFragment extends SetupMultiPaneFragment {
() -> {
synchronized (mPostalCodeLock) {
if (DEBUG) {
- Log.d(TAG, "get location timeout. mPostalCode=" + mPostalCode);
+ Log.d(TAG,
+ "get location timeout. mPostalCode=" + mPostalCode);
}
if (mPostalCode == null) {
// timeout. setup activity will get null postal code
@@ -118,7 +121,8 @@ public class LocationFragment extends SetupMultiPaneFragment {
.id(ACTION_GETTING_LOCATION)
.title(getString(R.string.location_choices_getting_location))
.focusable(false)
- .build());
+ .build()
+ );
}
@Override
@@ -143,8 +147,8 @@ public class LocationFragment extends SetupMultiPaneFragment {
}
@Override
- public void onRequestPermissionsResult(
- int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
diff --git a/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java b/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java
index f9ea1675..52247972 100644
--- a/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/PostalCodeFragment.java
@@ -18,9 +18,9 @@ package com.android.tv.tuner.setup;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import androidx.leanback.widget.GuidanceStylist.Guidance;
-import androidx.leanback.widget.GuidedAction;
-import androidx.leanback.widget.GuidedActionsStylist;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
import android.text.InputFilter;
import android.text.InputFilter.AllCaps;
import android.view.View;
diff --git a/tuner/src/com/android/tv/tuner/setup/ScanFragment.java b/tuner/src/com/android/tv/tuner/setup/ScanFragment.java
index 87a79e35..7d59284c 100644
--- a/tuner/src/com/android/tv/tuner/setup/ScanFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/ScanFragment.java
@@ -40,9 +40,11 @@ import com.android.tv.common.ui.setup.SetupFragment;
import com.android.tv.tuner.R;
import com.android.tv.tuner.api.ScanChannel;
import com.android.tv.tuner.api.Tuner;
-import com.android.tv.tuner.data.Channel.TunerType;
import com.android.tv.tuner.data.PsipData;
import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.data.nano.Channel;
+
+
import com.android.tv.tuner.prefs.TunerPreferences;
import com.android.tv.tuner.source.FileTsStreamer;
import com.android.tv.tuner.source.TsDataSource;
@@ -72,13 +74,7 @@ public class ScanFragment extends SetupFragment {
public static final int ACTION_FINISH = 2;
public static final String EXTRA_FOR_CHANNEL_SCAN_FILE = "scan_file_choice";
- public static final String EXTRA_FOR_INPUT_ID = "input_id";
public static final String KEY_CHANNEL_NUMBERS = "channel_numbers";
-
- // Allows adding audio-only channels (CJ music channel) for which VCT is not present.
- private static final boolean ADD_CJ_MUSIC_CHANNELS = false;
- private static final int CJ_MUSIC_CHANNEL_FREQUENCY = 585000000;
-
private static final long CHANNEL_SCAN_SHOW_DELAY_MS = 10000;
private static final long CHANNEL_SCAN_PERIOD_MS = 4000;
private static final long SHOW_PROGRESS_DIALOG_DELAY_MS = 300;
@@ -103,6 +99,8 @@ public class ScanFragment extends SetupFragment {
if (DEBUG) Log.d(TAG, "onCreateView");
View view = super.onCreateView(inflater, container, savedInstanceState);
mChannelNumbers = new ArrayList<>();
+ mChannelDataManager = new ChannelDataManager(getActivity().getApplicationContext());
+ mChannelDataManager.checkDataVersion(getActivity());
mAdapter = new ChannelAdapter();
mProgressBar = (ProgressBar) view.findViewById(R.id.tune_progress);
mScanningMessage = (TextView) view.findViewById(R.id.tune_description);
@@ -124,6 +122,8 @@ public class ScanFragment extends SetupFragment {
});
Bundle args = getArguments();
int tunerType = (args == null ? 0 : args.getInt(BaseTunerSetupActivity.KEY_TUNER_TYPE, 0));
+ // TODO: Handle the case when the fragment is restored.
+ startScan(args == null ? 0 : args.getInt(EXTRA_FOR_CHANNEL_SCAN_FILE, 0));
TextView scanTitleView = (TextView) view.findViewById(R.id.tune_title);
switch (tunerType) {
case Tuner.TUNER_TYPE_USB:
@@ -139,28 +139,6 @@ public class ScanFragment extends SetupFragment {
}
@Override
- public void onStart() {
- super.onStart();
- Bundle args = getArguments();
- String inputId = args == null ? null : args.getString(ScanFragment.EXTRA_FOR_INPUT_ID);
- if (inputId == null) {
- Log.w(TAG, "No input ID, stopping setup activity.");
- getActivity().finish();
- }
-
- mChannelDataManager = new ChannelDataManager(getContext().getApplicationContext(), inputId);
- mChannelDataManager.checkDataVersion(getActivity());
- }
-
- @Override
- public void onStop() {
- if (mChannelDataManager != null) {
- mChannelDataManager.release();
- }
- super.onStop();
- }
-
- @Override
protected int getLayoutResourceId() {
return R.layout.ut_channel_scan;
}
@@ -176,13 +154,6 @@ public class ScanFragment extends SetupFragment {
}
@Override
- public void onResume() {
- Bundle args = getArguments();
- startScan(args == null ? 0 : args.getInt(EXTRA_FOR_CHANNEL_SCAN_FILE, 0));
- super.onResume();
- }
-
- @Override
public void onPause() {
Log.d(TAG, "onPause");
if (mChannelScanTask != null) {
@@ -279,7 +250,6 @@ public class ScanFragment extends SetupFragment {
private final Activity mActivity;
private final int mChannelMapId;
-// AOSP_Comment_Out private final com.android.tv.tuner.hdhomerun.HdHomeRunTunerHal mNetworkTuner;
private final TsStreamer mScanTsStreamer;
private final TsStreamer mFileTsStreamer;
private final ConditionVariable mConditionStopped;
@@ -300,13 +270,6 @@ public class ScanFragment extends SetupFragment {
if (hal == null) {
throw new RuntimeException("Failed to open a DVB device");
}
- /* Begin_AOSP_Comment_Out
- if (hal instanceof com.android.tv.tuner.hdhomerun.HdHomeRunTunerHal) {
- mNetworkTuner = (com.android.tv.tuner.hdhomerun.HdHomeRunTunerHal) hal;
- } else {
- mNetworkTuner = null;
- }
- End_AOSP_Comment_Out */
mScanTsStreamer = new TunerTsStreamer(hal, this);
}
mFileTsStreamer = SCAN_LOCAL_STREAMS ? new FileTsStreamer(this, mActivity) : null;
@@ -351,18 +314,6 @@ public class ScanFragment extends SetupFragment {
@Override
protected Void doInBackground(Void... params) {
- /* Begin_AOSP_Comment_Out
- if (mNetworkTuner != null) {
- mChannelDataManager.notifyScanStarted();
- com.android.tv.tuner.hdhomerun.HdHomeRunChannelScan hdHomeRunChannelScan =
- new com.android.tv.tuner.hdhomerun.HdHomeRunChannelScan(
- mActivity.getApplicationContext(), this, mNetworkTuner);
- hdHomeRunChannelScan.scan(mConditionStopped);
- mChannelDataManager.notifyScanCompleted();
- publishProgress(MAX_PROGRESS);
- return null;
- }
- End_AOSP_Comment_Out */
mScanChannelList.clear();
if (SCAN_LOCAL_STREAMS) {
FileTsStreamer.addLocalStreamFiles(mScanChannelList);
@@ -425,10 +376,6 @@ public class ScanFragment extends SetupFragment {
e);
}
streamer.stopStream();
-
- if (ADD_CJ_MUSIC_CHANNELS) {
- addCjMusicChannel(frequency, modulation);
- }
addChannelsWithoutVct(scanChannel);
if (System.currentTimeMillis() > startMs + CHANNEL_SCAN_SHOW_DELAY_MS
&& !mChannelListVisible) {
@@ -447,24 +394,6 @@ public class ScanFragment extends SetupFragment {
if (DEBUG) Log.i(TAG, "Channel scan ended");
}
- private void addCjMusicChannel(int frequency, String modulation) {
- if (frequency == CJ_MUSIC_CHANNEL_FREQUENCY
- && mChannelMapId == R.raw.ut_kr_dev_cj_cable_center_frequencies_qam256) {
- List<TunerChannel> incompleteChannels =
- mScanTsStreamer instanceof TunerTsStreamer
- ? ((TunerTsStreamer) mScanTsStreamer).getMalFormedChannels()
- : new ArrayList<>();
- for (TunerChannel tunerChannel : incompleteChannels) {
- if ((tunerChannel.getVideoPid() == TunerChannel.INVALID_PID)
- && (tunerChannel.getAudioPid() != TunerChannel.INVALID_PID)) {
- tunerChannel.setFrequency(frequency);
- tunerChannel.setModulation(modulation);
- onChannelDetected(tunerChannel, true);
- }
- }
- }
- }
-
private void addChannelsWithoutVct(ScanChannel scanChannel) {
if (scanChannel.radioFrequencyNumber == null
|| !(mScanTsStreamer instanceof TunerTsStreamer)) {
@@ -474,7 +403,6 @@ public class ScanFragment extends SetupFragment {
((TunerTsStreamer) mScanTsStreamer).getMalFormedChannels()) {
if ((tunerChannel.getVideoPid() != TunerChannel.INVALID_PID)
&& (tunerChannel.getAudioPid() != TunerChannel.INVALID_PID)) {
- tunerChannel.setDeliverySystemType(scanChannel.deliverySystemType);
tunerChannel.setFrequency(scanChannel.frequency);
tunerChannel.setModulation(scanChannel.modulation);
tunerChannel.setShortName(
@@ -492,9 +420,9 @@ public class ScanFragment extends SetupFragment {
private TsStreamer getStreamer(int type) {
switch (type) {
- case TunerType.TYPE_TUNER_VALUE:
+ case Channel.TunerType.TYPE_TUNER:
return mScanTsStreamer;
- case TunerType.TYPE_FILE_VALUE:
+ case Channel.TunerType.TYPE_FILE:
return mFileTsStreamer;
default:
return null;
diff --git a/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java b/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java
index 01bcc9f2..bd3f9ad9 100644
--- a/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/ScanResultFragment.java
@@ -20,8 +20,8 @@ import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import androidx.leanback.widget.GuidanceStylist.Guidance;
-import androidx.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
import com.android.tv.tuner.R;
diff --git a/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java b/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java
index dfa994b6..2a414df7 100644
--- a/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java
+++ b/tuner/src/com/android/tv/tuner/setup/WelcomeFragment.java
@@ -19,8 +19,8 @@ package com.android.tv.tuner.setup;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import androidx.leanback.widget.GuidanceStylist.Guidance;
-import androidx.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
import com.android.tv.tuner.R;
diff --git a/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java b/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java
index dfe9005b..48b17dcb 100644
--- a/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java
+++ b/tuner/src/com/android/tv/tuner/singletons/TunerSingletons.java
@@ -18,17 +18,4 @@ package com.android.tv.tuner.singletons;
import com.android.tv.common.singletons.HasTvInputId;
/** Singletons used in tuner applications */
-public interface TunerSingletons extends HasTvInputId {
-
- /*
- * Do not add any new methods here.
- *
- * To move a getter to Injection.
- * 1. Make a type injectable @Singleton.
- * 2. Mark the getter here as deprecated.
- * 3. Lazily inject the object in TvApplication.
- * 4. Move easy usages of getters to injection instead.
- * 5. Delete the method when all usages are migrated.
- */
-
-}
+public interface TunerSingletons extends HasTvInputId {}
diff --git a/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java b/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java
index 5ee897bb..85932c8c 100644
--- a/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java
+++ b/tuner/src/com/android/tv/tuner/source/FileSourceEventDetector.java
@@ -24,9 +24,9 @@ import com.android.tv.tuner.data.PsiData.PmtItem;
import com.android.tv.tuner.data.PsipData.EitItem;
import com.android.tv.tuner.data.PsipData.SdtItem;
import com.android.tv.tuner.data.PsipData.VctItem;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.ts.EventDetector.EventListener;
import com.android.tv.tuner.ts.TsParser;
import java.util.ArrayList;
diff --git a/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java b/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java
index 15f3458a..99d37e39 100644
--- a/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java
+++ b/tuner/src/com/android/tv/tuner/source/FileTsStreamer.java
@@ -17,9 +17,7 @@
package com.android.tv.tuner.source;
import android.content.Context;
-import android.net.Uri;
import android.os.Environment;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.util.SparseBooleanArray;
import com.android.tv.common.SoftPreconditions;
@@ -28,8 +26,8 @@ import com.android.tv.tuner.data.TunerChannel;
import com.android.tv.tuner.features.TunerFeatures;
import com.android.tv.tuner.ts.EventDetector.EventListener;
import com.android.tv.tuner.ts.TsParser;
-import com.google.android.exoplayer2.upstream.DataSpec;
-import com.google.android.exoplayer2.upstream.TransferListener;
+import com.google.android.exoplayer.C;
+import com.google.android.exoplayer.upstream.DataSpec;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -73,7 +71,6 @@ public class FileTsStreamer implements TsStreamer {
public static class FileDataSource extends TsDataSource {
private final FileTsStreamer mTsStreamer;
private final AtomicLong mLastReadPosition = new AtomicLong(0);
- private Uri mUri;
private long mStartBufferedPosition;
private FileDataSource(FileTsStreamer tsStreamer) {
@@ -99,10 +96,9 @@ public class FileTsStreamer implements TsStreamer {
}
@Override
- public long open(DataSpec dataSpec) {
- mUri = dataSpec.uri;
+ public long open(DataSpec dataSpec) throws IOException {
mLastReadPosition.set(0);
- return com.google.android.exoplayer2.C.LENGTH_UNSET;
+ return C.LENGTH_UNBOUNDED;
}
@Override
@@ -121,19 +117,6 @@ public class FileTsStreamer implements TsStreamer {
}
return ret;
}
-
- // ExoPlayer V2 DataSource implementation.
-
- @Override
- public void addTransferListener(TransferListener transferListener) {
- // TODO: Implement to support metrics collection.
- }
-
- @Nullable
- @Override
- public Uri getUri() {
- return mUri;
- }
}
/**
diff --git a/tuner/src/com/android/tv/tuner/source/TsDataSource.java b/tuner/src/com/android/tv/tuner/source/TsDataSource.java
index 18f4458b..cf3c25d9 100644
--- a/tuner/src/com/android/tv/tuner/source/TsDataSource.java
+++ b/tuner/src/com/android/tv/tuner/source/TsDataSource.java
@@ -17,7 +17,7 @@
package com.android.tv.tuner.source;
import com.android.tv.common.compat.TvInputConstantCompat;
-import com.google.android.exoplayer2.upstream.DataSource;
+import com.google.android.exoplayer.upstream.DataSource;
/** {@link DataSource} for MPEG-TS stream, which will be used by {@link TsExtractor}. */
public abstract class TsDataSource implements DataSource {
diff --git a/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java b/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java
index 3c00b5cc..28756a93 100644
--- a/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java
+++ b/tuner/src/com/android/tv/tuner/source/TsDataSourceManager.java
@@ -19,8 +19,8 @@ package com.android.tv.tuner.source;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import com.android.tv.tuner.api.Tuner;
-import com.android.tv.tuner.data.Channel;
import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.data.nano.Channel;
import com.android.tv.tuner.ts.EventDetector.EventListener;
import com.google.auto.factory.AutoFactory;
import com.google.auto.factory.Provided;
diff --git a/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java b/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java
index 19058c8a..9e68c910 100644
--- a/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java
+++ b/tuner/src/com/android/tv/tuner/source/TunerTsStreamer.java
@@ -17,11 +17,8 @@
package com.android.tv.tuner.source;
import android.content.Context;
-import android.net.Uri;
-import android.support.annotation.Nullable;
import android.util.Log;
import android.util.Pair;
-
import com.android.tv.common.SoftPreconditions;
import com.android.tv.tuner.api.ScanChannel;
import com.android.tv.tuner.api.Tuner;
@@ -29,10 +26,8 @@ import com.android.tv.tuner.data.TunerChannel;
import com.android.tv.tuner.prefs.TunerPreferences;
import com.android.tv.tuner.ts.EventDetector;
import com.android.tv.tuner.ts.EventDetector.EventListener;
-
-import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.upstream.DataSpec;
-import com.google.android.exoplayer2.upstream.TransferListener;
+import com.google.android.exoplayer.C;
+import com.google.android.exoplayer.upstream.DataSpec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -71,7 +66,6 @@ public class TunerTsStreamer implements TsStreamer {
private final TunerTsStreamer mTsStreamer;
private final AtomicLong mLastReadPosition = new AtomicLong(0);
private long mStartBufferedPosition;
- private Uri mUri;
private TunerDataSource(TunerTsStreamer tsStreamer) {
mTsStreamer = tsStreamer;
@@ -96,16 +90,13 @@ public class TunerTsStreamer implements TsStreamer {
}
@Override
- public long open(DataSpec dataSpec) {
- mUri = dataSpec.uri;
+ public long open(DataSpec dataSpec) throws IOException {
mLastReadPosition.set(0);
- return C.LENGTH_UNSET;
+ return C.LENGTH_UNBOUNDED;
}
@Override
- public void close() {
- mUri = null;
- }
+ public void close() {}
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
@@ -135,18 +126,6 @@ public class TunerTsStreamer implements TsStreamer {
public int getSignalStrength() {
return mTsStreamer.getSignalStrength();
}
-
- @Override
- public void addTransferListener(TransferListener transferListener) {
- // TODO: Implement to support metrics collection.
- }
-
- @Nullable
- @Override
- public Uri getUri() {
- return mUri;
- }
-
}
/**
* Creates {@link TsStreamer} for playing or recording the specified channel.
@@ -173,8 +152,7 @@ public class TunerTsStreamer implements TsStreamer {
@Override
public boolean startStream(TunerChannel channel) {
if (mTunerHal.tune(
- channel.getDeliverySystemType().getNumber(), channel.getFrequency(),
- channel.getModulation(), channel.getDisplayNumber(false))) {
+ channel.getFrequency(), channel.getModulation(), channel.getDisplayNumber(false))) {
if (channel.hasVideo()) {
mTunerHal.addPidFilter(channel.getVideoPid(), Tuner.FILTER_TYPE_VIDEO);
}
@@ -192,7 +170,6 @@ public class TunerTsStreamer implements TsStreamer {
mTunerHal.addPidFilter(channel.getPcrPid(), Tuner.FILTER_TYPE_PCR);
if (mEventDetector != null) {
mEventDetector.startDetecting(
- channel.getDeliverySystemType(),
channel.getFrequency(),
channel.getModulation(),
channel.getProgramNumber());
@@ -222,11 +199,9 @@ public class TunerTsStreamer implements TsStreamer {
@Override
public boolean startStream(ScanChannel channel) {
- if (mTunerHal.tune(channel.deliverySystemType.getNumber(), channel.frequency,
- channel.modulation, null)) {
+ if (mTunerHal.tune(channel.frequency, channel.modulation, null)) {
mEventDetector.startDetecting(
- channel.deliverySystemType, channel.frequency, channel.modulation,
- EventDetector.ALL_PROGRAM_NUMBERS);
+ channel.frequency, channel.modulation, EventDetector.ALL_PROGRAM_NUMBERS);
synchronized (mCircularBufferMonitor) {
if (mStreaming) {
Log.w(TAG, "Streaming should be stopped before start streaming");
@@ -320,7 +295,7 @@ public class TunerTsStreamer implements TsStreamer {
public void registerListener(EventListener listener) {
if (mEventDetector != null && listener != null) {
synchronized (mEventListenerActions) {
- mEventListenerActions.add(Pair.create(listener, true));
+ mEventListenerActions.add(new Pair<>(listener, true));
}
}
}
diff --git a/tuner/src/com/android/tv/tuner/ts/EventDetector.java b/tuner/src/com/android/tv/tuner/ts/EventDetector.java
index 3a2d835e..6d1fc277 100644
--- a/tuner/src/com/android/tv/tuner/ts/EventDetector.java
+++ b/tuner/src/com/android/tv/tuner/ts/EventDetector.java
@@ -20,13 +20,12 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.tv.tuner.api.Tuner;
-import com.android.tv.tuner.data.Channel.DeliverySystemType;
import com.android.tv.tuner.data.PsiData;
import com.android.tv.tuner.data.PsipData;
import com.android.tv.tuner.data.PsipData.EitItem;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -52,7 +51,6 @@ public class EventDetector {
private final SparseBooleanArray mVctCaptionTracksFound = new SparseBooleanArray();
private final SparseBooleanArray mEitCaptionTracksFound = new SparseBooleanArray();
private final List<EventListener> mEventListeners = new ArrayList<>();
- private DeliverySystemType mDeliverySystemType;
private int mFrequency;
private String mModulation;
private int mProgramNumber = ALL_PROGRAM_NUMBERS;
@@ -172,7 +170,6 @@ public class EventDetector {
}
tunerChannel.setAudioTracks(audioTracks);
tunerChannel.setCaptionTracks(captionTracks);
- tunerChannel.setDeliverySystemType(mDeliverySystemType);
tunerChannel.setFrequency(mFrequency);
tunerChannel.setModulation(mModulation);
mChannelMap.put(tunerChannel.getProgramNumber(), tunerChannel);
@@ -212,7 +209,6 @@ public class EventDetector {
int channelProgramNumber = channel.getServiceId();
tunerChannel.setAudioTracks(audioTracks);
tunerChannel.setCaptionTracks(captionTracks);
- tunerChannel.setDeliverySystemType(mDeliverySystemType);
tunerChannel.setFrequency(mFrequency);
tunerChannel.setModulation(mModulation);
mChannelMap.put(tunerChannel.getProgramNumber(), tunerChannel);
@@ -256,18 +252,10 @@ public class EventDetector {
private void reset() {
// TODO: Use TsParser.reset()
- int[] deliverySystemTypes = mTunerHal.getDeliverySystemTypes();
- boolean isDvbSignal = false;
- for (int i = 0; i < deliverySystemTypes.length; i++) {
- if (Tuner.isDvbDeliverySystem(deliverySystemTypes[i])) {
- isDvbSignal = true;
- break;
- }
- }
mTsParser =
new TsParser(
mTsOutputListener,
- isDvbSignal);
+ Tuner.isDvbDeliverySystem(mTunerHal.getDeliverySystemType()));
mPidSet.clear();
mVctProgramNumberSet.clear();
mSdtProgramNumberSet.clear();
@@ -284,10 +272,8 @@ public class EventDetector {
* @param programNumber The program number if this is for handling tune request. For scanning
* purpose, supply {@link #ALL_PROGRAM_NUMBERS}.
*/
- public void startDetecting(DeliverySystemType deliverySystemType, int frequency,
- String modulation, int programNumber) {
+ public void startDetecting(int frequency, String modulation, int programNumber) {
reset();
- mDeliverySystemType = deliverySystemType;
mFrequency = frequency;
mModulation = modulation;
mProgramNumber = programNumber;
diff --git a/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java b/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java
index e47162ad..d22b6399 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/BaseTunerTvInputService.java
@@ -21,26 +21,17 @@ import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.media.tv.TvInputService;
-import android.net.Uri;
import android.util.Log;
-
import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.tuner.source.TsDataSourceManager;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
-import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory;
import com.android.tv.tuner.tvinput.factory.TunerSessionFactory;
-
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.cache.RemovalListener;
-
import dagger.android.AndroidInjection;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
-
import javax.inject.Inject;
/** {@link BaseTunerTvInputService} serves TV channels coming from a tuner device. */
@@ -51,19 +42,10 @@ public class BaseTunerTvInputService extends TvInputService {
private static final int DVR_STORAGE_CLEANUP_JOB_ID = 100;
private final Set<Session> mTunerSessions = Collections.newSetFromMap(new WeakHashMap<>());
- private final Set<RecordingSession> mTunerRecordingSession =
- Collections.newSetFromMap(new WeakHashMap<>());
+ private ChannelDataManager mChannelDataManager;
+ @Inject ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
+ @Inject TsDataSourceManager.Factory mTsDataSourceManagerFactory;
@Inject TunerSessionFactory mTunerSessionFactory;
- @Inject TunerRecordingSessionFactory mTunerRecordingSessionFactory;
-
- LoadingCache<String, ChannelDataManager> mChannelDataManagers;
- RemovalListener<String, ChannelDataManager> mChannelDataManagerRemovalListener =
- notification -> {
- ChannelDataManager cdm = notification.getValue();
- if (cdm != null) {
- cdm.release();
- }
- };
@Override
public void onCreate() {
@@ -75,17 +57,7 @@ public class BaseTunerTvInputService extends TvInputService {
AndroidInjection.inject(this);
super.onCreate();
if (DEBUG) Log.d(TAG, "onCreate");
- mChannelDataManagers =
- CacheBuilder.newBuilder()
- .weakValues()
- .removalListener(mChannelDataManagerRemovalListener)
- .build(
- new CacheLoader<String, ChannelDataManager>() {
- @Override
- public ChannelDataManager load(String inputId) {
- return createChannelDataManager(inputId);
- }
- });
+ mChannelDataManager = new ChannelDataManager(getApplicationContext());
if (CommonFeatures.DVR.isEnabled(this)) {
JobScheduler jobScheduler =
(JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
@@ -105,24 +77,21 @@ public class BaseTunerTvInputService extends TvInputService {
}
}
- private ChannelDataManager createChannelDataManager(String inputId) {
- return new ChannelDataManager(getApplicationContext(), inputId);
- }
-
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy");
super.onDestroy();
- mChannelDataManagers.invalidateAll();
+ mChannelDataManager.release();
}
@Override
public RecordingSession onCreateRecordingSession(String inputId) {
- RecordingSession session =
- mTunerRecordingSessionFactory.create(
- inputId, this::onReleased, mChannelDataManagers.getUnchecked(inputId));
- mTunerRecordingSession.add(session);
- return session;
+ return new TunerRecordingSession(
+ this,
+ inputId,
+ mChannelDataManager,
+ mConcurrentDvrPlaybackFlags,
+ mTsDataSourceManagerFactory);
}
@Override
@@ -134,12 +103,8 @@ public class BaseTunerTvInputService extends TvInputService {
Log.d(TAG, "abort creating an session");
return null;
}
-
final Session session =
- mTunerSessionFactory.create(
- mChannelDataManagers.getUnchecked(inputId),
- this::onReleased,
- this::getRecordingUri);
+ mTunerSessionFactory.create(this, mChannelDataManager, this::onReleased);
mTunerSessions.add(session);
session.setOverlayViewEnabled(true);
return session;
@@ -150,22 +115,7 @@ public class BaseTunerTvInputService extends TvInputService {
}
}
- private Uri getRecordingUri(Uri channelUri) {
- for (RecordingSession session : mTunerRecordingSession) {
- TunerRecordingSession tunerSession = (TunerRecordingSession) session;
- if (tunerSession.getChannelUri().equals(channelUri)) {
- return tunerSession.getRecordingUri();
- }
- }
- return null;
- }
-
private void onReleased(Session session) {
mTunerSessions.remove(session);
- mChannelDataManagers.cleanUp();
- }
-
- private void onReleased(RecordingSession session) {
- mTunerRecordingSession.remove(session);
}
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
index ed61f71b..55616931 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
@@ -22,40 +22,33 @@ import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.util.Log;
-
import com.android.tv.common.compat.RecordingSessionCompat;
-import com.android.tv.common.dagger.annotations.ApplicationContext;
+import com.android.tv.tuner.source.TsDataSourceManager;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
-import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory;
-import com.android.tv.tuner.tvinput.factory.TunerRecordingSessionFactory.RecordingSessionReleasedCallback;
-
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
/** Processes DVR recordings, and deletes the previously recorded contents. */
-@AutoFactory(
- className = "TunerRecordingSessionFactoryImpl",
- implementing = TunerRecordingSessionFactory.class)
public class TunerRecordingSession extends RecordingSessionCompat {
private static final String TAG = "TunerRecordingSession";
private static final boolean DEBUG = false;
private final TunerRecordingSessionWorker mSessionWorker;
- private final RecordingSessionReleasedCallback mReleasedCallback;
- private Uri mChannelUri;
- private Uri mRecordingUri;
public TunerRecordingSession(
- @Provided @ApplicationContext Context context,
+ Context context,
String inputId,
- RecordingSessionReleasedCallback releasedCallback,
ChannelDataManager channelDataManager,
- @Provided TunerRecordingSessionWorker.Factory tunerRecordingSessionWorkerFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
super(context);
- mReleasedCallback = releasedCallback;
mSessionWorker =
- tunerRecordingSessionWorkerFactory.create(
- context, inputId, channelDataManager, this);
+ new TunerRecordingSessionWorker(
+ context,
+ inputId,
+ channelDataManager,
+ this,
+ concurrentDvrPlaybackFlags,
+ tsDataSourceManagerFactory);
}
// RecordingSession
@@ -76,7 +69,6 @@ public class TunerRecordingSession extends RecordingSessionCompat {
Log.d(TAG, "Requesting recording session release.");
}
mSessionWorker.release();
- mReleasedCallback.onReleased(this);
}
@MainThread
@@ -103,7 +95,6 @@ public class TunerRecordingSession extends RecordingSessionCompat {
if (DEBUG) {
Log.d(TAG, "Notifying recording session tuned.");
}
- mChannelUri = channelUri;
notifyTuned(channelUri);
}
@@ -121,7 +112,6 @@ public class TunerRecordingSession extends RecordingSessionCompat {
if (DEBUG) {
Log.d(TAG, "Notifying record successfully finished.");
}
- mRecordingUri = null;
notifyRecordingStopped(recordedProgramUri);
}
@@ -130,19 +120,4 @@ public class TunerRecordingSession extends RecordingSessionCompat {
Log.w(TAG, "Notifying recording error: " + reason);
notifyError(reason);
}
-
- public void onRecordingStatePartial(Uri recUri) {
- if (DEBUG) {
- Log.d(TAG, "Updating recording session state to Partial");
- }
- mRecordingUri = recUri;
- }
-
- public Uri getChannelUri() {
- return mChannelUri;
- }
-
- public Uri getRecordingUri() {
- return mRecordingUri;
- }
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
index 97cd0572..2c0c09a6 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
@@ -37,19 +37,17 @@ import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.Pair;
-
import androidx.tvprovider.media.tv.Program;
-
import com.android.tv.common.BaseApplication;
import com.android.tv.common.data.RecordedProgramState;
import com.android.tv.common.recording.RecordingCapability;
import com.android.tv.common.recording.RecordingStorageStatusManager;
import com.android.tv.common.util.CommonUtils;
+import com.android.tv.tuner.DvbDeviceAccessor;
import com.android.tv.tuner.data.PsipData;
import com.android.tv.tuner.data.PsipData.EitItem;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import com.android.tv.tuner.data.TunerChannel;
-import com.android.tv.tuner.dvb.DvbDeviceAccessor;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractor;
import com.android.tv.tuner.exoplayer.SampleExtractor;
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
@@ -59,11 +57,8 @@ import com.android.tv.tuner.source.TsDataSource;
import com.android.tv.tuner.source.TsDataSourceManager;
import com.android.tv.tuner.ts.EventDetector.EventListener;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
-
import com.google.android.exoplayer.C;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -147,6 +142,7 @@ public class TunerRecordingSessionWorker
private static final long CHANNEL_ID_NONE = -1;
private static final int MAX_TUNING_RETRY = 6;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
private final Context mContext;
private final ChannelDataManager mChannelDataManager;
@@ -172,31 +168,15 @@ public class TunerRecordingSessionWorker
private PsipData.EitItem mCurrenProgram;
private List<AtscCaptionTrack> mCaptionTracks;
private DvrStorageManager mDvrStorageManager;
- private final ExoPlayerSampleExtractor.Factory mExoPlayerSampleExtractorFactory;
- /**
- * Factory for {@link TunerRecordingSessionWorker}}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- TunerRecordingSessionWorker create(
- Context context,
- String inputId,
- ChannelDataManager dataManager,
- TunerRecordingSession session);
- }
-
- @AutoFactory(implementing = Factory.class)
public TunerRecordingSessionWorker(
Context context,
String inputId,
ChannelDataManager dataManager,
TunerRecordingSession session,
- @Provided ExoPlayerSampleExtractor.Factory exoPlayerSampleExtractorFactory,
- @Provided TsDataSourceManager.Factory tsDataSourceManagerFactory) {
- mExoPlayerSampleExtractorFactory = exoPlayerSampleExtractorFactory;
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
mRandom.setSeed(System.nanoTime());
mContext = context;
HandlerThread handlerThread = new HandlerThread(TAG);
@@ -237,7 +217,7 @@ public class TunerRecordingSessionWorker
if (mChannel == null || mChannel.compareTo(channel) != 0) {
return;
}
- mHandler.obtainMessage(MSG_UPDATE_CC_INFO, Pair.create(channel, items)).sendToTarget();
+ mHandler.obtainMessage(MSG_UPDATE_CC_INFO, new Pair<>(channel, items)).sendToTarget();
mChannelDataManager.notifyEventDetected(channel, items);
}
@@ -382,7 +362,7 @@ public class TunerRecordingSessionWorker
}
case MSG_UPDATE_PARTIAL_STATE:
{
- updateRecordedProgramStatePartial();
+ updateRecordedProgram(RecordedProgramState.PARTIAL, -1, -1);
return true;
}
}
@@ -476,30 +456,36 @@ public class TunerRecordingSessionWorker
mRecordStartTime = System.currentTimeMillis();
mDvrStorageManager = new DvrStorageManager(mStorageDir, true);
mRecorder =
- mExoPlayerSampleExtractorFactory.create(
- Uri.EMPTY, mTunerSource, new BufferManager(mDvrStorageManager), this, true);
+ new ExoPlayerSampleExtractor(
+ Uri.EMPTY,
+ mTunerSource,
+ new BufferManager(mDvrStorageManager),
+ this,
+ true,
+ mConcurrentDvrPlaybackFlags);
mRecorder.setOnCompletionListener(this, mHandler);
mProgramUri = programUri;
mSessionState = STATE_RECORDING;
mRecorderRunning = true;
- mRecordedProgramUri =
- insertRecordedProgram(
- getRecordedProgram(),
- mChannel.getChannelId(),
- Uri.fromFile(mStorageDir).toString(),
- calculateRecordingSizeInBytes(),
- mRecordStartTime,
- mRecordStartTime);
- if (mRecordedProgramUri == null) {
- new DeleteRecordingTask().execute(mStorageDir);
- mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
- Log.e(TAG, "Inserting a recording to DB failed");
- return false;
+ if (mConcurrentDvrPlaybackFlags.enabled()) {
+ mRecordedProgramUri =
+ insertRecordedProgram(
+ getRecordedProgram(),
+ mChannel.getChannelId(),
+ Uri.fromFile(mStorageDir).toString(),
+ calculateRecordingSizeInBytes(),
+ mRecordStartTime,
+ mRecordStartTime);
+ if (mRecordedProgramUri == null) {
+ new DeleteRecordingTask().execute(mStorageDir);
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.e(TAG, "Inserting a recording to DB failed");
+ return false;
+ }
+ mSession.onRecordingUri(mRecordedProgramUri.toString());
+ mHandler.sendEmptyMessageDelayed(
+ MSG_UPDATE_PARTIAL_STATE, MIN_PARTIAL_RECORDING_DURATION_MS);
}
- mSession.onRecordingUri(mRecordedProgramUri.toString());
- mHandler.sendEmptyMessageDelayed(
- MSG_UPDATE_PARTIAL_STATE, MIN_PARTIAL_RECORDING_DURATION_MS);
-
mHandler.sendEmptyMessage(MSG_PREPARE_RECODER);
mHandler.removeMessages(MSG_MONITOR_STORAGE_STATUS);
mHandler.sendEmptyMessageDelayed(MSG_MONITOR_STORAGE_STATUS, STORAGE_MONITOR_INTERVAL_MS);
@@ -606,7 +592,7 @@ public class TunerRecordingSessionWorker
if (checkRecordedProgramTable(COLUMN_SERIES_ID)) {
values.put(COLUMN_SERIES_ID, mSeriesId);
}
- if (checkRecordedProgramTable(COLUMN_STATE)) {
+ if (mConcurrentDvrPlaybackFlags.enabled() && checkRecordedProgramTable(COLUMN_STATE)) {
values.put(COLUMN_STATE, RecordedProgramState.STARTED.name());
}
if (program != null) {
@@ -616,24 +602,18 @@ public class TunerRecordingSessionWorker
.insert(TvContract.RecordedPrograms.CONTENT_URI, values);
}
- private void updateRecordedProgramStateFinished(long endTime, long totalBytes) {
+ private void updateRecordedProgram(RecordedProgramState state, long endTime, long totalBytes) {
ContentValues values = new ContentValues();
- values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, totalBytes);
- values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, endTime - mRecordStartTime);
- values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
if (checkRecordedProgramTable(COLUMN_STATE)) {
- values.put(COLUMN_STATE, RecordedProgramState.FINISHED.name());
+ values.put(COLUMN_STATE, state.name());
}
- mContext.getContentResolver().update(mRecordedProgramUri, values, null, null);
- }
-
- private void updateRecordedProgramStatePartial() {
- mSession.onRecordingStatePartial(mRecordedProgramUri);
- if (checkRecordedProgramTable(COLUMN_STATE)) {
- ContentValues values = new ContentValues();
- values.put(COLUMN_STATE, RecordedProgramState.PARTIAL.name());
- mContext.getContentResolver().update(mRecordedProgramUri, values, null, null);
+ if (state.equals(RecordedProgramState.FINISHED)) {
+ values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, totalBytes);
+ values.put(
+ RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, endTime - mRecordStartTime);
+ values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
}
+ mContext.getContentResolver().update(mRecordedProgramUri, values, null, null);
}
private void onRecordingResult(boolean success, long lastExtractedPositionUs) {
@@ -660,7 +640,25 @@ public class TunerRecordingSessionWorker
(lastExtractedPositionUs == C.UNKNOWN_TIME_US)
? System.currentTimeMillis()
: mRecordStartTime + lastExtractedPositionUs / 1000;
- updateRecordedProgramStateFinished(recordEndTime, calculateRecordingSizeInBytes());
+ if (!mConcurrentDvrPlaybackFlags.enabled()) {
+ mRecordedProgramUri =
+ insertRecordedProgram(
+ getRecordedProgram(),
+ mChannel.getChannelId(),
+ Uri.fromFile(mStorageDir).toString(),
+ calculateRecordingSizeInBytes(),
+ mRecordStartTime,
+ recordEndTime);
+ if (mRecordedProgramUri == null) {
+ new DeleteRecordingTask().execute(mStorageDir);
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.e(TAG, "Inserting a recording to DB failed");
+ return;
+ }
+ } else {
+ updateRecordedProgram(
+ RecordedProgramState.FINISHED, recordEndTime, calculateRecordingSizeInBytes());
+ }
mDvrStorageManager.writeCaptionInfoFiles(mCaptionTracks);
mSession.onRecordFinished(mRecordedProgramUri);
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java
index eb3a7d0c..fedb5f6b 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSession.java
@@ -27,24 +27,18 @@ import android.os.SystemClock;
import android.util.Log;
import android.view.Surface;
import android.view.View;
-
import com.android.tv.common.CommonPreferences.CommonPreferencesChangedListener;
import com.android.tv.common.compat.TisSessionCompat;
-import com.android.tv.common.dagger.annotations.ApplicationContext;
import com.android.tv.tuner.prefs.TunerPreferences;
+import com.android.tv.tuner.source.TsDataSourceManager;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
-import com.android.tv.tuner.tvinput.factory.TunerSessionFactory;
-import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionRecordingCallback;
import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionReleasedCallback;
-
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
/**
* Provides a tuner TV input session. Main tuner input functions are implemented in {@link
* TunerSessionWorker}.
*/
-@AutoFactory(className = "TunerSessionV1Factory", implementing = TunerSessionFactory.class)
public class TunerSession extends TisSessionCompat implements CommonPreferencesChangedListener {
private static final String TAG = "TunerSession";
@@ -53,26 +47,26 @@ public class TunerSession extends TisSessionCompat implements CommonPreferencesC
private final TunerSessionOverlay mTunerSessionOverlay;
private final TunerSessionWorker mSessionWorker;
private final SessionReleasedCallback mReleasedCallback;
- private final SessionRecordingCallback mRecordingCallback;
private boolean mPlayPaused;
private long mTuneStartTimestamp;
public TunerSession(
- @Provided @ApplicationContext Context context,
+ Context context,
ChannelDataManager channelDataManager,
SessionReleasedCallback releasedCallback,
- SessionRecordingCallback recordingCallback,
- @Provided TunerSessionWorker.Factory tunerSessionWorkerFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
super(context);
mReleasedCallback = releasedCallback;
- mRecordingCallback = recordingCallback;
mTunerSessionOverlay = new TunerSessionOverlay(context);
mSessionWorker =
- tunerSessionWorkerFactory.create(
+ new TunerSessionWorker(
context,
channelDataManager,
this,
- mTunerSessionOverlay);
+ mTunerSessionOverlay,
+ concurrentDvrPlaybackFlags,
+ tsDataSourceManagerFactory);
TunerPreferences.setCommonPreferencesChangedListener(this);
}
@@ -210,8 +204,4 @@ public class TunerSession extends TisSessionCompat implements CommonPreferencesC
public void onCommonPreferencesChanged() {
mSessionWorker.sendMessage(TunerSessionWorker.MSG_TUNER_PREFERENCES_CHANGED);
}
-
- public Uri getRecordingUri(Uri channelUri) {
- return mRecordingCallback.getRecordingUri(channelUri);
- }
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java
index 7ebb2b21..4eca44d6 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionExoV2.java
@@ -27,21 +27,15 @@ import android.os.SystemClock;
import android.util.Log;
import android.view.Surface;
import android.view.View;
-
import com.android.tv.common.CommonPreferences.CommonPreferencesChangedListener;
import com.android.tv.common.compat.TisSessionCompat;
-import com.android.tv.common.dagger.annotations.ApplicationContext;
import com.android.tv.tuner.prefs.TunerPreferences;
+import com.android.tv.tuner.source.TsDataSourceManager;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
-import com.android.tv.tuner.tvinput.factory.TunerSessionFactory;
-import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionRecordingCallback;
import com.android.tv.tuner.tvinput.factory.TunerSessionFactory.SessionReleasedCallback;
-
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
/** Provides a tuner TV input session. */
-@AutoFactory(implementing = TunerSessionFactory.class)
public class TunerSessionExoV2 extends TisSessionCompat
implements CommonPreferencesChangedListener {
@@ -51,26 +45,26 @@ public class TunerSessionExoV2 extends TisSessionCompat
private final TunerSessionOverlay mTunerSessionOverlay;
private final TunerSessionWorkerExoV2 mSessionWorker;
private final SessionReleasedCallback mReleasedCallback;
- private final SessionRecordingCallback mRecordingCallback;
private boolean mPlayPaused;
private long mTuneStartTimestamp;
public TunerSessionExoV2(
- @Provided @ApplicationContext Context context,
+ Context context,
ChannelDataManager channelDataManager,
SessionReleasedCallback releasedCallback,
- SessionRecordingCallback recordingCallback,
- @Provided TunerSessionWorkerExoV2.Factory tunerSessionWorkerExoV2Factory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
super(context);
mReleasedCallback = releasedCallback;
- mRecordingCallback = recordingCallback;
mTunerSessionOverlay = new TunerSessionOverlay(context);
mSessionWorker =
- tunerSessionWorkerExoV2Factory.create(
+ new TunerSessionWorkerExoV2(
context,
channelDataManager,
this,
- mTunerSessionOverlay);
+ mTunerSessionOverlay,
+ concurrentDvrPlaybackFlags,
+ tsDataSourceManagerFactory);
TunerPreferences.setCommonPreferencesChangedListener(this);
}
@@ -209,8 +203,4 @@ public class TunerSessionExoV2 extends TisSessionCompat
public void onCommonPreferencesChanged() {
mSessionWorker.sendMessage(TunerSessionWorkerExoV2.MSG_TUNER_PREFERENCES_CHANGED);
}
-
- public Uri getRecordingUri(Uri channelUri) {
- return mRecordingCallback.getRecordingUri(channelUri);
- }
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java
index 53e0bcc2..9f21e16a 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionOverlay.java
@@ -26,18 +26,17 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
-
+import com.android.tv.common.util.SystemPropertiesProxy;
import com.android.tv.tuner.R;
import com.android.tv.tuner.cc.CaptionLayout;
import com.android.tv.tuner.cc.CaptionTrackRenderer;
import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.util.GlobalSettingsUtils;
import com.android.tv.tuner.util.StatusTextUtils;
/** Executes {@link Session} overlay changes on the main thread. */
/* package */ final class TunerSessionOverlay implements Handler.Callback {
- private static final boolean DEBUG = false;
/** Displays the given {@link String} message object in the message view. */
public static final int MSG_UI_SHOW_MESSAGE = 1;
@@ -68,6 +67,8 @@ import com.android.tv.tuner.util.StatusTextUtils;
/** Displays a toast signalling that a re-scan is required. Does not expect a message object. */
public static final int MSG_UI_TOAST_RESCAN_NEEDED = 11;
+ private static final String USBTUNER_SHOW_DEBUG = "persist.tv.tuner.show_debug";
+
private final Context mContext;
private final Handler mHandler;
private final View mOverlayView;
@@ -87,12 +88,13 @@ import com.android.tv.tuner.util.StatusTextUtils;
mHandler = new Handler(this);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ boolean showDebug = SystemPropertiesProxy.getBoolean(USBTUNER_SHOW_DEBUG, false);
mOverlayView = inflater.inflate(R.layout.ut_overlay_view, null);
mMessageLayout = mOverlayView.findViewById(R.id.message_layout);
mMessageLayout.setVisibility(View.INVISIBLE);
mMessageView = mOverlayView.findViewById(R.id.message);
mStatusView = mOverlayView.findViewById(R.id.tuner_status);
- mStatusView.setVisibility(DEBUG ? View.VISIBLE : View.INVISIBLE);
+ mStatusView.setVisibility(showDebug ? View.VISIBLE : View.INVISIBLE);
mAudioStatusView = mOverlayView.findViewById(R.id.audio_status);
mAudioStatusView.setVisibility(View.INVISIBLE);
CaptionLayout captionLayout = mOverlayView.findViewById(R.id.caption);
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
index 792dfaab..d3f9409b 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
@@ -44,22 +44,22 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.Surface;
import android.view.accessibility.CaptioningManager;
-
import com.android.tv.common.CommonPreferences.TrickplaySetting;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.TvContentRatingCache;
import com.android.tv.common.compat.TvInputConstantCompat;
import com.android.tv.common.customization.CustomizationManager;
import com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE;
-import com.android.tv.common.dev.DeveloperPreferences;
+import com.android.tv.common.experiments.Experiments;
import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.util.SystemPropertiesProxy;
import com.android.tv.tuner.data.Cea708Data;
-import com.android.tv.tuner.data.Channel;
import com.android.tv.tuner.data.PsipData.EitItem;
import com.android.tv.tuner.data.PsipData.TvTracksInterface;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.data.nano.Channel;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.exoplayer.MpegTsPlayer;
import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder;
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
@@ -74,15 +74,10 @@ import com.android.tv.tuner.ts.EventDetector.EventListener;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
import com.android.tv.tuner.tvinput.debug.TunerDebug;
import com.android.tv.tuner.util.StatusTextUtils;
-
import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.audio.AudioCapabilities;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
import com.google.common.collect.ImmutableList;
-
-import com.android.tv.common.flags.LegacyFlags;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
@@ -108,6 +103,8 @@ public class TunerSessionWorker
private static final boolean DEBUG = false;
private static final boolean ENABLE_PROFILER = true;
private static final String PLAY_FROM_CHANNEL = "channel";
+ private static final String MAX_BUFFER_SIZE_KEY = "tv.tuner.buffersize_mbytes";
+ private static final int MAX_BUFFER_SIZE_DEF = 2 * 1024; // 2GB
private static final int MIN_BUFFER_SIZE_DEF = 256; // 256MB
// Public messages
@@ -192,8 +189,6 @@ public class TunerSessionWorker
private final int mMaxTrickplayBufferSizeMb;
private final File mTrickplayBufferDir;
private final @TRICKPLAY_MODE int mTrickplayModeCustomization;
- private final LegacyFlags mLegacyFlags;
- private final MpegTsRendererBuilder.Factory mMpegTsRendererBuilderFactory;
private volatile Surface mSurface;
private volatile float mVolume = 1.0f;
private volatile boolean mCaptionEnabled;
@@ -236,44 +231,25 @@ public class TunerSessionWorker
private boolean mIsActiveSession;
private boolean mReleaseRequested; // Guarded by mReleaseLock
private final Object mReleaseLock = new Object();
- private Uri mChannelUri;
- private Uri mRecordingUri;
- private boolean mOnTuneUsesRecording = false;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
private int mSignalStrength;
private long mRecordedProgramStartTimeMs;
- /**
- * Factory for {@link TunerSessionWorker}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public TunerSessionWorker create(
- Context context,
- ChannelDataManager channelDataManager,
- TunerSession tunerSession,
- TunerSessionOverlay tunerSessionOverlay);
- }
-
- @AutoFactory(implementing = Factory.class)
public TunerSessionWorker(
Context context,
ChannelDataManager channelDataManager,
TunerSession tunerSession,
TunerSessionOverlay tunerSessionOverlay,
- @Provided LegacyFlags legacyFlags,
- @Provided MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory,
- @Provided TsDataSourceManager.Factory tsDataSourceManagerFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
this(
context,
channelDataManager,
tunerSession,
tunerSessionOverlay,
null,
- legacyFlags,
- mpegTsRendererBuilderFactory,
+ concurrentDvrPlaybackFlags,
tsDataSourceManagerFactory);
}
@@ -284,10 +260,9 @@ public class TunerSessionWorker
TunerSession tunerSession,
TunerSessionOverlay tunerSessionOverlay,
@Nullable Handler handler,
- LegacyFlags legacyFlags,
- MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory,
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
TsDataSourceManager.Factory tsDataSourceManagerFactory) {
- mLegacyFlags = legacyFlags;
+ this.mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
if (DEBUG) Log.d(TAG, "TunerSessionWorker created");
mContext = context;
if (handler != null) {
@@ -302,8 +277,6 @@ public class TunerSessionWorker
mSession = tunerSession;
mTunerSessionOverlay = tunerSessionOverlay;
mChannelDataManager = channelDataManager;
- mMpegTsRendererBuilderFactory = mpegTsRendererBuilderFactory;
- mRecordingUri = null;
mChannelDataManager.setListener(this);
mChannelDataManager.checkDataVersion(mContext);
mSourceManager = tsDataSourceManagerFactory.create(false);
@@ -320,7 +293,8 @@ public class TunerSessionWorker
(CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
mCaptionEnabled = captioningManager.isEnabled();
mPlaybackParams.setSpeed(1.0f);
- mMaxTrickplayBufferSizeMb = DeveloperPreferences.MAX_BUFFER_SIZE_MBYTES.get(context);
+ mMaxTrickplayBufferSizeMb =
+ SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF);
mTrickplayModeCustomization = CustomizationManager.getTrickplayMode(context);
if (mTrickplayModeCustomization
== CustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) {
@@ -513,11 +487,6 @@ public class TunerSessionWorker
// Final status
// notification of STATE_ENDED from MpegTsPlayer will be ignored afterwards.
Log.i(TAG, "Player ended: end of stream");
- if (mOnTuneUsesRecording) {
- mRecordingUri = null;
- mSession.notifyChannelRetuned(mChannelUri);
- sendMessage(MSG_TUNE, mChannelUri);
- }
if (mChannel != null) {
sendMessage(MSG_RETRY_PLAYBACK, System.identityHashCode(mPlayer));
}
@@ -546,10 +515,10 @@ public class TunerSessionWorker
@Override
public void onVideoSizeChanged(int width, int height, float pixelWidthHeight) {
if (mChannel != null && mChannel.hasVideo()) {
- updateVideoTrack(width, height, pixelWidthHeight);
+ updateVideoTrack(width, height);
}
if (mRecordingId != null) {
- updateVideoTrack(width, height, pixelWidthHeight);
+ updateVideoTrack(width, height);
}
}
@@ -563,9 +532,6 @@ public class TunerSessionWorker
} else {
mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis();
}
- if (mOnTuneUsesRecording) {
- mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs;
- }
notifyVideoAvailable();
mReportedDrawnToSurface = true;
@@ -621,7 +587,7 @@ public class TunerSessionWorker
// ChannelDataManager.ProgramInfoListener
@Override
public void onProgramsArrived(TunerChannel channel, List<EitItem> programs) {
- sendMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(channel, programs));
+ sendMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(channel, programs));
}
@Override
@@ -636,7 +602,7 @@ public class TunerSessionWorker
@Override
public void onRequestProgramsResponse(TunerChannel channel, List<EitItem> programs) {
- sendMessage(MSG_PROGRAM_DATA_RESULT, Pair.create(channel, programs));
+ sendMessage(MSG_PROGRAM_DATA_RESULT, new Pair<>(channel, programs));
}
// PlaybackBufferListener
@@ -684,7 +650,7 @@ public class TunerSessionWorker
}
private static class RecordedProgram {
- private final long mChannelId;
+ // private final long mChannelId;
private final String mDataUri;
private final long mStartTimeMillis;
@@ -696,13 +662,14 @@ public class TunerSessionWorker
public RecordedProgram(Cursor cursor) {
int index = 0;
- mChannelId = cursor.getLong(index++);
+ // mChannelId = cursor.getLong(index++);
+ index++;
mDataUri = cursor.getString(index++);
mStartTimeMillis = cursor.getLong(index++);
}
public RecordedProgram(long channelId, String dataUri) {
- mChannelId = channelId;
+ // mChannelId = channelId;
mDataUri = dataUri;
mStartTimeMillis = 0;
}
@@ -722,10 +689,6 @@ public class TunerSessionWorker
public long getStartTime() {
return mStartTimeMillis;
}
-
- public long getChannelId() {
- return mChannelId;
- }
}
private RecordedProgram getRecordedProgram(Uri recordedUri) {
@@ -748,13 +711,9 @@ public class TunerSessionWorker
}
}
- private String parseRecording(Uri uri, long channelId) {
+ private String parseRecording(Uri uri) {
RecordedProgram recording = getRecordedProgram(uri);
if (recording != null) {
- if (channelId != -1 && channelId != recording.getChannelId()) {
- // Recorded URI is of some other channel
- return null;
- }
mRecordedProgramStartTimeMs = recording.getStartTime();
return recording.getDataUri();
}
@@ -867,20 +826,10 @@ public class TunerSessionWorker
mIsActiveSession = true;
}
String recording = null;
- mOnTuneUsesRecording = false;
long channelId = parseChannel(channelUri);
TunerChannel channel = (channelId == -1) ? null : mChannelDataManager.getChannel(channelId);
- mRecordingUri = mSession.getRecordingUri(channelUri);
if (channelId == -1) {
- recording = parseRecording(channelUri, channelId);
-
- } else if (mRecordingUri != null) {
- mChannelUri = channelUri;
- recording = parseRecording(mRecordingUri, channelId);
- if (recording != null) {
- mOnTuneUsesRecording = true;
- channel = null;
- }
+ recording = parseRecording(channelUri);
}
if (channel == null && recording == null) {
Log.w(TAG, "onTune() is failed. Can't find channel for " + channelUri);
@@ -1184,15 +1133,8 @@ public class TunerSessionWorker
if (mPlayer == null) {
return true;
}
- long seekPosMs = timeMs;
- if (mRecordingId != null) {
- long systemBufferTime = System.currentTimeMillis() - SEEK_MARGIN_MS;
- if (seekPosMs > systemBufferTime) {
- seekPosMs = systemBufferTime;
- }
- }
setTrickplayEnabledIfNeeded();
- doTimeShiftSeekTo(seekPosMs);
+ doTimeShiftSeekTo(timeMs);
return true;
}
@@ -1490,7 +1432,8 @@ public class TunerSessionWorker
}
MpegTsPlayer player =
new MpegTsPlayer(
- mMpegTsRendererBuilderFactory.create(mContext, bufferManager, this),
+ new MpegTsRendererBuilder(
+ mContext, bufferManager, this, mConcurrentDvrPlaybackFlags),
mHandler,
mSourceManager,
capabilities,
@@ -1501,7 +1444,7 @@ public class TunerSessionWorker
player.setVideoEventListener(this);
player.setCaptionServiceNumber(
mCaptionTrack != null
- ? mCaptionTrack.getServiceNumber()
+ ? mCaptionTrack.serviceNumber
: Cea708Data.EMPTY_SERVICE_NUMBER);
return player;
}
@@ -1511,7 +1454,7 @@ public class TunerSessionWorker
mTunerSessionOverlay.sendUiMessage(
TunerSessionOverlay.MSG_UI_START_CAPTION_TRACK, mCaptionTrack);
if (mPlayer != null) {
- mPlayer.setCaptionServiceNumber(mCaptionTrack.getServiceNumber());
+ mPlayer.setCaptionServiceNumber(mCaptionTrack.serviceNumber);
}
}
}
@@ -1568,13 +1511,12 @@ public class TunerSessionWorker
}
}
- private void updateVideoTrack(int width, int height, float pixelWidthHeight) {
+ private void updateVideoTrack(int width, int height) {
removeTvTracks(TvTrackInfo.TYPE_VIDEO);
mTvTracks.add(
new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID)
.setVideoWidth(width)
.setVideoHeight(height)
- .setVideoPixelAspectRatio(pixelWidthHeight)
.build());
mSession.notifyTracksChanged(mTvTracks);
mSession.notifyTrackSelected(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID);
@@ -1588,7 +1530,7 @@ public class TunerSessionWorker
if (audioTracks != null) {
int index = 0;
for (AtscAudioTrack audioTrack : audioTracks) {
- audioTrack = audioTrack.toBuilder().setIndex(index).build();
+ audioTrack.index = index;
mAudioTrackMap.put(index, audioTrack);
++index;
}
@@ -1618,10 +1560,10 @@ public class TunerSessionWorker
String language =
!TextUtils.isEmpty(infoFromPlayer.language)
? infoFromPlayer.language
- : (infoFromEit != null && infoFromEit.hasLanguage())
- ? infoFromEit.getLanguage()
- : (infoFromVct != null && infoFromVct.hasLanguage())
- ? infoFromVct.getLanguage()
+ : (infoFromEit != null && infoFromEit.language != null)
+ ? infoFromEit.language
+ : (infoFromVct != null && infoFromVct.language != null)
+ ? infoFromVct.language
: null;
TvTrackInfo.Builder builder =
new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, AUDIO_TRACK_PREFIX + i);
@@ -1642,20 +1584,20 @@ public class TunerSessionWorker
mCaptionTrackMap.clear();
if (captionTracks != null) {
for (AtscCaptionTrack captionTrack : captionTracks) {
- if (mCaptionTrackMap.indexOfKey(captionTrack.getServiceNumber()) >= 0) {
+ if (mCaptionTrackMap.indexOfKey(captionTrack.serviceNumber) >= 0) {
continue;
}
- String language = captionTrack.getLanguage();
+ String language = captionTrack.language;
// The service number of the caption service is used for track id of a subtitle.
// Later, when a subtitle is chosen, track id will be passed on to TsParser.
TvTrackInfo.Builder builder =
new TvTrackInfo.Builder(
TvTrackInfo.TYPE_SUBTITLE,
- SUBTITLE_TRACK_PREFIX + captionTrack.getServiceNumber());
+ SUBTITLE_TRACK_PREFIX + captionTrack.serviceNumber);
builder.setLanguage(language);
mTvTracks.add(builder.build());
- mCaptionTrackMap.put(captionTrack.getServiceNumber(), captionTrack);
+ mCaptionTrackMap.put(captionTrack.serviceNumber, captionTrack);
}
}
mSession.notifyTracksChanged(mTvTracks);
@@ -1835,9 +1777,6 @@ public class TunerSessionWorker
} else {
mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis();
}
- if (mOnTuneUsesRecording) {
- mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs;
- }
mLastPositionMs = 0;
mCaptionTrack = null;
mSignalStrength = TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN;
@@ -1845,14 +1784,6 @@ public class TunerSessionWorker
mSession.notifySignalStrength(mSignalStrength);
}
mHandler.sendEmptyMessage(MSG_PARENTAL_CONTROLS);
- if (mOnTuneUsesRecording) {
- mHandler.obtainMessage(
- MSG_TIMESHIFT_SEEK_TO,
- 1,
- 0,
- System.currentTimeMillis() - SEEK_MARGIN_MS)
- .sendToTarget();
- }
}
private void doReschedulePrograms() {
@@ -1874,7 +1805,7 @@ public class TunerSessionWorker
+ " current program: "
+ getCurrentProgram());
}
- mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(mChannel, mPrograms))
+ mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(mChannel, mPrograms))
.sendToTarget();
}
mHandler.removeMessages(MSG_RESCHEDULE_PROGRAMS);
@@ -2035,12 +1966,10 @@ public class TunerSessionWorker
private void doDiscoverCaptionServiceNumber(int serviceNumber) {
int index = mCaptionTrackMap.indexOfKey(serviceNumber);
if (index < 0) {
- AtscCaptionTrack captionTrack =
- AtscCaptionTrack.newBuilder()
- .setServiceNumber(serviceNumber)
- .setWideAspectRatio(false)
- .setEasyReader(false)
- .build();
+ AtscCaptionTrack captionTrack = new AtscCaptionTrack();
+ captionTrack.serviceNumber = serviceNumber;
+ captionTrack.wideAspectRatio = false;
+ captionTrack.easyReader = false;
mCaptionTrackMap.put(serviceNumber, captionTrack);
mTvTracks.add(
new TvTrackInfo.Builder(
@@ -2059,7 +1988,7 @@ public class TunerSessionWorker
ImmutableList<TvContentRating> ratings =
mTvContentRatingCache.getRatings(currentProgram.getContentRating());
if ((ratings == null || ratings.isEmpty())) {
- if (mLegacyFlags.enableUnratedContentSettings()) {
+ if (Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get()) {
ratings = ImmutableList.of(TvContentRating.UNRATED);
} else {
ratings = NO_CONTENT_RATINGS;
diff --git a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java
index f56e4879..82afff15 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/TunerSessionWorkerExoV2.java
@@ -44,22 +44,22 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.Surface;
import android.view.accessibility.CaptioningManager;
-
import com.android.tv.common.CommonPreferences.TrickplaySetting;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.TvContentRatingCache;
import com.android.tv.common.compat.TvInputConstantCompat;
import com.android.tv.common.customization.CustomizationManager;
import com.android.tv.common.customization.CustomizationManager.TRICKPLAY_MODE;
-import com.android.tv.common.dev.DeveloperPreferences;
+import com.android.tv.common.experiments.Experiments;
import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.util.SystemPropertiesProxy;
import com.android.tv.tuner.data.Cea708Data;
-import com.android.tv.tuner.data.Channel;
import com.android.tv.tuner.data.PsipData.EitItem;
import com.android.tv.tuner.data.PsipData.TvTracksInterface;
-import com.android.tv.tuner.data.Track.AtscAudioTrack;
-import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.data.nano.Channel;
+import com.android.tv.tuner.data.nano.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack;
import com.android.tv.tuner.exoplayer.MpegTsPlayer;
import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder;
import com.android.tv.tuner.exoplayer.buffer.BufferManager;
@@ -74,15 +74,10 @@ import com.android.tv.tuner.ts.EventDetector.EventListener;
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
import com.android.tv.tuner.tvinput.debug.TunerDebug;
import com.android.tv.tuner.util.StatusTextUtils;
-
import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.audio.AudioCapabilities;
-import com.google.auto.factory.AutoFactory;
-import com.google.auto.factory.Provided;
import com.google.common.collect.ImmutableList;
-
-import com.android.tv.common.flags.LegacyFlags;
-
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
@@ -105,6 +100,8 @@ public class TunerSessionWorkerExoV2
private static final boolean DEBUG = false;
private static final boolean ENABLE_PROFILER = true;
private static final String PLAY_FROM_CHANNEL = "channel";
+ private static final String MAX_BUFFER_SIZE_KEY = "tv.tuner.buffersize_mbytes";
+ private static final int MAX_BUFFER_SIZE_DEF = 2 * 1024; // 2GB
private static final int MIN_BUFFER_SIZE_DEF = 256; // 256MB
// Public messages
@@ -191,7 +188,6 @@ public class TunerSessionWorkerExoV2
private final int mMaxTrickplayBufferSizeMb;
private final File mTrickplayBufferDir;
private final @TRICKPLAY_MODE int mTrickplayModeCustomization;
- private final MpegTsRendererBuilder.Factory mMpegTsRendererBuilderFactory;
private volatile Surface mSurface;
private volatile float mVolume = 1.0f;
private volatile boolean mCaptionEnabled;
@@ -234,45 +230,25 @@ public class TunerSessionWorkerExoV2
private boolean mIsActiveSession;
private boolean mReleaseRequested; // Guarded by mReleaseLock
private final Object mReleaseLock = new Object();
- private final LegacyFlags mLegacyFlags;
- private Uri mChannelUri;
- private Uri mRecordingUri;
- private boolean mOnTuneUsesRecording = false;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
private int mSignalStrength;
private long mRecordedProgramStartTimeMs;
- /**
- * Factory for {@link TunerSessionWorkerExoV2}.
- *
- * <p>This wrapper class keeps other classes from needing to reference the {@link AutoFactory}
- * generated class.
- */
- public interface Factory {
- public TunerSessionWorkerExoV2 create(
- Context context,
- ChannelDataManager channelDataManager,
- TunerSessionExoV2 tunerSession,
- TunerSessionOverlay tunerSessionOverlay);
- }
-
- @AutoFactory(implementing = Factory.class)
public TunerSessionWorkerExoV2(
Context context,
ChannelDataManager channelDataManager,
TunerSessionExoV2 tunerSession,
TunerSessionOverlay tunerSessionOverlay,
- @Provided LegacyFlags legacyFlags,
- @Provided MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory,
- @Provided TsDataSourceManager.Factory tsDataSourceManagerFactory) {
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
this(
context,
channelDataManager,
tunerSession,
tunerSessionOverlay,
null,
- legacyFlags,
- mpegTsRendererBuilderFactory,
+ concurrentDvrPlaybackFlags,
tsDataSourceManagerFactory);
}
@@ -283,10 +259,9 @@ public class TunerSessionWorkerExoV2
TunerSessionExoV2 tunerSession,
TunerSessionOverlay tunerSessionOverlay,
@Nullable Handler handler,
- LegacyFlags legacyFlags,
- MpegTsRendererBuilder.Factory mpegTsRendererBuilderFactory,
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
TsDataSourceManager.Factory tsDataSourceManagerFactory) {
- mLegacyFlags = legacyFlags;
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
if (DEBUG) {
Log.d(TAG, "TunerSessionWorkerExoV2 created");
}
@@ -303,8 +278,6 @@ public class TunerSessionWorkerExoV2
mSession = tunerSession;
mTunerSessionOverlay = tunerSessionOverlay;
mChannelDataManager = channelDataManager;
- mMpegTsRendererBuilderFactory = mpegTsRendererBuilderFactory;
- mRecordingUri = null;
mChannelDataManager.setListener(this);
mChannelDataManager.checkDataVersion(mContext);
mSourceManager = tsDataSourceManagerFactory.create(false);
@@ -321,7 +294,8 @@ public class TunerSessionWorkerExoV2
(CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
mCaptionEnabled = captioningManager.isEnabled();
mPlaybackParams.setSpeed(1.0f);
- mMaxTrickplayBufferSizeMb = DeveloperPreferences.MAX_BUFFER_SIZE_MBYTES.get(context);
+ mMaxTrickplayBufferSizeMb =
+ SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF);
mTrickplayModeCustomization = CustomizationManager.getTrickplayMode(context);
if (mTrickplayModeCustomization
== CustomizationManager.TRICKPLAY_MODE_USE_EXTERNAL_STORAGE) {
@@ -519,11 +493,6 @@ public class TunerSessionWorkerExoV2
// Final status
// notification of STATE_ENDED from MpegTsPlayer will be ignored afterwards.
Log.i(TAG, "Player ended: end of stream");
- if (mOnTuneUsesRecording) {
- mRecordingUri = null;
- mSession.notifyChannelRetuned(mChannelUri);
- sendMessage(MSG_TUNE, mChannelUri);
- }
if (mChannel != null) {
sendMessage(MSG_RETRY_PLAYBACK, System.identityHashCode(mPlayer));
}
@@ -552,10 +521,10 @@ public class TunerSessionWorkerExoV2
@Override
public void onVideoSizeChanged(int width, int height, float pixelWidthHeight) {
if (mChannel != null && mChannel.hasVideo()) {
- updateVideoTrack(width, height, pixelWidthHeight);
+ updateVideoTrack(width, height);
}
if (mRecordingId != null) {
- updateVideoTrack(width, height, pixelWidthHeight);
+ updateVideoTrack(width, height);
}
}
@@ -571,9 +540,6 @@ public class TunerSessionWorkerExoV2
} else {
mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis();
}
- if (mOnTuneUsesRecording) {
- mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs;
- }
notifyVideoAvailable();
mReportedDrawnToSurface = true;
@@ -629,7 +595,7 @@ public class TunerSessionWorkerExoV2
// ChannelDataManager.ProgramInfoListener
@Override
public void onProgramsArrived(TunerChannel channel, List<EitItem> programs) {
- sendMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(channel, programs));
+ sendMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(channel, programs));
}
@Override
@@ -644,7 +610,7 @@ public class TunerSessionWorkerExoV2
@Override
public void onRequestProgramsResponse(TunerChannel channel, List<EitItem> programs) {
- sendMessage(MSG_PROGRAM_DATA_RESULT, Pair.create(channel, programs));
+ sendMessage(MSG_PROGRAM_DATA_RESULT, new Pair<>(channel, programs));
}
// PlaybackBufferListener
@@ -692,7 +658,7 @@ public class TunerSessionWorkerExoV2
}
private static class RecordedProgram {
- private final long mChannelId;
+ // private final long mChannelId;
private final String mDataUri;
private final long mStartTimeMillis;
@@ -704,13 +670,14 @@ public class TunerSessionWorkerExoV2
public RecordedProgram(Cursor cursor) {
int index = 0;
- mChannelId = cursor.getLong(index++);
+ // mChannelId = cursor.getLong(index++);
+ index++;
mDataUri = cursor.getString(index++);
mStartTimeMillis = cursor.getLong(index++);
}
public RecordedProgram(long channelId, String dataUri) {
- mChannelId = channelId;
+ // mChannelId = channelId;
mDataUri = dataUri;
mStartTimeMillis = 0;
}
@@ -730,10 +697,6 @@ public class TunerSessionWorkerExoV2
public long getStartTime() {
return mStartTimeMillis;
}
-
- public long getChannelId() {
- return mChannelId;
- }
}
private RecordedProgram getRecordedProgram(Uri recordedUri) {
@@ -758,13 +721,9 @@ public class TunerSessionWorkerExoV2
}
}
- private String parseRecording(Uri uri, long channelId) {
+ private String parseRecording(Uri uri) {
RecordedProgram recording = getRecordedProgram(uri);
if (recording != null) {
- if (channelId != -1 && channelId != recording.getChannelId()) {
- // Recorded URI is of some other channel
- return null;
- }
mRecordedProgramStartTimeMs = recording.getStartTime();
return recording.getDataUri();
}
@@ -877,19 +836,10 @@ public class TunerSessionWorkerExoV2
mIsActiveSession = true;
}
String recording = null;
- mOnTuneUsesRecording = false;
long channelId = parseChannel(channelUri);
TunerChannel channel = (channelId == -1) ? null : mChannelDataManager.getChannel(channelId);
- mRecordingUri = mSession.getRecordingUri(channelUri);
if (channelId == -1) {
- recording = parseRecording(channelUri, channelId);
- } else if (mRecordingUri != null) {
- mChannelUri = channelUri;
- recording = parseRecording(mRecordingUri, channelId);
- if (recording != null) {
- mOnTuneUsesRecording = true;
- channel = null;
- }
+ recording = parseRecording(channelUri);
}
if (channel == null && recording == null) {
Log.w(TAG, "onTune() is failed. Can't find channel for " + channelUri);
@@ -1492,7 +1442,8 @@ public class TunerSessionWorkerExoV2
}
MpegTsPlayer player =
new MpegTsPlayer(
- mMpegTsRendererBuilderFactory.create(mContext, bufferManager, this),
+ new MpegTsRendererBuilder(
+ mContext, bufferManager, this, mConcurrentDvrPlaybackFlags),
mHandler,
mSourceManager,
capabilities,
@@ -1505,7 +1456,7 @@ public class TunerSessionWorkerExoV2
player.setVideoEventListener(this);
player.setCaptionServiceNumber(
mCaptionTrack != null
- ? mCaptionTrack.getServiceNumber()
+ ? mCaptionTrack.serviceNumber
: Cea708Data.EMPTY_SERVICE_NUMBER);
return player;
}
@@ -1515,7 +1466,7 @@ public class TunerSessionWorkerExoV2
mTunerSessionOverlay.sendUiMessage(
TunerSessionOverlay.MSG_UI_START_CAPTION_TRACK, mCaptionTrack);
if (mPlayer != null) {
- mPlayer.setCaptionServiceNumber(mCaptionTrack.getServiceNumber());
+ mPlayer.setCaptionServiceNumber(mCaptionTrack.serviceNumber);
}
}
}
@@ -1572,13 +1523,12 @@ public class TunerSessionWorkerExoV2
}
}
- private void updateVideoTrack(int width, int height, float pixelWidthHeight) {
+ private void updateVideoTrack(int width, int height) {
removeTvTracks(TvTrackInfo.TYPE_VIDEO);
mTvTracks.add(
new TvTrackInfo.Builder(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID)
.setVideoWidth(width)
.setVideoHeight(height)
- .setVideoPixelAspectRatio(pixelWidthHeight)
.build());
mSession.notifyTracksChanged(mTvTracks);
mSession.notifyTrackSelected(TvTrackInfo.TYPE_VIDEO, VIDEO_TRACK_ID);
@@ -1592,7 +1542,7 @@ public class TunerSessionWorkerExoV2
if (audioTracks != null) {
int index = 0;
for (AtscAudioTrack audioTrack : audioTracks) {
- audioTrack = audioTrack.toBuilder().setIndex(index).build();
+ audioTrack.index = index;
mAudioTrackMap.put(index, audioTrack);
++index;
}
@@ -1622,10 +1572,10 @@ public class TunerSessionWorkerExoV2
String language =
!TextUtils.isEmpty(infoFromPlayer.language)
? infoFromPlayer.language
- : (infoFromEit != null && infoFromEit.hasLanguage())
- ? infoFromEit.getLanguage()
- : (infoFromVct != null && infoFromVct.hasLanguage())
- ? infoFromVct.getLanguage()
+ : (infoFromEit != null && infoFromEit.language != null)
+ ? infoFromEit.language
+ : (infoFromVct != null && infoFromVct.language != null)
+ ? infoFromVct.language
: null;
TvTrackInfo.Builder builder =
new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, AUDIO_TRACK_PREFIX + i);
@@ -1646,20 +1596,20 @@ public class TunerSessionWorkerExoV2
mCaptionTrackMap.clear();
if (captionTracks != null) {
for (AtscCaptionTrack captionTrack : captionTracks) {
- if (mCaptionTrackMap.indexOfKey(captionTrack.getServiceNumber()) >= 0) {
+ if (mCaptionTrackMap.indexOfKey(captionTrack.serviceNumber) >= 0) {
continue;
}
- String language = captionTrack.getLanguage();
+ String language = captionTrack.language;
// The service number of the caption service is used for track id of a subtitle.
// Later, when a subtitle is chosen, track id will be passed on to TsParser.
TvTrackInfo.Builder builder =
new TvTrackInfo.Builder(
TvTrackInfo.TYPE_SUBTITLE,
- SUBTITLE_TRACK_PREFIX + captionTrack.getServiceNumber());
+ SUBTITLE_TRACK_PREFIX + captionTrack.serviceNumber);
builder.setLanguage(language);
mTvTracks.add(builder.build());
- mCaptionTrackMap.put(captionTrack.getServiceNumber(), captionTrack);
+ mCaptionTrackMap.put(captionTrack.serviceNumber, captionTrack);
}
}
mSession.notifyTracksChanged(mTvTracks);
@@ -1841,9 +1791,6 @@ public class TunerSessionWorkerExoV2
} else {
mBufferStartTimeMs = mRecordStartTimeMs = System.currentTimeMillis();
}
- if (mOnTuneUsesRecording) {
- mBufferStartTimeMs = mRecordStartTimeMs = mRecordedProgramStartTimeMs;
- }
mLastPositionMs = 0;
mCaptionTrack = null;
mSignalStrength = TvInputConstantCompat.SIGNAL_STRENGTH_UNKNOWN;
@@ -1851,14 +1798,6 @@ public class TunerSessionWorkerExoV2
mSession.notifySignalStrength(mSignalStrength);
}
mHandler.sendEmptyMessage(MSG_PARENTAL_CONTROLS);
- if (mOnTuneUsesRecording) {
- mHandler.obtainMessage(
- MSG_TIMESHIFT_SEEK_TO,
- 1,
- 0,
- System.currentTimeMillis() - SEEK_MARGIN_MS)
- .sendToTarget();
- }
}
private void doReschedulePrograms() {
@@ -1880,7 +1819,7 @@ public class TunerSessionWorkerExoV2
+ " current program: "
+ getCurrentProgram());
}
- mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, Pair.create(mChannel, mPrograms))
+ mHandler.obtainMessage(MSG_SCHEDULE_OF_PROGRAMS, new Pair<>(mChannel, mPrograms))
.sendToTarget();
}
mHandler.removeMessages(MSG_RESCHEDULE_PROGRAMS);
@@ -2041,13 +1980,10 @@ public class TunerSessionWorkerExoV2
private void doDiscoverCaptionServiceNumber(int serviceNumber) {
int index = mCaptionTrackMap.indexOfKey(serviceNumber);
if (index < 0) {
- AtscCaptionTrack.Builder captionTrackBuilder = AtscCaptionTrack.newBuilder();
- AtscCaptionTrack captionTrack =
- captionTrackBuilder
- .setServiceNumber(serviceNumber)
- .setWideAspectRatio(false)
- .setEasyReader(false)
- .build();
+ AtscCaptionTrack captionTrack = new AtscCaptionTrack();
+ captionTrack.serviceNumber = serviceNumber;
+ captionTrack.wideAspectRatio = false;
+ captionTrack.easyReader = false;
mCaptionTrackMap.put(serviceNumber, captionTrack);
mTvTracks.add(
new TvTrackInfo.Builder(
@@ -2066,7 +2002,7 @@ public class TunerSessionWorkerExoV2
ImmutableList<TvContentRating> ratings =
mTvContentRatingCache.getRatings(currentProgram.getContentRating());
if ((ratings == null || ratings.isEmpty())) {
- if (mLegacyFlags.enableUnratedContentSettings()) {
+ if (Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get()) {
ratings = ImmutableList.of(TvContentRating.UNRATED);
} else {
ratings = NO_CONTENT_RATINGS;
diff --git a/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java b/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java
index 447618a4..585b28bc 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/datamanager/ChannelDataManager.java
@@ -29,10 +29,11 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.RemoteException;
-import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.format.DateUtils;
import android.util.Log;
+import com.android.tv.common.singletons.HasSingletons;
+import com.android.tv.common.singletons.HasTvInputId;
import com.android.tv.common.util.PermissionUtils;
import com.android.tv.tuner.data.PsipData.EitItem;
import com.android.tv.tuner.data.TunerChannel;
@@ -50,7 +51,7 @@ import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-/** Manages the channel info and EPG data for a specific inputId. */
+/** Manages the channel info and EPG data through {@link TvInputManager}. */
public class ChannelDataManager implements Handler.Callback {
private static final String TAG = "ChannelDataManager";
@@ -145,9 +146,9 @@ public class ChannelDataManager implements Handler.Callback {
void onChannelHandlingDone();
}
- public ChannelDataManager(Context context, String inputId) {
+ public ChannelDataManager(Context context) {
mContext = context;
- mInputId = inputId;
+ mInputId = HasSingletons.get(HasTvInputId.class, context).getEmbeddedTunerInputId();
mChannelsUri = TvContract.buildChannelsUriForInput(mInputId);
mTunerChannelMap = new ConcurrentHashMap<>();
mTunerChannelIdMap = new ConcurrentSkipListMap<>();
@@ -381,12 +382,6 @@ public class ChannelDataManager implements Handler.Callback {
return false;
}
- @NonNull
- @Override
- public String toString() {
- return "ChannelDataManager[" + mInputId + "]";
- }
-
// Private methods
private void handleEvents(TunerChannel channel, List<EitItem> items) {
long channelId = getChannelId(channel);
diff --git a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java
deleted file mode 100644
index c5950756..00000000
--- a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerRecordingSessionFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.tuner.tvinput.factory;
-
-import android.media.tv.TvInputService.RecordingSession;
-
-import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
-
-/** {@link RecordingSession} factory */
-public interface TunerRecordingSessionFactory {
-
- /** Called when a recording session is released */
- interface RecordingSessionReleasedCallback {
-
- /**
- * Called when the given recording session is released.
- *
- * @param session The recording session that has been released.
- */
- void onReleased(RecordingSession session);
- }
-
- RecordingSession create(
- String inputId,
- RecordingSessionReleasedCallback releasedCallback,
- ChannelDataManager channelDataManager);
-}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java
index e22562ac..a27cb22a 100644
--- a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java
+++ b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactory.java
@@ -1,24 +1,7 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
package com.android.tv.tuner.tvinput.factory;
+import android.content.Context;
import android.media.tv.TvInputService.Session;
-import android.net.Uri;
-
import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
/** {@link android.media.tv.TvInputService.Session} factory */
@@ -35,19 +18,8 @@ public interface TunerSessionFactory {
void onReleased(Session session);
}
- /** Called when recording URI is required for playback */
- interface SessionRecordingCallback {
-
- /**
- * Called when recording URI is required for playback.
- *
- * @param channelUri for which recording URI is requested.
- */
- Uri getRecordingUri(Uri channelUri);
- }
-
Session create(
+ Context context,
ChannelDataManager channelDataManager,
- SessionReleasedCallback releasedCallback,
- SessionRecordingCallback recordingCallback);
+ SessionReleasedCallback releasedCallback);
}
diff --git a/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java
new file mode 100644
index 00000000..54e959e6
--- /dev/null
+++ b/tuner/src/com/android/tv/tuner/tvinput/factory/TunerSessionFactoryImpl.java
@@ -0,0 +1,49 @@
+package com.android.tv.tuner.tvinput.factory;
+
+import android.content.Context;
+import android.media.tv.TvInputService.Session;
+import com.android.tv.tuner.source.TsDataSourceManager;
+import com.android.tv.tuner.tvinput.TunerSession;
+import com.android.tv.tuner.tvinput.TunerSessionExoV2;
+import com.android.tv.tuner.tvinput.datamanager.ChannelDataManager;
+import com.android.tv.common.flags.ConcurrentDvrPlaybackFlags;
+import com.android.tv.common.flags.TunerFlags;
+import javax.inject.Inject;
+
+/** Creates a {@link TunerSessionFactory}. */
+public class TunerSessionFactoryImpl implements TunerSessionFactory {
+
+ private final TunerFlags mTunerFlags;
+ private final ConcurrentDvrPlaybackFlags mConcurrentDvrPlaybackFlags;
+ private final TsDataSourceManager.Factory mTsDataSourceManagerFactory;
+
+ @Inject
+ public TunerSessionFactoryImpl(
+ TunerFlags tunerFlags,
+ ConcurrentDvrPlaybackFlags concurrentDvrPlaybackFlags,
+ TsDataSourceManager.Factory tsDataSourceManagerFactory) {
+ mTunerFlags = tunerFlags;
+ mConcurrentDvrPlaybackFlags = concurrentDvrPlaybackFlags;
+ mTsDataSourceManagerFactory = tsDataSourceManagerFactory;
+ }
+
+ @Override
+ public Session create(
+ Context context,
+ ChannelDataManager channelDataManager,
+ SessionReleasedCallback releasedCallback) {
+ return mTunerFlags.useExoplayerV2()
+ ? new TunerSessionExoV2(
+ context,
+ channelDataManager,
+ releasedCallback,
+ mConcurrentDvrPlaybackFlags,
+ mTsDataSourceManagerFactory)
+ : new TunerSession(
+ context,
+ channelDataManager,
+ releasedCallback,
+ mConcurrentDvrPlaybackFlags,
+ mTsDataSourceManagerFactory);
+ }
+}