blob: 8e396649cbfd4d81d40e3a6a07b9234b78f7d6da [file] [log] [blame]
/*
* Copyright 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 android.media.tv.tuner.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.media.tv.tuner.DemuxCapabilities;
import android.media.tv.tuner.Descrambler;
import android.media.tv.tuner.Lnb;
import android.media.tv.tuner.LnbCallback;
import android.media.tv.tuner.Tuner;
import android.media.tv.tuner.TunerVersionChecker;
import android.media.tv.tuner.dvr.DvrPlayback;
import android.media.tv.tuner.dvr.DvrRecorder;
import android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener;
import android.media.tv.tuner.dvr.OnRecordStatusChangedListener;
import android.media.tv.tuner.filter.AlpFilterConfiguration;
import android.media.tv.tuner.filter.AudioDescriptor;
import android.media.tv.tuner.filter.AvSettings;
import android.media.tv.tuner.filter.DownloadEvent;
import android.media.tv.tuner.filter.DownloadSettings;
import android.media.tv.tuner.filter.Filter;
import android.media.tv.tuner.filter.FilterCallback;
import android.media.tv.tuner.filter.FilterConfiguration;
import android.media.tv.tuner.filter.FilterEvent;
import android.media.tv.tuner.filter.IpCidChangeEvent;
import android.media.tv.tuner.filter.IpFilterConfiguration;
import android.media.tv.tuner.filter.IpPayloadEvent;
import android.media.tv.tuner.filter.MediaEvent;
import android.media.tv.tuner.filter.MmtpFilterConfiguration;
import android.media.tv.tuner.filter.MmtpRecordEvent;
import android.media.tv.tuner.filter.PesEvent;
import android.media.tv.tuner.filter.PesSettings;
import android.media.tv.tuner.filter.RecordSettings;
import android.media.tv.tuner.filter.RestartEvent;
import android.media.tv.tuner.filter.ScramblingStatusEvent;
import android.media.tv.tuner.filter.SectionEvent;
import android.media.tv.tuner.filter.SectionSettingsWithSectionBits;
import android.media.tv.tuner.filter.SectionSettingsWithTableInfo;
import android.media.tv.tuner.filter.Settings;
import android.media.tv.tuner.filter.SharedFilter;
import android.media.tv.tuner.filter.SharedFilterCallback;
import android.media.tv.tuner.filter.TemiEvent;
import android.media.tv.tuner.filter.TimeFilter;
import android.media.tv.tuner.filter.TlvFilterConfiguration;
import android.media.tv.tuner.filter.TsFilterConfiguration;
import android.media.tv.tuner.filter.TsRecordEvent;
import android.media.tv.tuner.frontend.AnalogFrontendCapabilities;
import android.media.tv.tuner.frontend.AnalogFrontendSettings;
import android.media.tv.tuner.frontend.Atsc3FrontendCapabilities;
import android.media.tv.tuner.frontend.Atsc3FrontendSettings;
import android.media.tv.tuner.frontend.Atsc3PlpInfo;
import android.media.tv.tuner.frontend.AtscFrontendCapabilities;
import android.media.tv.tuner.frontend.AtscFrontendSettings;
import android.media.tv.tuner.frontend.DtmbFrontendCapabilities;
import android.media.tv.tuner.frontend.DtmbFrontendSettings;
import android.media.tv.tuner.frontend.DvbcFrontendCapabilities;
import android.media.tv.tuner.frontend.DvbcFrontendSettings;
import android.media.tv.tuner.frontend.DvbsFrontendCapabilities;
import android.media.tv.tuner.frontend.DvbsFrontendSettings;
import android.media.tv.tuner.frontend.DvbtFrontendCapabilities;
import android.media.tv.tuner.frontend.DvbtFrontendSettings;
import android.media.tv.tuner.frontend.FrontendCapabilities;
import android.media.tv.tuner.frontend.FrontendInfo;
import android.media.tv.tuner.frontend.FrontendSettings;
import android.media.tv.tuner.frontend.FrontendStatus;
import android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpTuningInfo;
import android.media.tv.tuner.frontend.FrontendStatusReadiness;
import android.media.tv.tuner.frontend.Isdbs3FrontendCapabilities;
import android.media.tv.tuner.frontend.Isdbs3FrontendSettings;
import android.media.tv.tuner.frontend.IsdbsFrontendCapabilities;
import android.media.tv.tuner.frontend.IsdbsFrontendSettings;
import android.media.tv.tuner.frontend.IsdbtFrontendCapabilities;
import android.media.tv.tuner.frontend.IsdbtFrontendSettings;
import android.media.tv.tuner.frontend.OnTuneEventListener;
import android.media.tv.tuner.frontend.ScanCallback;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.RequiredFeatureRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TunerTest {
private static final String TAG = "MediaTunerTest";
@Rule
public RequiredFeatureRule featureRule = new RequiredFeatureRule(
PackageManager.FEATURE_TUNER);
private static final int TIMEOUT_MS = 10 * 1000; // 10 seconds
private static final int SCAN_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
private static final long TIMEOUT_BINDER_SERVICE_SEC = 2;
private Context mContext;
private Tuner mTuner;
private CountDownLatch mLockLatch = new CountDownLatch(1);
private TunerResourceManager mTunerResourceManager = null;
private TestServiceConnection mConnection;
private ISharedFilterTestServer mSharedFilterTestServer;
private class TestServiceConnection implements ServiceConnection {
private BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBlockingQueue.offer(service);
}
public void onServiceDisconnected(ComponentName componentName) {}
public IBinder getService() throws Exception {
final IBinder service =
mBlockingQueue.poll(TIMEOUT_BINDER_SERVICE_SEC, TimeUnit.SECONDS);
return service;
}
}
private class TunerResourceTestServiceConnection implements ServiceConnection {
private BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBlockingQueue.offer(service);
}
@Override
public void onServiceDisconnected(ComponentName componentName){}
public ITunerResourceTestServer getService() throws Exception {
final IBinder service =
mBlockingQueue.poll(TIMEOUT_BINDER_SERVICE_SEC, TimeUnit.SECONDS);
return ITunerResourceTestServer.Stub.asInterface(service);
}
}
private class TunerTestOnTuneEventListener implements OnTuneEventListener {
public static final int INVALID_TUNE_EVENT = -1;
private static final int SLEEP_TIME_MS = 100;
private static final int TIMEOUT_MS = 500;
private final ReentrantLock mLock = new ReentrantLock();
private final ConditionVariable mCV = new ConditionVariable();
private int mLastTuneEvent = INVALID_TUNE_EVENT;
@Override
public void onTuneEvent(int tuneEvent) {
synchronized (mLock) {
mLastTuneEvent = tuneEvent;
mCV.open();
}
}
public void resetLastTuneEvent() {
synchronized (mLock) {
mLastTuneEvent = INVALID_TUNE_EVENT;
}
}
public int getLastTuneEvent() {
try {
// yield to let the callback handling execute
Thread.sleep(SLEEP_TIME_MS);
} catch (Exception e) {
// ignore exception
}
synchronized (mLock) {
mCV.block(TIMEOUT_MS);
mCV.close();
return mLastTuneEvent;
}
}
}
private class TunerTestLnbCallback implements LnbCallback {
public static final int INVALID_LNB_EVENT = -1;
private static final int SLEEP_TIME_MS = 100;
private static final int TIMEOUT_MS = 500;
private final ReentrantLock mDMLock = new ReentrantLock();
private final ConditionVariable mDMCV = new ConditionVariable();
private boolean mOnDiseqcMessageCalled = false;
// will not test this as there is no good way to trigger this
@Override
public void onEvent(int lnbEventType) {}
// will test this instead
@Override
public void onDiseqcMessage(byte[] diseqcMessage) {
synchronized (mDMLock) {
mOnDiseqcMessageCalled = true;
mDMCV.open();
}
}
public void resetOnDiseqcMessageCalled() {
synchronized (mDMLock) {
mOnDiseqcMessageCalled = false;
}
}
public boolean getOnDiseqcMessageCalled() {
try {
// yield to let the callback handling execute
Thread.sleep(SLEEP_TIME_MS);
} catch (Exception e) {
// ignore exception
}
synchronized (mDMLock) {
mDMCV.block(TIMEOUT_MS);
mDMCV.close();
return mOnDiseqcMessageCalled;
}
}
}
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
InstrumentationRegistry
.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
mTuner = new Tuner(mContext, null, 100);
}
@After
public void tearDown() {
if (mTuner != null) {
mTuner.close();
mTuner = null;
}
}
@Test
public void testTunerConstructor() throws Exception {
assertNotNull(mTuner);
}
@Test
public void testTunerVersion() {
assertNotNull(mTuner);
int version = TunerVersionChecker.getTunerVersion();
assertTrue(version >= TunerVersionChecker.TUNER_VERSION_1_0);
assertTrue(version <= TunerVersionChecker.TUNER_VERSION_2_0);
}
@Test
public void testFrontendHardwareInfo() throws Exception {
String hwInfo = null;
try {
hwInfo = mTuner.getCurrentFrontendHardwareInfo();
if (TunerVersionChecker.isHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_2_0)) {
fail("Get Frontend hardware info should throw IllegalStateException.");
} else {
assertNull(hwInfo);
}
} catch (IllegalStateException e) {
// pass
}
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
hwInfo = mTuner.getCurrentFrontendHardwareInfo();
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
assertNotNull(hwInfo);
assertFalse(hwInfo.isEmpty());
} else {
assertNull(hwInfo);
}
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
}
@Test
public void testTuning() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
res = mTuner.setLnaEnabled(false);
assertTrue((res == Tuner.RESULT_SUCCESS) || (res == Tuner.RESULT_UNAVAILABLE));
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
}
@Test
public void testMultiTuning() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
// Tune again with the same frontend.
mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
for (int i = 1; i < ids.size(); i++) {
FrontendInfo info2 = mTuner.getFrontendInfoById(ids.get(i));
if (info2.getType() != info.getType()) {
res = mTuner.tune(createFrontendSettings(info2));
assertEquals(Tuner.RESULT_INVALID_STATE, res);
}
}
}
@Test
public void testScanning() throws Exception {
// Use the same test approach as testTune since it is not possible to test all frontends on
// one signal source
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.scan(
createFrontendSettings(info),
Tuner.SCAN_TYPE_AUTO,
getExecutor(),
getScanCallback());
assertEquals(Tuner.RESULT_SUCCESS, res);
res = mTuner.cancelScanning();
assertEquals(Tuner.RESULT_SUCCESS, res);
}
@Test
public void testFrontendStatus() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
for (int id : ids) {
Tuner tuner = new Tuner(mContext, null, 100);
FrontendInfo info = tuner.getFrontendInfoById(id);
int res = tuner.tune(createFrontendSettings(info));
int[] statusCapabilities = info.getStatusCapabilities();
assertNotNull(statusCapabilities);
FrontendStatus status = tuner.getFrontendStatus(statusCapabilities);
assertNotNull(status);
for (int i = 0; i < statusCapabilities.length; i++) {
switch (statusCapabilities[i]) {
case FrontendStatus.FRONTEND_STATUS_TYPE_DEMOD_LOCK:
status.isDemodLocked();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_SNR:
status.getSnr();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_BER:
status.getBer();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_PER:
status.getPer();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_PRE_BER:
status.getPerBer();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_SIGNAL_QUALITY:
status.getSignalQuality();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH:
status.getSignalStrength();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_SYMBOL_RATE:
status.getSymbolRate();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_FEC:
status.getInnerFec();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_MODULATION:
status.getModulation();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_SPECTRAL:
status.getSpectralInversion();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_LNB_VOLTAGE:
status.getLnbVoltage();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_PLP_ID:
status.getPlpId();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_EWBS:
status.isEwbs();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_AGC:
status.getAgc();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_LNA:
status.isLnaOn();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_LAYER_ERROR:
boolean[] r = status.getLayerErrors();
assertNotNull(r);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_MER:
status.getMer();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_FREQ_OFFSET:
status.getFreqOffsetLong();
status.getFreqOffset();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_HIERARCHY:
status.getHierarchy();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_RF_LOCK:
status.isRfLocked();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO:
Atsc3PlpTuningInfo[] tuningInfos = status.getAtsc3PlpTuningInfo();
if (tuningInfos != null) {
for (Atsc3PlpTuningInfo tuningInfo : tuningInfos) {
tuningInfo.getPlpId();
tuningInfo.isLocked();
tuningInfo.getUec();
}
}
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_BERS:
int[] b = status.getBers();
assertNotNull(b);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_CODERATES:
int[] c = status.getCodeRates();
assertNotNull(c);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_BANDWIDTH:
status.getBandwidth();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_GUARD_INTERVAL:
status.getGuardInterval();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_TRANSMISSION_MODE:
status.getTransmissionMode();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_UEC:
status.getUec();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_T2_SYSTEM_ID:
status.getSystemId();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_INTERLEAVINGS:
int[] l = status.getInterleaving();
assertNotNull(l);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS:
int[] segment = status.getIsdbtSegment();
assertNotNull(segment);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_TS_DATA_RATES:
int[] rates = status.getTsDataRate();
assertNotNull(rates);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_MODULATIONS_EXT:
int[] modulations = status.getExtendedModulations();
assertNotNull(modulations);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_ROLL_OFF:
status.getRollOff();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_IS_MISO_ENABLED:
status.isMisoEnabled();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_IS_LINEAR:
status.isLinear();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED:
status.isShortFramesEnabled();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_ISDBT_MODE:
status.getIsdbtMode();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG:
status.getIsdbtPartialReceptionFlag();
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_STREAM_IDS:
int[] streamIds = status.getStreamIds();
assertNotNull(streamIds);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_DVBT_CELL_IDS:
int[] cellIds = status.getDvbtCellIds();
assertNotNull(cellIds);
break;
case FrontendStatus.FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO:
List<Atsc3PlpInfo> plps = status.getAllAtsc3PlpInfo();
assertFalse(plps.isEmpty());
break;
}
}
tuner.close();
tuner = null;
}
}
@Test
public void testFrontendStatusReadiness() throws Exception {
// Test w/o active frontend
try {
int[] caps = {0};
List<FrontendStatusReadiness> readiness = mTuner.getFrontendStatusReadiness(caps);
if (TunerVersionChecker.isHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_2_0)) {
fail("Get Frontend Status Readiness should throw IllegalStateException.");
} else {
assertFalse(readiness.isEmpty());
}
} catch (IllegalStateException e) {
// pass
}
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null)
return;
assertFalse(ids.isEmpty());
for (int id : ids) {
Tuner tuner = new Tuner(mContext, null, 100);
FrontendInfo info = tuner.getFrontendInfoById(id);
int res = tuner.tune(createFrontendSettings(info));
int[] statusCapabilities = info.getStatusCapabilities();
assertNotNull(statusCapabilities);
List<FrontendStatusReadiness> readiness =
tuner.getFrontendStatusReadiness(statusCapabilities);
if (TunerVersionChecker.isHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_2_0)) {
assertEquals(readiness.size(), statusCapabilities.length);
for (int i = 0; i < readiness.size(); i++) {
assertEquals(readiness.get(i).getStatusType(), statusCapabilities[i]);
int r = readiness.get(i).getStatusReadiness();
if (r == FrontendStatusReadiness.FRONTEND_STATUS_READINESS_UNAVAILABLE
|| r == FrontendStatusReadiness.FRONTEND_STATUS_READINESS_UNSTABLE
|| r == FrontendStatusReadiness.FRONTEND_STATUS_READINESS_STABLE) {
// pass
} else {
fail("Get Frontend Status Readiness returned wrong readiness " + r);
}
}
} else {
assertNull(readiness);
}
tuner.cancelTuning();
tuner.close();
tuner = null;
}
}
@Test
public void testLnb() throws Exception {
Lnb lnb = mTuner.openLnb(getExecutor(), getLnbCallback());
if (lnb == null) return;
assertEquals(lnb.setVoltage(Lnb.VOLTAGE_5V), Tuner.RESULT_SUCCESS);
assertEquals(lnb.setTone(Lnb.TONE_NONE), Tuner.RESULT_SUCCESS);
assertEquals(
lnb.setSatellitePosition(Lnb.POSITION_A), Tuner.RESULT_SUCCESS);
lnb.sendDiseqcMessage(new byte[] {1, 2});
lnb.close();
}
@Test
public void testLnbAddAndRemoveCallback() throws Exception {
TunerTestLnbCallback lnbCB1 = new TunerTestLnbCallback();
Lnb lnb = mTuner.openLnb(getExecutor(), lnbCB1);
if (lnb == null) {
return;
}
assertEquals(lnb.setVoltage(Lnb.VOLTAGE_5V), Tuner.RESULT_SUCCESS);
assertEquals(lnb.setTone(Lnb.TONE_NONE), Tuner.RESULT_SUCCESS);
assertEquals(
lnb.setSatellitePosition(Lnb.POSITION_A), Tuner.RESULT_SUCCESS);
lnb.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
List<Integer> ids = mTuner.getFrontendIds();
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
int res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
// create sharee
Tuner sharee = new Tuner(mContext, null, 100);
sharee.shareFrontendFromTuner(mTuner);
TunerTestLnbCallback lnbCB2 = new TunerTestLnbCallback();
// add it as sharee
lnb.addCallback(getExecutor(), lnbCB2);
// check callback
lnb.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
assertTrue(lnbCB2.getOnDiseqcMessageCalled());
lnbCB2.resetOnDiseqcMessageCalled();
// remove sharee the sharee (should succeed)
assertTrue(lnb.removeCallback(lnbCB2));
// check callback (only the original owner gets callback
lnb.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
assertFalse(lnbCB2.getOnDiseqcMessageCalled());
lnbCB2.resetOnDiseqcMessageCalled();
sharee.close();
}
@Test
public void testOpenLnbByname() throws Exception {
Lnb lnb = mTuner.openLnbByName("default", getExecutor(), getLnbCallback());
if (lnb != null) {
lnb.close();
}
}
@Test
public void testCiCam() throws Exception {
// open filter to get demux resource
mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
mTuner.connectCiCam(1);
mTuner.disconnectCiCam();
}
@Test
public void testFrontendToCiCam() throws Exception {
// tune to get frontend resource
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
// TODO: get real CiCam id from MediaCas
res = mTuner.connectFrontendToCiCam(0);
} else {
assertEquals(Tuner.INVALID_LTS_ID, mTuner.connectFrontendToCiCam(0));
}
if (res != Tuner.INVALID_LTS_ID) {
assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_SUCCESS);
} else {
// Make sure the connectFrontendToCiCam only fails because the current device
// does not support connecting frontend to cicam
assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_UNAVAILABLE);
}
}
@Test
public void testRemoveOutputPid() throws Exception {
// Test w/o active frontend
try {
int status = mTuner.removeOutputPid(10);
if (TunerVersionChecker.isHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_2_0)) {
fail("Remove output PID should throw IllegalStateException.");
} else {
assertEquals(status, Tuner.RESULT_UNAVAILABLE);
}
} catch (IllegalStateException e) {
// pass
}
// tune to get frontend resource
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null)
return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
// TODO: get real CiCam id from MediaCas
res = mTuner.connectFrontendToCiCam(0);
} else {
assertEquals(Tuner.INVALID_LTS_ID, mTuner.connectFrontendToCiCam(0));
}
int status = mTuner.removeOutputPid(10);
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
if (status != Tuner.RESULT_SUCCESS) {
assertEquals(status, Tuner.RESULT_UNAVAILABLE);
}
} else {
assertEquals(status, Tuner.RESULT_UNAVAILABLE);
}
if (res != Tuner.INVALID_LTS_ID) {
assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_SUCCESS);
} else {
// Make sure the connectFrontendToCiCam only fails because the current device
// does not support connecting frontend to cicam
assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_UNAVAILABLE);
}
}
@Test
public void testAvSyncId() throws Exception {
// open filter to get demux resource
Filter f = mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
Settings settings = AvSettings
.builder(Filter.TYPE_TS, true)
.setPassthrough(false)
.setUseSecureMemory(false)
.setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
.build();
FilterConfiguration config = TsFilterConfiguration
.builder()
.setTpid(10)
.setSettings(settings)
.build();
f.configure(config);
int id = mTuner.getAvSyncHwId(f);
if (id != Tuner.INVALID_AV_SYNC_ID) {
assertNotEquals(Tuner.INVALID_TIMESTAMP, mTuner.getAvSyncTime(id));
}
}
@Test
public void testReadFilter() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
assertNotEquals(Tuner.INVALID_FILTER_ID_LONG, f.getIdLong());
} else {
assertEquals(Tuner.INVALID_FILTER_ID_LONG, f.getIdLong());
}
Settings settings = SectionSettingsWithTableInfo
.builder(Filter.TYPE_TS)
.setTableId(2)
.setVersion(1)
.setCrcEnabled(true)
.setRaw(false)
.setRepeat(false)
.build();
FilterConfiguration config = TsFilterConfiguration
.builder()
.setTpid(10)
.setSettings(settings)
.build();
f.configure(config);
f.setMonitorEventMask(
Filter.MONITOR_EVENT_SCRAMBLING_STATUS | Filter.MONITOR_EVENT_IP_CID_CHANGE);
// Tune a frontend before start the filter
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
f.start();
f.flush();
f.read(new byte[3], 0, 3);
f.stop();
f.close();
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
}
@Test
public void testAudioFilterStreamTypeConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
Settings settings = AvSettings
.builder(Filter.TYPE_TS, true)
.setPassthrough(false)
.setUseSecureMemory(false)
.setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
.build();
FilterConfiguration config = TsFilterConfiguration
.builder()
.setTpid(10)
.setSettings(settings)
.build();
f.configure(config);
// Tune a frontend before start the filter
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
f.start();
f.flush();
f.stop();
f.close();
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
}
@Test
public void testTimeFilter() throws Exception {
if (!mTuner.getDemuxCapabilities().isTimeFilterSupported()) return;
TimeFilter f = mTuner.openTimeFilter();
assertNotNull(f);
f.setCurrentTimestamp(0);
assertNotEquals(Tuner.INVALID_TIMESTAMP, f.getTimeStamp());
assertNotEquals(Tuner.INVALID_TIMESTAMP, f.getSourceTime());
f.clearTimestamp();
f.close();
}
@Test
public void testIpFilter() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_IP, Filter.SUBTYPE_IP, 1000, getExecutor(), getFilterCallback());
if (f == null) return;
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
FilterConfiguration config = IpFilterConfiguration
.builder()
.setSrcIpAddress(new byte[] {(byte) 0xC0, (byte) 0xA8, 0, 1})
.setDstIpAddress(new byte[] {(byte) 0xC0, (byte) 0xA8, 3, 4})
.setSrcPort(33)
.setDstPort(23)
.setPassthrough(false)
.setSettings(null)
.setIpFilterContextId(1)
.build();
f.configure(config);
// Tune a frontend before start the filter
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
f.start();
f.stop();
f.close();
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
}
@Test
public void testAlpSectionFilterConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_ALP, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
if (f == null) return;
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
SectionSettingsWithSectionBits settings =
SectionSettingsWithSectionBits
.builder(Filter.TYPE_TS)
.setCrcEnabled(true)
.setRepeat(false)
.setRaw(false)
.setFilter(new byte[]{2, 3, 4})
.setMask(new byte[]{7, 6, 5, 4})
.setMode(new byte[]{22, 55, 33})
.build();
AlpFilterConfiguration config =
AlpFilterConfiguration
.builder()
.setPacketType(AlpFilterConfiguration.PACKET_TYPE_COMPRESSED)
.setLengthType(AlpFilterConfiguration.LENGTH_TYPE_WITH_ADDITIONAL_HEADER)
.setSettings(settings)
.build();
f.configure(config);
f.start();
f.stop();
f.close();
}
@Test
public void testMmtpPesFilterConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_MMTP, Filter.SUBTYPE_PES, 1000, getExecutor(), getFilterCallback());
if (f == null) return;
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
PesSettings settings =
PesSettings
.builder(Filter.TYPE_TS)
.setStreamId(3)
.setRaw(false)
.build();
MmtpFilterConfiguration config =
MmtpFilterConfiguration
.builder()
.setMmtpPacketId(3)
.setSettings(settings)
.build();
f.configure(config);
f.start();
f.stop();
f.close();
}
@Test
public void testMmtpDownloadFilterConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_MMTP, Filter.SUBTYPE_DOWNLOAD,
1000, getExecutor(), getFilterCallback());
if (f == null) return;
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
DownloadSettings.Builder builder = DownloadSettings.builder(Filter.TYPE_MMTP);
if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
builder.setUseDownloadId(true);
}
builder.setDownloadId(2);
DownloadSettings settings = builder.build();
if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
assertEquals(settings.useDownloadId(), true);
} else {
assertEquals(settings.useDownloadId(), false);
}
assertEquals(settings.getDownloadId(), 2);
MmtpFilterConfiguration config =
MmtpFilterConfiguration
.builder()
.setMmtpPacketId(3)
.setSettings(settings)
.build();
f.configure(config);
f.start();
f.stop();
f.close();
}
@Test
public void testTsAvFilterConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
AvSettings settings =
AvSettings
.builder(Filter.TYPE_TS, true) // is Audio
.setPassthrough(false)
.setUseSecureMemory(false)
.setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
.build();
TsFilterConfiguration config =
TsFilterConfiguration
.builder()
.setTpid(521)
.setSettings(settings)
.build();
f.configure(config);
f.start();
f.stop();
f.close();
}
@Test
public void testTsRecordFilterConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_RECORD, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
RecordSettings settings =
RecordSettings
.builder(Filter.TYPE_TS)
.setTsIndexMask(
RecordSettings.TS_INDEX_FIRST_PACKET
| RecordSettings.TS_INDEX_PRIVATE_DATA)
.setScIndexType(RecordSettings.INDEX_TYPE_SC)
.setScIndexMask(RecordSettings.SC_INDEX_B_SLICE)
.build();
TsFilterConfiguration config =
TsFilterConfiguration
.builder()
.setTpid(521)
.setSettings(settings)
.build();
f.configure(config);
f.start();
f.stop();
f.close();
}
@Test
public void testTlvTlvFilterConfig() throws Exception {
Filter f = mTuner.openFilter(
Filter.TYPE_TLV, Filter.SUBTYPE_TLV, 1000, getExecutor(), getFilterCallback());
if (f == null) return;
assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
TlvFilterConfiguration config =
TlvFilterConfiguration
.builder()
.setPacketType(TlvFilterConfiguration.PACKET_TYPE_IPV4)
.setCompressedIpPacket(true)
.setPassthrough(false)
.setSettings(null)
.build();
f.configure(config);
f.start();
f.stop();
f.close();
}
@Test
public void testDescrambler() throws Exception {
Descrambler d = mTuner.openDescrambler();
byte[] keyToken = new byte[] {1, 3, 2};
assertNotNull(d);
Filter f = mTuner.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
assertTrue(d.isValidKeyToken(keyToken));
d.setKeyToken(keyToken);
d.addPid(Descrambler.PID_TYPE_T, 1, f);
d.removePid(Descrambler.PID_TYPE_T, 1, f);
f.close();
d.close();
}
@Test
public void testDescramblerKeyTokenValidator() throws Exception {
byte[] invalidToken = new byte[17];
byte[] validToken = new byte[] {1, 3, 2};
assertTrue(Descrambler.isValidKeyToken(validToken));
assertTrue(Descrambler.isValidKeyToken(Tuner.VOID_KEYTOKEN));
assertFalse(Descrambler.isValidKeyToken(invalidToken));
}
@Test
public void testOpenDvrRecorder() throws Exception {
DvrRecorder d = mTuner.openDvrRecorder(100, getExecutor(), getRecordListener());
assertNotNull(d);
d.close();
}
@Test
public void testOpenDvPlayback() throws Exception {
DvrPlayback d = mTuner.openDvrPlayback(100, getExecutor(), getPlaybackListener());
assertNotNull(d);
d.close();
}
@Test
public void testDemuxCapabilities() throws Exception {
DemuxCapabilities d = mTuner.getDemuxCapabilities();
assertNotNull(d);
d.getDemuxCount();
d.getRecordCount();
d.getPlaybackCount();
d.getTsFilterCount();
d.getSectionFilterCount();
d.getAudioFilterCount();
d.getVideoFilterCount();
d.getPesFilterCount();
d.getPcrFilterCount();
d.getSectionFilterLength();
d.getFilterCapabilities();
d.getLinkCapabilities();
d.isTimeFilterSupported();
}
@Test
public void testResourceLostListener() throws Exception {
mTuner.setResourceLostListener(getExecutor(), new Tuner.OnResourceLostListener() {
@Override
public void onResourceLost(Tuner tuner) {
}
});
mTuner.clearResourceLostListener();
}
@Test
public void testOnTuneEventListener() throws Exception {
mTuner.setOnTuneEventListener(getExecutor(), new OnTuneEventListener() {
@Override
public void onTuneEvent(int tuneEvent) {
}
});
mTuner.clearOnTuneEventListener();
}
@Test
public void testUpdateResourcePriority() throws Exception {
mTuner.updateResourcePriority(100, 20);
}
@Test
public void testResourceReclaimed() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
// first tune with mTuner to acquire resource
int res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
// now tune with a higher priority tuner to have mTuner's resource reclaimed
Tuner higherPrioTuner = new Tuner(mContext, null, 200);
res = higherPrioTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(higherPrioTuner.getFrontendInfo());
higherPrioTuner.close();
}
// TODO: change this to use ITunerResourceTestServer
@Test
public void testResourceReclaimedDifferentThread() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
// first tune with mTuner to acquire resource
int res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
// now tune with a higher priority tuner to have mTuner's resource reclaimed
TunerHandler tunerHandler = createTunerHandler(null);
Message msgCreate = new Message();
msgCreate.what = MSG_TUNER_HANDLER_CREATE;
msgCreate.arg1 = 200;
tunerHandler.sendMessage(msgCreate);
mTunerHandlerTaskComplete.block();
mTunerHandlerTaskComplete.close();
Message msgTune = new Message();
msgTune.what = MSG_TUNER_HANDLER_TUNE;
msgTune.obj = (Object) feSettings;
tunerHandler.sendMessage(msgTune);
// call mTuner.close in parallel
int sleepMS = 1;
//int sleepMS = (int) (Math.random() * 3.);
try {
Thread.sleep(sleepMS);
} catch (Exception e) { } // ignore
mTuner.close();
mTuner = null;
mTunerHandlerTaskComplete.block();
mTunerHandlerTaskComplete.close();
res = tunerHandler.getResult();
assertEquals(Tuner.RESULT_SUCCESS, res);
Tuner higherPrioTuner = tunerHandler.getTuner();
assertNotNull(higherPrioTuner.getFrontendInfo());
Message msgClose = new Message();
msgClose.what = MSG_TUNER_HANDLER_CLOSE;
tunerHandler.sendMessage(msgClose);
}
@Test
public void testResourceReclaimedDifferentProcess() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
int frontendIndex = 0;
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(frontendIndex));
FrontendSettings feSettings = createFrontendSettings(info);
// set up the test server
TunerResourceTestServiceConnection connection = new TunerResourceTestServiceConnection();
ITunerResourceTestServer tunerResourceTestServer = null;
Intent intent = new Intent(mContext, TunerResourceTestService.class);
// get the TunerResourceTestService
mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
tunerResourceTestServer = connection.getService();
// CASE1 - normal reclaim
//
// first tune with mTuner to acquire resource
int res = mTuner.tune(feSettings);
boolean tunerReclaimed = false;
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
// now tune with a higher priority tuner to have mTuner's resource reclaimed
// create higher priority tuner
tunerResourceTestServer.createTuner(200);
// now tune on higher priority tuner to get mTuner reclaimed
res = tunerResourceTestServer.tune(frontendIndex);
assertEquals(Tuner.RESULT_SUCCESS, res);
try {
int[] statusCapabilities = info.getStatusCapabilities();
mTuner.getFrontendStatus(statusCapabilities);
} catch (IllegalStateException e) {
tunerReclaimed = true;
mTuner.close();
mTuner = null;
}
// confirm if the mTuner is reclaimed
assertTrue(tunerReclaimed);
tunerResourceTestServer.closeTuner();
assertTrue(tunerResourceTestServer.verifyTunerIsNull());
// CASE2 - race between Tuner#close() and reclaim
mTuner = new Tuner(mContext, null, 100);
res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
tunerResourceTestServer.createTuner(200);
tunerResourceTestServer.tuneAsync(frontendIndex);
// adjust timing to induce race/deadlock
int sleepMS = 4;
//int sleepMS = (int) (Math.random() * 5.);
try {
Thread.sleep(sleepMS);
} catch (Exception e) { } // ignore
mTuner.close();
mTuner = null;
tunerResourceTestServer.closeTuner();
// unbind
mContext.unbindService(connection);
}
@Test
public void testShareFrontendFromTuner() throws Exception {
Tuner tuner100 = new Tuner(mContext, null, 100);
List<Integer> ids = tuner100.getFrontendIds();
assertFalse(ids.isEmpty());
FrontendInfo info = tuner100.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
int[] statusTypes = {1};
boolean exceptionThrown = false;
int res;
// CASE1: check resource reclaim while sharee's priority < owner's priority
// let tuner100 share from tuner200
Tuner tuner200 = new Tuner(mContext, null, 200);
res = tuner200.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
info = tuner200.getFrontendInfoById(ids.get(0));
res = tuner200.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
tuner100 = new Tuner(mContext, null, 100);
tuner100.shareFrontendFromTuner(tuner200);
// call openFilter to trigger ITunerDemux.setFrontendDataSourceById()
Filter f = tuner100.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
// setup onTuneCallback
TunerTestOnTuneEventListener cb100 = new TunerTestOnTuneEventListener();
TunerTestOnTuneEventListener cb200 = new TunerTestOnTuneEventListener();
// tune again on the owner
info = tuner200.getFrontendInfoById(ids.get(1));
tuner100.setOnTuneEventListener(getExecutor(), cb100);
tuner200.setOnTuneEventListener(getExecutor(), cb200);
res = tuner200.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertEquals(OnTuneEventListener.SIGNAL_LOCKED, cb100.getLastTuneEvent());
assertEquals(OnTuneEventListener.SIGNAL_LOCKED, cb200.getLastTuneEvent());
tuner100.clearOnTuneEventListener();
tuner200.clearOnTuneEventListener();
// now let the higher priority tuner steal the resource
Tuner tuner300 = new Tuner(mContext, null, 300);
res = tuner300.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
// confirm owner & sharee's resource gets reclaimed by confirming an exception is thrown
exceptionThrown = false;
try {
tuner200.getFrontendStatus(statusTypes);
} catch (Exception e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
exceptionThrown = false;
try {
tuner100.getFrontendStatus(statusTypes);
} catch (Exception e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
tuner100.close();
tuner200.close();
tuner300.close();
// CASE2: check resource reclaim fail when sharee's priority > new requester
tuner100 = new Tuner(mContext, null, 100);
res = tuner100.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
tuner300 = new Tuner(mContext, null, 300);
tuner300.shareFrontendFromTuner(tuner100);
f = tuner100.openFilter(
Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
assertNotNull(f);
tuner200 = new Tuner(mContext, null, 200);
res = tuner200.tune(feSettings);
assertNotEquals(Tuner.RESULT_SUCCESS, res);
// confirm the original tuner is still intact
res = tuner100.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
tuner100.close();
tuner200.close();
tuner300.close();
}
private void testTransferFeOwnershipSingleTuner() {
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) {
return;
}
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
// SCENARIO 1 - transfer and close the previous owner
// First create a tuner and tune() to acquire frontend resource
Tuner tunerA = new Tuner(mContext, null, 100);
int res = tunerA.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
// Create another tuner and share frontend from tunerA
Tuner tunerB = new Tuner(mContext, null, 500);
tunerB.shareFrontendFromTuner(tunerA);
DvrRecorder d = tunerB.openDvrRecorder(100, getExecutor(), getRecordListener());
assertNotNull(d);
// Call transferOwner in the wrong configurations and confirm it fails
assertEquals(Tuner.RESULT_INVALID_STATE, tunerB.transferOwner(tunerA));
Tuner nonSharee = new Tuner(mContext, null, 300);
assertEquals(Tuner.RESULT_INVALID_STATE, tunerA.transferOwner(nonSharee));
nonSharee.close();
// Now call it correctly to transfer ownership from tunerA to tunerB
assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
// Close the original owner (tunerA)
tunerA.close();
// Confirm the new owner (tunerB) is still functional
assertNotNull(tunerB.getFrontendInfo());
// Close the new owner (tunerB)
d.close();
tunerB.close();
// SCENARIO 2 - transfer and closeFrontend and tune on the previous owner
// First create a tuner and tune() to acquire frontend resource
tunerA = new Tuner(mContext, null, 200);
res = tunerA.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
// Create another tuner and share frontend from tunerA
tunerB = new Tuner(mContext, null, 100);
tunerB.shareFrontendFromTuner(tunerA);
assertNotNull(tunerB.getFrontendInfo());
// Transfer ownership from tunerA to tunerB
assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
// Close frontend for the original owner (tunerA)
tunerA.closeFrontend();
// Confirm tune works without going through Tuner.close() even after transferOwner()
// The purpose isn't to get tunerB's frontend revoked, but doing so as singletuner
// based test has wider coverage
res = tunerA.tune(feSettings); // this should reclaim tunerB
assertEquals(Tuner.RESULT_SUCCESS, res);
// Confirm tuberB is revoked
assertNull(tunerB.getFrontendInfo());
// Close tunerA
tunerA.close();
// close TunerB just in case
tunerB.close();
}
private void testTransferFeAndCiCamOwnership() {
List<Integer> ids = mTuner.getFrontendIds();
assertNotNull(ids);
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
// Create tuner and tune to get frontend resource
Tuner tunerA = new Tuner(mContext, null, 100);
assertEquals(Tuner.RESULT_SUCCESS, tunerA.tune(feSettings));
int ciCamId = 0;
boolean linkCiCamToFrontendSupported = false;
// connect CiCam to Frontend
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
// TODO: get real CiCam id from MediaCas
assertEquals(Tuner.RESULT_SUCCESS, tunerA.connectFrontendToCiCam(ciCamId));
linkCiCamToFrontendSupported = true;
} else {
assertEquals(Tuner.INVALID_LTS_ID, tunerA.connectFrontendToCiCam(ciCamId));
}
// connect CiCam to Demux
assertEquals(Tuner.RESULT_SUCCESS, tunerA.connectCiCam(ciCamId));
// start another tuner and connect the same CiCam to its own demux
Tuner tunerB = new Tuner(mContext, null, 400);
tunerB.shareFrontendFromTuner(tunerA);
assertNotNull(tunerB.getFrontendInfo());
assertEquals(Tuner.RESULT_SUCCESS, tunerB.connectCiCam(ciCamId));
// unlink CiCam to Demux in tunerA and transfer ownership
assertEquals(Tuner.RESULT_SUCCESS, tunerA.disconnectCiCam());
assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
// close the original owner
tunerA.close();
// disconnect CiCam from demux
assertEquals(Tuner.RESULT_SUCCESS, tunerB.disconnectCiCam());
// let Tuner.close() handle the release of CiCam
tunerB.close();
// now that the CiCam is released, disconnectFrontendToCiCam() should fail
assertEquals(Tuner.RESULT_UNAVAILABLE, tunerB.disconnectFrontendToCiCam(ciCamId));
// see if tune still works just in case
tunerA = new Tuner(mContext, null, 100);
assertEquals(Tuner.RESULT_SUCCESS, tunerA.tune(feSettings));
tunerA.close();
}
private void testTransferFeAndLnbOwnership() {
List<Integer> ids = mTuner.getFrontendIds();
assertNotNull(ids);
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
// Create tuner and tune to acquire frontend resource
Tuner tunerA = new Tuner(mContext, null, 100);
assertEquals(Tuner.RESULT_SUCCESS, tunerA.tune(feSettings));
// Open Lnb and check the callback
TunerTestLnbCallback lnbCB1 = new TunerTestLnbCallback();
Lnb lnbA = tunerA.openLnb(getExecutor(), lnbCB1);
assertNotNull(lnbA);
lnbA.setVoltage(Lnb.VOLTAGE_5V);
lnbA.setTone(Lnb.TONE_CONTINUOUS);
lnbA.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
// Create another tuner and share from tunerB
Tuner tunerB = new Tuner(mContext, null, 300);
tunerB.shareFrontendFromTuner(tunerA);
// add sharee and check the callback
TunerTestLnbCallback lnbCB2 = new TunerTestLnbCallback();
lnbA.addCallback(getExecutor(), lnbCB2);
lnbA.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
assertTrue(lnbCB2.getOnDiseqcMessageCalled());
lnbCB2.resetOnDiseqcMessageCalled();
// transfer owner and check callback
assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
lnbA.sendDiseqcMessage(new byte[] {1, 2});
assertTrue(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
assertTrue(lnbCB2.getOnDiseqcMessageCalled());
lnbCB2.resetOnDiseqcMessageCalled();
// remove the owner callback (just for testing)
assertTrue(lnbA.removeCallback(lnbCB2));
// remove sharee and check callback
assertTrue(lnbA.removeCallback(lnbCB1));
lnbA.sendDiseqcMessage(new byte[] {1, 2});
assertFalse(lnbCB1.getOnDiseqcMessageCalled());
lnbCB1.resetOnDiseqcMessageCalled();
assertFalse(lnbCB2.getOnDiseqcMessageCalled());
lnbCB2.resetOnDiseqcMessageCalled();
// close the original owner
tunerA.close();
// confirm the new owner is still intact
int[] statusCapabilities = info.getStatusCapabilities();
assertNotNull(statusCapabilities);
FrontendStatus status = tunerB.getFrontendStatus(statusCapabilities);
assertNotNull(status);
tunerB.close();
}
@Test
public void testTransferOwner() throws Exception {
testTransferFeOwnershipSingleTuner();
testTransferFeAndCiCamOwnership();
testTransferFeAndLnbOwnership();
}
@Test
public void testClose() throws Exception {
Tuner other = new Tuner(mContext, null, 100);
List<Integer> ids = other.getFrontendIds();
if (ids == null) return;
assertFalse(ids.isEmpty());
FrontendInfo info = other.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
int res = other.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(other.getFrontendInfo());
other.close();
// make sure pre-existing tuner is still functional
res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
// Frontend sharing scenario 1: close owner first
// create sharee
Tuner sharee = new Tuner(mContext, null, 100);
sharee.shareFrontendFromTuner(mTuner);
// close the owner
mTuner.close();
mTuner = null;
// check the sharee is also closed
// tune() would have failed even before close() but still..
// TODO: fix this once callback sharing is implemented
res = sharee.tune(feSettings);
assertEquals(Tuner.RESULT_UNAVAILABLE, res);
sharee.close();
// Frontend sharing scenario 2: close sharee first
// create owner first
mTuner = new Tuner(mContext, null, 100);
res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
// create sharee
sharee = new Tuner(mContext, null, 100);
sharee.shareFrontendFromTuner(mTuner);
// close sharee
sharee.close();
// confirm owner is still intact
int[] statusCapabilities = info.getStatusCapabilities();
assertNotNull(statusCapabilities);
FrontendStatus status = mTuner.getFrontendStatus(statusCapabilities);
assertNotNull(status);
}
@Test
public void testCloseFrontend() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
if (ids == null) {
return;
}
// SCENARIO 1 - without Lnb
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
FrontendSettings feSettings = createFrontendSettings(info);
int res = mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
// now close frontend
mTuner.closeFrontend();
// confirm frontend is closed
int[] statusCapabilities = info.getStatusCapabilities();
boolean frontendClosed = false;
try {
mTuner.getFrontendStatus(statusCapabilities);
} catch (IllegalStateException e) {
frontendClosed = true;
}
assertTrue(frontendClosed);
// now tune to a different setting
info = mTuner.getFrontendInfoById(ids.get(1));
feSettings = createFrontendSettings(info);
mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
FrontendStatus status = mTuner.getFrontendStatus(statusCapabilities);
assertNotNull(status);
// SCENARIO 2 - with Lnb
TunerTestLnbCallback lnbCB1 = new TunerTestLnbCallback();
Lnb lnb = mTuner.openLnb(getExecutor(), lnbCB1);
if (lnb == null) {
return;
}
mTuner.closeFrontend();
// confirm frontend is closed
statusCapabilities = info.getStatusCapabilities();
frontendClosed = false;
try {
mTuner.getFrontendStatus(statusCapabilities);
} catch (IllegalStateException e) {
frontendClosed = true;
}
assertTrue(frontendClosed);
info = mTuner.getFrontendInfoById(ids.get(0));
feSettings = createFrontendSettings(info);
mTuner.tune(feSettings);
assertEquals(Tuner.RESULT_SUCCESS, res);
assertNotNull(mTuner.getFrontendInfo());
status = mTuner.getFrontendStatus(statusCapabilities);
assertNotNull(status);
}
@Test
public void testHasUnusedFrontend1() throws Exception {
prepTRMCustomFeResourceMapTest();
// Use try block to ensure restoring the TunerResourceManager
// Note: the handles will be changed from the original value, but should be OK
try {
TunerFrontendInfo[] infos = new TunerFrontendInfo[6];
// tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBT, 2);
infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBC, 2);
infos[5] = tunerFrontendInfo(6, FrontendSettings.TYPE_DVBS, 2);
mTunerResourceManager.setFrontendInfoList(infos);
Tuner A = new Tuner(mContext, null, 100);
Tuner B = new Tuner(mContext, null, 100);
Tuner C = new Tuner(mContext, null, 100);
// check before anyone holds resource
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_UNDEFINED));
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_ATSC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
// let B hold resource
assignFeResource(B.getClientId(), FrontendSettings.TYPE_DVBT,
true /* expectedResult */, 1 /* expectedHandle */);
// check when one of the two exclusive groups are held
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
assertTrue(B.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
// let C hold the resource
assignFeResource(C.getClientId(), FrontendSettings.TYPE_DVBC,
true /* expectedResult */, 5 /* expectedHandle */);
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
assertFalse(B.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertFalse(C.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
// let go of B's resource
B.close();
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
assertTrue(B.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(C.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
C.close();
A.close();
} catch (Exception e) {
throw (e);
} finally {
cleanupTRMCustomFeResourceMapTest();
}
}
@Test
public void testHasUnusedFrontend2() throws Exception {
prepTRMCustomFeResourceMapTest();
// Use try block to ensure restoring the TunerResourceManager
// Note: the handles will be changed from the original value, but should be OK
try {
TunerFrontendInfo[] infos = new TunerFrontendInfo[5];
// tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBT, 2);
infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBC, 2);
infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBS, 3);
mTunerResourceManager.setFrontendInfoList(infos);
Tuner A = new Tuner(mContext, null, 100);
Tuner B = new Tuner(mContext, null, 100);
Tuner C = new Tuner(mContext, null, 100);
// let B hold resource
assignFeResource(B.getClientId(), FrontendSettings.TYPE_DVBT,
true /* expectedResult */, 1 /* expectedHandle */);
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
// let C hold the resource
assignFeResource(C.getClientId(), FrontendSettings.TYPE_DVBC,
true /* expectedResult */, 4 /* expectedHandle */);
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
B.close();
C.close();
} catch (Exception e) {
throw (e);
} finally {
cleanupTRMCustomFeResourceMapTest();
}
}
@Test
public void testHasUnusedFrontend3() throws Exception {
prepTRMCustomFeResourceMapTest();
// Use try block to ensure restoring the TunerResourceManager
// Note: the handles will be changed from the original value, but should be OK
try {
TunerFrontendInfo[] infos = new TunerFrontendInfo[6];
// tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBT, 2);
infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBC, 2);
infos[5] = tunerFrontendInfo(6, FrontendSettings.TYPE_DVBS, 2);
mTunerResourceManager.setFrontendInfoList(infos);
Tuner A = new Tuner(mContext, null, 100);
Tuner B = new Tuner(mContext, null, 100);
Tuner C = new Tuner(mContext, null, 100);
// let B hold resource
assignFeResource(B.getClientId(), FrontendSettings.TYPE_DVBT,
true /* expectedResult */, 1 /* expectedHandle */);
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
// let C share from B
mTunerResourceManager.shareFrontend(C.getClientId(), B.getClientId());
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
A.close();
C.close();
B.close();
} catch (Exception e) {
throw (e);
} finally {
cleanupTRMCustomFeResourceMapTest();
}
}
@Test
public void testIsLowestPriorityCornerCases() throws Exception {
prepTRMCustomFeResourceMapTest();
// Use try block to ensure restoring the TunerResourceManager
// Note: the handles will be changed from the original value, but should be OK
try {
setupSingleTunerSetupForIsLowestPriority();
// must return true when non existing frontend type is specified
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_UNDEFINED));
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_ATSC));
// must return true when no one is holding the resource
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
// must return true when the callee is the only one holding the resource
assignFeResource(mTuner.getClientId(), FrontendSettings.TYPE_DVBT,
true /* expectedResult */, 1 /* expectedHandle */);
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
} catch (Exception e) {
throw (e);
} finally {
cleanupTRMCustomFeResourceMapTest();
}
}
@Test
public void testIsLowestPriorityTwoClients() throws Exception {
prepTRMCustomFeResourceMapTest();
// Use try block to ensure restoring the TunerResourceManager
// Note: the handles will be changed from the original value, but should be OK
try {
setupSingleTunerSetupForIsLowestPriority();
testTwoClientsForIsLowestPriority(200, 100); // A > B
testTwoClientsForIsLowestPriority(100, 200); // A < B
testTwoClientsForIsLowestPriority(100, 100); // A = B
setupDualTunerSetupForIsLowestPriority();
testTwoClientsForIsLowestPriority(200, 100); // A > B
testTwoClientsForIsLowestPriority(100, 200); // A < B
testTwoClientsForIsLowestPriority(100, 100); // A = B
} catch (Exception e) {
throw (e);
} finally {
cleanupTRMCustomFeResourceMapTest();
}
}
@Test
public void testIsLowestPriorityThreeClients() throws Exception {
prepTRMCustomFeResourceMapTest();
// Use try block to ensure restoring the TunerResourceManager
// Note: the handles will be changed from the original value, but should be OK
try {
setupDualTunerSetupForIsLowestPriority();
testThreeClientsForIsLowestPriority(300, 200, 100); // A > B > C
testThreeClientsForIsLowestPriority(300, 100, 200); // A > C > B
testThreeClientsForIsLowestPriority(200, 300, 100); // B > A > C
testThreeClientsForIsLowestPriority(200, 100, 300); // C > A > B
testThreeClientsForIsLowestPriority(100, 300, 200); // B > C > A
testThreeClientsForIsLowestPriority(100, 200, 300); // C > B > A
testThreeClientsForIsLowestPriority(100, 100, 100); // A = B = C
testThreeClientsForIsLowestPriority(200, 200, 100); // A = B > C
testThreeClientsForIsLowestPriority(200, 100, 100); // A > B = C
testThreeClientsForIsLowestPriority(200, 100, 200); // A = C > B
testThreeClientsForIsLowestPriority(200, 300, 200); // B > A = C
testThreeClientsForIsLowestPriority(100, 100, 200); // C > A = B
testThreeClientsForIsLowestPriority(100, 200, 200); // B = C > A
} catch (Exception e) {
throw (e);
} finally {
cleanupTRMCustomFeResourceMapTest();
}
}
private TunerFrontendInfo tunerFrontendInfo(
int handle, int frontendType, int exclusiveGroupId) {
TunerFrontendInfo info = new TunerFrontendInfo();
info.handle = handle;
info.type = frontendType;
info.exclusiveGroupId = exclusiveGroupId;
return info;
}
/**
* Prep function for TunerTest that requires custom frontend resource map
*/
private void prepTRMCustomFeResourceMapTest() {
if (mTunerResourceManager == null) {
mTunerResourceManager = (TunerResourceManager)
mContext.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
}
mTunerResourceManager.storeResourceMap(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
mTunerResourceManager.clearResourceMap(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
}
/**
* Clean up function for TunerTest that requires custom frontend resource map
*/
private void cleanupTRMCustomFeResourceMapTest() {
// first close mTuner in case a frontend resource is opened
if (mTuner != null) {
mTuner.close();
mTuner = null;
}
// now restore the original frontend resource map
if (mTunerResourceManager != null) {
mTunerResourceManager.restoreResourceMap(
TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
}
}
private void clearFrontendInfoList() {
if (mTunerResourceManager != null) {
mTunerResourceManager.clearResourceMap(
TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
}
}
private void assignFeResource(int clientId, int frontendType,
boolean expectedResult, int expectedHandle) {
int[] feHandle = new int[1];
TunerFrontendRequest request = new TunerFrontendRequest();
request.clientId = clientId;
request.frontendType = frontendType;
boolean granted = mTunerResourceManager.requestFrontend(request, feHandle);
assertEquals(granted, expectedResult);
assertEquals(feHandle[0], expectedHandle);
}
private void setupSingleTunerSetupForIsLowestPriority() {
// first clear the frontend resource to register new set of resources
clearFrontendInfoList();
TunerFrontendInfo[] infos = new TunerFrontendInfo[3];
// tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
mTunerResourceManager.setFrontendInfoList(infos);
}
private void setupDualTunerSetupForIsLowestPriority() {
// first clear the frontend resource to register new set of resources
clearFrontendInfoList();
TunerFrontendInfo[] infos = new TunerFrontendInfo[6];
// tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBT, 2);
infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBC, 2);
infos[5] = tunerFrontendInfo(6, FrontendSettings.TYPE_DVBS, 2);
mTunerResourceManager.setFrontendInfoList(infos);
}
private void testTwoClientsForIsLowestPriority(int prioA, int prioB) {
Tuner A = new Tuner(mContext, null, prioA);
Tuner B = new Tuner(mContext, null, prioB);
// all should return true
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBT));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
// let A hold resource
assignFeResource(A.getClientId(), FrontendSettings.TYPE_DVBT,
true /* expectedResult */, 1 /* expectedHandle */);
// should return true for A as A is the sole holder
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBT));
// should return false for B only if A < B
if ( prioA < prioB ) {
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
} else {
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
}
A.close();
B.close();
}
private void testThreeClientsForIsLowestPriority(int prioA, int prioB, int prioC) {
Tuner A = new Tuner(mContext, null, prioA);
Tuner B = new Tuner(mContext, null, prioB);
Tuner C = new Tuner(mContext, null, prioC);
// all should return true
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBT));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBS));
// let A & C hold resource
assignFeResource(A.getClientId(), FrontendSettings.TYPE_DVBT,
true /* expectedResult */, 1 /* expectedHandle */);
assignFeResource(C.getClientId(), FrontendSettings.TYPE_DVBC,
true /* expectedResult */, 5 /* expectedHandle */);
// should return false for B only if A < B
if (prioA > prioB && prioB > prioC) {
assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioA > prioC && prioC > prioB) {
assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioA > prioC && prioC > prioB) {
assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioB > prioA && prioA > prioC) {
assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioC > prioA && prioA > prioB) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioB > prioC && prioC > prioA) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioC > prioB && prioB > prioA) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioA == prioB && prioB == prioC) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioA == prioB && prioB > prioC) {
assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioA > prioB && prioB == prioC) {
assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioA == prioC && prioC > prioB) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioB > prioA && prioA == prioC) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioC > prioA && prioA == prioB) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
} else if (prioB == prioC && prioC > prioA) {
assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
}
A.close();
B.close();
C.close();
}
@Test
public void testSharedFilterOneProcess() throws Exception {
Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
assertTrue(f != null);
String token1 = f.acquireSharedFilterToken();
assertTrue(token1 != null);
String token2 = f.acquireSharedFilterToken();
assertTrue(token2 == null);
// Tune a frontend before start the filter
List<Integer> ids = mTuner.getFrontendIds();
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
Settings settings = SectionSettingsWithTableInfo
.builder(Filter.TYPE_TS)
.setTableId(2)
.setVersion(1)
.setCrcEnabled(true)
.setRaw(false)
.setRepeat(false)
.build();
FilterConfiguration config = TsFilterConfiguration
.builder()
.setTpid(10)
.setSettings(settings)
.build();
assertEquals(f.configure(config), Tuner.RESULT_INVALID_STATE);
assertEquals(f.setMonitorEventMask(Filter.MONITOR_EVENT_SCRAMBLING_STATUS),
Tuner.RESULT_INVALID_STATE);
assertEquals(f.setDataSource(null), Tuner.RESULT_INVALID_STATE);
assertEquals(f.start(), Tuner.RESULT_INVALID_STATE);
assertEquals(f.flush(), Tuner.RESULT_INVALID_STATE);
assertEquals(f.read(new byte[3], 0, 3), 0);
assertEquals(f.stop(), Tuner.RESULT_INVALID_STATE);
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
f.freeSharedFilterToken(token1);
f.close();
f = null;
}
@Test
public void testSharedFilterTwoProcessesCloseInSharedFilter() throws Exception {
mConnection = new TestServiceConnection();
mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
Context.BIND_AUTO_CREATE);
mSharedFilterTestServer =
ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
String token = mSharedFilterTestServer.acquireSharedFilterToken();
assertTrue(token != null);
SharedFilter f =
Tuner.openSharedFilter(mContext, token, getExecutor(), getSharedFilterCallback());
assertTrue(f != null);
assertEquals(f.start(), Tuner.RESULT_SUCCESS);
assertEquals(f.flush(), Tuner.RESULT_SUCCESS);
int size = f.read(new byte[3], 0, 3);
assertTrue(size >= 0 && size <= 3);
assertEquals(f.stop(), Tuner.RESULT_SUCCESS);
mLockLatch = new CountDownLatch(1);
f.close();
f = null;
mSharedFilterTestServer.closeFilter();
Thread.sleep(2000);
assertEquals(mLockLatch.getCount(), 1);
mLockLatch = null;
mContext.unbindService(mConnection);
}
@Test
public void testSharedFilterTwoProcessesCloseInFilter() throws Exception {
mConnection = new TestServiceConnection();
mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
Context.BIND_AUTO_CREATE);
mSharedFilterTestServer =
ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
String token = mSharedFilterTestServer.acquireSharedFilterToken();
assertTrue(token != null);
SharedFilter f =
Tuner.openSharedFilter(mContext, token, getExecutor(), getSharedFilterCallback());
assertTrue(f != null);
assertEquals(f.start(), Tuner.RESULT_SUCCESS);
assertEquals(f.flush(), Tuner.RESULT_SUCCESS);
int size = f.read(new byte[3], 0, 3);
assertTrue(size >= 0 && size <= 3);
assertEquals(f.stop(), Tuner.RESULT_SUCCESS);
mLockLatch = new CountDownLatch(1);
mSharedFilterTestServer.closeFilter();
assertTrue(mLockLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mLockLatch = null;
f.close();
f = null;
mContext.unbindService(mConnection);
}
@Test
public void testSharedFilterTwoProcessesReleaseInFilter() throws Exception {
mConnection = new TestServiceConnection();
mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
Context.BIND_AUTO_CREATE);
mSharedFilterTestServer =
ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
String token = mSharedFilterTestServer.acquireSharedFilterToken();
assertTrue(token != null);
SharedFilter f =
Tuner.openSharedFilter(mContext, token, getExecutor(), getSharedFilterCallback());
assertTrue(f != null);
assertEquals(f.start(), Tuner.RESULT_SUCCESS);
assertEquals(f.flush(), Tuner.RESULT_SUCCESS);
int size = f.read(new byte[3], 0, 3);
assertTrue(size >= 0 && size <= 3);
assertEquals(f.stop(), Tuner.RESULT_SUCCESS);
mLockLatch = new CountDownLatch(1);
mSharedFilterTestServer.freeSharedFilterToken(token);
assertTrue(mLockLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mLockLatch = null;
mSharedFilterTestServer.closeFilter();
f.close();
f = null;
mContext.unbindService(mConnection);
}
@Test
public void testSharedFilterTwoProcessesVerifySharedFilter() throws Exception {
mConnection = new TestServiceConnection();
mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
Context.BIND_AUTO_CREATE);
mSharedFilterTestServer =
ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
assertTrue(f != null);
String token = f.acquireSharedFilterToken();
assertTrue(token != null);
// Tune a frontend before start the shared filter
List<Integer> ids = mTuner.getFrontendIds();
assertFalse(ids.isEmpty());
FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
int res = mTuner.tune(createFrontendSettings(info));
assertEquals(Tuner.RESULT_SUCCESS, res);
assertTrue(mSharedFilterTestServer.verifySharedFilter(token));
res = mTuner.cancelTuning();
assertEquals(Tuner.RESULT_SUCCESS, res);
f.freeSharedFilterToken(token);
f.close();
f = null;
mContext.unbindService(mConnection);
}
@Test
public void testFilterTimeDelay() throws Exception {
Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
int timeDelayInMs = 5000;
Instant start = Instant.now();
int status = f.delayCallbackForDurationMillis(timeDelayInMs);
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
// start / stop prevents initial race condition after first setting the time delay.
f.start();
f.stop();
mLockLatch = new CountDownLatch(1);
f.start();
assertTrue(mLockLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
Instant finish = Instant.now();
Duration timeElapsed = Duration.between(start, finish);
assertTrue(timeElapsed.toMillis() >= timeDelayInMs);
} else {
assertEquals(Tuner.RESULT_UNAVAILABLE, status);
}
f.close();
f = null;
}
@Test
public void testFilterDataSizeDelay() throws Exception {
Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
int status = f.delayCallbackUntilBytesAccumulated(5000);
if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
assertEquals(Tuner.RESULT_SUCCESS, status);
} else {
assertEquals(Tuner.RESULT_UNAVAILABLE, status);
}
f.close();
}
@Test
public void testMaxNumberOfFrontends() throws Exception {
List<Integer> ids = mTuner.getFrontendIds();
assertFalse(ids.isEmpty());
for (int i = 0; i < ids.size(); i++) {
int type = mTuner.getFrontendInfoById(ids.get(i)).getType();
if (TunerVersionChecker.isHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_2_0)) {
int defaultMax = -1;
int status;
// Check default value
defaultMax = mTuner.getMaxNumberOfFrontends(type);
assertTrue(defaultMax > 0);
// Set to -1
status = mTuner.setMaxNumberOfFrontends(type, -1);
assertEquals(Tuner.RESULT_INVALID_ARGUMENT, status);
// Set to defaultMax + 1
status = mTuner.setMaxNumberOfFrontends(type, defaultMax + 1);
assertEquals(Tuner.RESULT_INVALID_ARGUMENT, status);
// Set to 0
status = mTuner.setMaxNumberOfFrontends(type, 0);
assertEquals(Tuner.RESULT_SUCCESS, status);
// Check after set
int currentMax = -1;
currentMax = mTuner.getMaxNumberOfFrontends(type);
assertEquals(currentMax, 0);
// Reset to default
status = mTuner.setMaxNumberOfFrontends(type, defaultMax);
assertEquals(Tuner.RESULT_SUCCESS, status);
currentMax = mTuner.getMaxNumberOfFrontends(type);
assertEquals(defaultMax, currentMax);
} else {
int defaultMax = mTuner.getMaxNumberOfFrontends(type);
assertEquals(defaultMax, -1);
int status = mTuner.setMaxNumberOfFrontends(type, 0);
assertEquals(Tuner.RESULT_UNAVAILABLE, status);
}
}
}
public static Filter createTsSectionFilter(
Tuner tuner, Executor e, FilterCallback cb) {
Filter f = tuner.openFilter(Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, e, cb);
Settings settings = SectionSettingsWithTableInfo
.builder(Filter.TYPE_TS)
.setTableId(2)
.setVersion(1)
.setCrcEnabled(true)
.setRaw(false)
.setRepeat(false)
.build();
FilterConfiguration config = TsFilterConfiguration
.builder()
.setTpid(10)
.setSettings(settings)
.build();
f.configure(config);
f.setMonitorEventMask(
Filter.MONITOR_EVENT_SCRAMBLING_STATUS | Filter.MONITOR_EVENT_IP_CID_CHANGE);
return f;
}
private boolean hasTuner() {
return mContext.getPackageManager().hasSystemFeature("android.hardware.tv.tuner");
}
private Executor getExecutor() {
return Runnable::run;
}
private LnbCallback getLnbCallback() {
return new LnbCallback() {
@Override
public void onEvent(int lnbEventType) {}
@Override
public void onDiseqcMessage(byte[] diseqcMessage) {}
};
}
private FilterCallback getFilterCallback() {
return new FilterCallback() {
@Override
public void onFilterEvent(Filter filter, FilterEvent[] events) {
for (FilterEvent e : events) {
if (e instanceof DownloadEvent) {
testDownloadEvent(filter, (DownloadEvent) e);
} else if (e instanceof IpPayloadEvent) {
testIpPayloadEvent(filter, (IpPayloadEvent) e);
} else if (e instanceof MediaEvent) {
testMediaEvent(filter, (MediaEvent) e);
} else if (e instanceof MmtpRecordEvent) {
testMmtpRecordEvent(filter, (MmtpRecordEvent) e);
} else if (e instanceof PesEvent) {
testPesEvent(filter, (PesEvent) e);
} else if (e instanceof SectionEvent) {
testSectionEvent(filter, (SectionEvent) e);
} else if (e instanceof TemiEvent) {
testTemiEvent(filter, (TemiEvent) e);
} else if (e instanceof TsRecordEvent) {
testTsRecordEvent(filter, (TsRecordEvent) e);
} else if (e instanceof ScramblingStatusEvent) {
testScramblingStatusEvent(filter, (ScramblingStatusEvent) e);
} else if (e instanceof IpCidChangeEvent) {
testIpCidChangeEvent(filter, (IpCidChangeEvent) e);
} else if (e instanceof RestartEvent) {
testRestartEvent(filter, (RestartEvent) e);
}
}
if (mLockLatch != null) {
mLockLatch.countDown();
}
}
@Override
public void onFilterStatusChanged(Filter filter, int status) {}
};
}
private SharedFilterCallback getSharedFilterCallback() {
return new SharedFilterCallback() {
@Override
public void onFilterEvent(SharedFilter filter, FilterEvent[] events) {}
@Override
public void onFilterStatusChanged(SharedFilter filter, int status) {
if (status == SharedFilter.STATUS_INACCESSIBLE) {
if (mLockLatch != null) {
mLockLatch.countDown();
}
}
}
};
}
private void testDownloadEvent(Filter filter, DownloadEvent e) {
e.getItemId();
e.getDownloadId();
e.getMpuSequenceNumber();
e.getItemFragmentIndex();
e.getLastItemFragmentIndex();
long length = e.getDataLength();
if (length > 0) {
byte[] buffer = new byte[(int) length];
assertNotEquals(0, filter.read(buffer, 0, length));
}
}
private void testIpPayloadEvent(Filter filter, IpPayloadEvent e) {
long length = e.getDataLength();
if (length > 0) {
byte[] buffer = new byte[(int) length];
assertNotEquals(0, filter.read(buffer, 0, length));
}
}
private void testMediaEvent(Filter filter, MediaEvent e) {
e.getStreamId();
e.isPtsPresent();
e.getPts();
e.isDtsPresent();
e.getDts();
e.getDataLength();
e.getOffset();
e.getLinearBlock();
e.isSecureMemory();
e.getAvDataId();
e.getAudioHandle();
e.getMpuSequenceNumber();
e.isPrivateData();
e.getScIndexMask();
AudioDescriptor ad = e.getExtraMetaData();
if (ad != null) {
ad.getAdFade();
ad.getAdPan();
ad.getAdVersionTextTag();
ad.getAdGainCenter();
ad.getAdGainFront();
ad.getAdGainSurround();
}
e.release();
}
private void testMmtpRecordEvent(Filter filter, MmtpRecordEvent e) {
e.getScHevcIndexMask();
e.getDataLength();
int mpuSequenceNumber = e.getMpuSequenceNumber();
long pts = e.getPts();
int firstMbInSlice = e.getFirstMacroblockInSlice();
int tsIndexMask = e.getTsIndexMask();
if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
assertEquals(mpuSequenceNumber, Tuner.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM);
assertEquals(pts, Tuner.INVALID_TIMESTAMP);
assertEquals(firstMbInSlice, Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE);
assertEquals(tsIndexMask, 0);
}
}
private void testPesEvent(Filter filter, PesEvent e) {
e.getStreamId();
e.getMpuSequenceNumber();
long length = e.getDataLength();
if (length > 0) {
byte[] buffer = new byte[(int) length];
assertNotEquals(0, filter.read(buffer, 0, length));
}
}
private void testSectionEvent(Filter filter, SectionEvent e) {
e.getTableId();
e.getVersion();
e.getSectionNumber();
e.getDataLength();
long length = e.getDataLengthLong();
if (length > 0) {
byte[] buffer = new byte[(int) length];
assertNotEquals(0, filter.read(buffer, 0, length));
}
}
private void testTemiEvent(Filter filter, TemiEvent e) {
e.getPts();
e.getDescriptorTag();
e.getDescriptorData();
}
private void testTsRecordEvent(Filter filter, TsRecordEvent e) {
e.getPacketId();
e.getTsIndexMask();
e.getScIndexMask();
e.getDataLength();
long pts = e.getPts();
int firstMbInSlice = e.getFirstMacroblockInSlice();
if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
assertEquals(pts, Tuner.INVALID_TIMESTAMP);
assertEquals(firstMbInSlice, Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE);
}
}
private void testScramblingStatusEvent(Filter filter, ScramblingStatusEvent e) {
e.getScramblingStatus();
}
private void testIpCidChangeEvent(Filter filter, IpCidChangeEvent e) {
e.getIpCid();
}
private void testRestartEvent(Filter filter, RestartEvent e) {
e.getStartId();
}
private OnRecordStatusChangedListener getRecordListener() {
return new OnRecordStatusChangedListener() {
@Override
public void onRecordStatusChanged(int status) {}
};
}
private OnPlaybackStatusChangedListener getPlaybackListener() {
return new OnPlaybackStatusChangedListener() {
@Override
public void onPlaybackStatusChanged(int status) {}
};
}
static public FrontendSettings createFrontendSettings(FrontendInfo info) {
FrontendCapabilities caps = info.getFrontendCapabilities();
long minFreq = info.getFrequencyRangeLong().getLower();
long maxFreq = info.getFrequencyRangeLong().getUpper();
FrontendCapabilities feCaps = info.getFrontendCapabilities();
switch(info.getType()) {
case FrontendSettings.TYPE_ANALOG: {
AnalogFrontendCapabilities analogCaps = (AnalogFrontendCapabilities) caps;
int signalType = getFirstCapable(analogCaps.getSignalTypeCapability());
int sif = getFirstCapable(analogCaps.getSifStandardCapability());
return AnalogFrontendSettings
.builder()
.setFrequencyLong(55250000) //2nd freq of VHF
.setSignalType(signalType)
.setSifStandard(sif)
.build();
}
case FrontendSettings.TYPE_ATSC3: {
Atsc3FrontendCapabilities atsc3Caps = (Atsc3FrontendCapabilities) caps;
int bandwidth = getFirstCapable(atsc3Caps.getBandwidthCapability());
int demod = getFirstCapable(atsc3Caps.getDemodOutputFormatCapability());
Atsc3FrontendSettings settings =
Atsc3FrontendSettings
.builder()
.setFrequencyLong(473000000) // 1st freq of UHF
.setBandwidth(bandwidth)
.setDemodOutputFormat(demod)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_ATSC: {
AtscFrontendCapabilities atscCaps = (AtscFrontendCapabilities) caps;
int modulation = getFirstCapable(atscCaps.getModulationCapability());
return AtscFrontendSettings
.builder()
.setFrequencyLong(479000000) // 2nd freq of UHF
.setModulation(modulation)
.build();
}
case FrontendSettings.TYPE_DVBC: {
DvbcFrontendCapabilities dvbcCaps = (DvbcFrontendCapabilities) caps;
int modulation = getFirstCapable(dvbcCaps.getModulationCapability());
int fec = getFirstCapable(dvbcCaps.getFecCapability());
int annex = getFirstCapable(dvbcCaps.getAnnexCapability());
DvbcFrontendSettings settings =
DvbcFrontendSettings
.builder()
.setFrequencyLong(490000000)
.setModulation(modulation)
.setInnerFec(fec)
.setAnnex(annex)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_DVBS: {
DvbsFrontendCapabilities dvbsCaps = (DvbsFrontendCapabilities) caps;
int modulation = getFirstCapable(dvbsCaps.getModulationCapability());
int standard = getFirstCapable(dvbsCaps.getStandardCapability());
DvbsFrontendSettings settings =
DvbsFrontendSettings
.builder()
.setFrequencyLong(950000000) //950Mhz
.setModulation(modulation)
.setStandard(standard)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_DVBT: {
DvbtFrontendCapabilities dvbtCaps = (DvbtFrontendCapabilities) caps;
int transmission = getFirstCapable(dvbtCaps.getTransmissionModeCapability());
int bandwidth = getFirstCapable(dvbtCaps.getBandwidthCapability());
int constellation = getFirstCapable(dvbtCaps.getConstellationCapability());
int codeRate = getFirstCapable(dvbtCaps.getCodeRateCapability());
int hierarchy = getFirstCapable(dvbtCaps.getHierarchyCapability());
int guardInterval = getFirstCapable(dvbtCaps.getGuardIntervalCapability());
DvbtFrontendSettings settings = DvbtFrontendSettings
.builder()
.setFrequencyLong(498000000)
.setTransmissionMode(transmission)
.setBandwidth(bandwidth)
.setConstellation(constellation)
.setHierarchy(hierarchy)
.setHighPriorityCodeRate(codeRate)
.setLowPriorityCodeRate(codeRate)
.setGuardInterval(guardInterval)
.setStandard(DvbtFrontendSettings.STANDARD_T)
.setMiso(false)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_ISDBS3: {
Isdbs3FrontendCapabilities isdbs3Caps = (Isdbs3FrontendCapabilities) caps;
int modulation = getFirstCapable(isdbs3Caps.getModulationCapability());
int codeRate = getFirstCapable(isdbs3Caps.getCodeRateCapability());
Isdbs3FrontendSettings settings = Isdbs3FrontendSettings
.builder()
.setFrequencyLong(1000000000) //1000 Mhz
.setModulation(modulation)
.setCodeRate(codeRate)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_ISDBS: {
IsdbsFrontendCapabilities isdbsCaps = (IsdbsFrontendCapabilities) caps;
int modulation = getFirstCapable(isdbsCaps.getModulationCapability());
int codeRate = getFirstCapable(isdbsCaps.getCodeRateCapability());
IsdbsFrontendSettings settings = IsdbsFrontendSettings
.builder()
.setFrequencyLong(1050000000) //1050 Mhz
.setModulation(modulation)
.setCodeRate(codeRate)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_ISDBT: {
IsdbtFrontendCapabilities isdbtCaps = (IsdbtFrontendCapabilities) caps;
int mode = getFirstCapable(isdbtCaps.getModeCapability());
int bandwidth = getFirstCapable(isdbtCaps.getBandwidthCapability());
int modulation = getFirstCapable(isdbtCaps.getModulationCapability());
int codeRate = getFirstCapable(isdbtCaps.getCodeRateCapability());
int guardInterval = getFirstCapable(isdbtCaps.getGuardIntervalCapability());
int timeInterleaveMode =
getFirstCapable(isdbtCaps.getTimeInterleaveModeCapability());
boolean isSegmentAutoSupported = isdbtCaps.isSegmentAutoSupported();
boolean isFullSegmentSupported = isdbtCaps.isFullSegmentSupported();
IsdbtFrontendSettings.Builder builder = IsdbtFrontendSettings.builder();
builder.setFrequencyLong(527143000); //22 ch 527.143 MHz
builder.setBandwidth(bandwidth);
builder.setMode(mode);
builder.setGuardInterval(guardInterval);
if (!TunerVersionChecker.isHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_2_0)) {
builder.setModulation(modulation);
builder.setCodeRate(codeRate);
} else {
IsdbtFrontendSettings.IsdbtLayerSettings.Builder layerBuilder =
IsdbtFrontendSettings.IsdbtLayerSettings.builder();
layerBuilder.setTimeInterleaveMode(timeInterleaveMode);
layerBuilder.setModulation(modulation);
layerBuilder.setCodeRate(codeRate);
if (isSegmentAutoSupported) {
layerBuilder.setNumberOfSegments(0xFF);
} else {
if (isFullSegmentSupported) {
layerBuilder.setNumberOfSegments(13);
} else {
layerBuilder.setNumberOfSegments(1);
}
}
IsdbtFrontendSettings.IsdbtLayerSettings layer = layerBuilder.build();
builder.setLayerSettings(
new IsdbtFrontendSettings.IsdbtLayerSettings[] {layer});
builder.setPartialReceptionFlag(
IsdbtFrontendSettings.PARTIAL_RECEPTION_FLAG_TRUE);
}
IsdbtFrontendSettings settings = builder.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
case FrontendSettings.TYPE_DTMB: {
DtmbFrontendCapabilities dtmbCaps = (DtmbFrontendCapabilities) caps;
int modulation = getFirstCapable(dtmbCaps.getModulationCapability());
int transmissionMode = getFirstCapable(
dtmbCaps.getTransmissionModeCapability());
int guardInterval = getFirstCapable(dtmbCaps.getGuardIntervalCapability());
int timeInterleaveMode = getFirstCapable(
dtmbCaps.getTimeInterleaveModeCapability());
int codeRate = getFirstCapable(dtmbCaps.getCodeRateCapability());
int bandwidth = getFirstCapable(dtmbCaps.getBandwidthCapability());
DtmbFrontendSettings settings =
DtmbFrontendSettings
.builder()
.setFrequencyLong(506000000)
.setModulation(modulation)
.setTransmissionMode(transmissionMode)
.setBandwidth(bandwidth)
.setCodeRate(codeRate)
.setGuardInterval(guardInterval)
.setTimeInterleaveMode(timeInterleaveMode)
.build();
settings.setEndFrequencyLong(maxFreq);
return settings;
}
default:
break;
}
return null;
}
static public int getFirstCapable(int caps) {
if (caps == 0) return 0;
int mask = 1;
while ((mask & caps) == 0) {
mask = mask << 1;
}
return (mask & caps);
}
static public long getFirstCapable(long caps) {
if (caps == 0) return 0;
long mask = 1;
while ((mask & caps) == 0) {
mask = mask << 1;
}
return (mask & caps);
}
private ScanCallback getScanCallback() {
return new ScanCallback() {
@Override
public void onLocked() {
if (mLockLatch != null) {
mLockLatch.countDown();
}
}
@Override
public void onUnlocked() {
ScanCallback.super.onUnlocked();
if (mLockLatch != null) {
mLockLatch.countDown();
}
}
@Override
public void onScanStopped() {}
@Override
public void onProgress(int percent) {}
@Override
public void onFrequenciesReported(int[] frequency) {}
@Override
public void onFrequenciesLongReported(long[] frequencies) {
ScanCallback.super.onFrequenciesLongReported(frequencies);
}
@Override
public void onSymbolRatesReported(int[] rate) {}
@Override
public void onPlpIdsReported(int[] plpIds) {}
@Override
public void onGroupIdsReported(int[] groupIds) {}
@Override
public void onInputStreamIdsReported(int[] inputStreamIds) {}
@Override
public void onDvbsStandardReported(int dvbsStandard) {}
@Override
public void onDvbtStandardReported(int dvbtStandard) {}
@Override
public void onAnalogSifStandardReported(int sif) {}
@Override
public void onAtsc3PlpInfosReported(Atsc3PlpInfo[] atsc3PlpInfos) {
for (Atsc3PlpInfo info : atsc3PlpInfos) {
if (info != null) {
info.getPlpId();
info.getLlsFlag();
}
}
}
@Override
public void onHierarchyReported(int hierarchy) {}
@Override
public void onSignalTypeReported(int signalType) {}
@Override
public void onModulationReported(int modulation) {
ScanCallback.super.onModulationReported(modulation);
}
@Override
public void onPriorityReported(boolean isHighPriority) {
ScanCallback.super.onPriorityReported(isHighPriority);
}
@Override
public void onDvbcAnnexReported(int dvbcAnnext) {
ScanCallback.super.onDvbcAnnexReported(dvbcAnnext);
}
@Override
public void onDvbtCellIdsReported(int[] dvbtCellIds) {
ScanCallback.super.onDvbtCellIdsReported(dvbtCellIds);
}
};
}
// TunerHandler utility for testing Tuner api calls in a different thread
private static final int MSG_TUNER_HANDLER_CREATE = 1;
private static final int MSG_TUNER_HANDLER_TUNE = 2;
private static final int MSG_TUNER_HANDLER_CLOSE = 3;
private ConditionVariable mTunerHandlerTaskComplete = new ConditionVariable();
private TunerHandler createTunerHandler(Looper looper) {
if (looper != null) {
return new TunerHandler(looper);
} else if ((looper = Looper.myLooper()) != null) {
return new TunerHandler(looper);
} else if ((looper = Looper.getMainLooper()) != null) {
return new TunerHandler(looper);
}
return null;
}
private class TunerHandler extends Handler {
Object mLock = new Object();
Tuner mHandlersTuner;
int mResult;
private TunerHandler(Looper looper) {
super(looper);
}
public Tuner getTuner() {
synchronized (mLock) {
return mHandlersTuner;
}
}
public int getResult() {
synchronized (mLock) {
return mResult;
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TUNER_HANDLER_CREATE: {
synchronized (mLock) {
int useCase = msg.arg1;
mHandlersTuner = new Tuner(mContext, null, useCase);
}
break;
}
case MSG_TUNER_HANDLER_TUNE: {
synchronized (mLock) {
FrontendSettings feSettings = (FrontendSettings) msg.obj;
mResult = mHandlersTuner.tune(feSettings);
}
break;
}
case MSG_TUNER_HANDLER_CLOSE: {
synchronized (mLock) {
mHandlersTuner.close();
}
break;
}
default:
break;
}
mTunerHandlerTaskComplete.open();
}
}
}