1ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko/*
2ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Copyright (C) 2015 The Android Open Source Project
3ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko *
4ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
5ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * you may not use this file except in compliance with the License.
6ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * You may obtain a copy of the License at
7ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko *
8ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
9ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko *
10ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * Unless required by applicable law or agreed to in writing, software
11ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
12ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * See the License for the specific language governing permissions and
14ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * limitations under the License.
15ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */
16ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
1765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkopackage com.android.tv.tuner;
18ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
19ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.content.Context;
20ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.IntDef;
21ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.StringDef;
226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.support.annotation.WorkerThread;
23ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.util.Log;
246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.util.Pair;
256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.Features;
276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.customization.TvCustomizationManager;
28ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
29ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport java.lang.annotation.Retention;
30ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport java.lang.annotation.RetentionPolicy;
31ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport java.util.Objects;
32ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
33ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko/**
34ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko * A base class to handle a hardware tuner device.
35ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko */
36ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkopublic abstract class TunerHal implements AutoCloseable {
37ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected static final String TAG = "TunerHal";
38ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected static final boolean DEBUG = false;
39ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
40ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    @IntDef({ FILTER_TYPE_OTHER, FILTER_TYPE_AUDIO, FILTER_TYPE_VIDEO, FILTER_TYPE_PCR })
41ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    @Retention(RetentionPolicy.SOURCE)
42ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public @interface FilterType {}
43ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final int FILTER_TYPE_OTHER = 0;
44ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final int FILTER_TYPE_AUDIO = 1;
45ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final int FILTER_TYPE_VIDEO = 2;
46ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final int FILTER_TYPE_PCR = 3;
47ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
48ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    @StringDef({ MODULATION_8VSB, MODULATION_QAM256 })
49ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    @Retention(RetentionPolicy.SOURCE)
50ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public @interface ModulationType {}
51ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final String MODULATION_8VSB = "8VSB";
52ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    public static final String MODULATION_QAM256 = "QAM256";
53ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @IntDef({ DELIVERY_SYSTEM_UNDEFINED, DELIVERY_SYSTEM_ATSC, DELIVERY_SYSTEM_DVBC,
556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            DELIVERY_SYSTEM_DVBS, DELIVERY_SYSTEM_DVBS2, DELIVERY_SYSTEM_DVBT,
566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            DELIVERY_SYSTEM_DVBT2 })
576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Retention(RetentionPolicy.SOURCE)
586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public @interface DeliverySystemType {}
596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_UNDEFINED = 0;
606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_ATSC = 1;
616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_DVBC = 2;
626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_DVBS = 3;
636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_DVBS2 = 4;
646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_DVBT = 5;
656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int DELIVERY_SYSTEM_DVBT2 = 6;
666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @IntDef({ TUNER_TYPE_BUILT_IN, TUNER_TYPE_USB, TUNER_TYPE_NETWORK })
686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Retention(RetentionPolicy.SOURCE)
696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public @interface TunerType {}
7065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public static final int TUNER_TYPE_BUILT_IN = 1;
7165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public static final int TUNER_TYPE_USB = 2;
726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static final int TUNER_TYPE_NETWORK = 3;
7365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
74ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected static final int PID_PAT = 0;
75ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected static final int PID_ATSC_SI_BASE = 0x1ffb;
766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    protected static final int PID_DVB_SDT = 0x0011;
776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    protected static final int PID_DVB_EIT = 0x0012;
78ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected static final int DEFAULT_VSB_TUNE_TIMEOUT_MS = 2000;
79ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected static final int DEFAULT_QAM_TUNE_TIMEOUT_MS = 4000; // Some device takes time for
80ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                                                                   // QAM256 tuning.
816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @IntDef({
826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            BUILT_IN_TUNER_TYPE_LINUX_DVB
836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    })
846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @Retention(RetentionPolicy.SOURCE)
856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private @interface BuiltInTunerType {}
866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static final int BUILT_IN_TUNER_TYPE_LINUX_DVB = 1;
876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static Integer sBuiltInTunerType;
896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    protected @DeliverySystemType int mDeliverySystemType;
91ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    private boolean mIsStreaming;
92ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    private int mFrequency;
93ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    private String mModulation;
94ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
95ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    static {
96ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        System.loadLibrary("tunertvinput_jni");
97ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
98ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
992e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    /**
1002e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko     * Creates a TunerHal instance.
1012e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko     * @param context context for creating the TunerHal instance
1022e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko     * @return the TunerHal instance
1032e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko     */
1046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @WorkerThread
10565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public synchronized static TunerHal createInstance(Context context) {
10665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        TunerHal tunerHal = null;
1076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (DvbTunerHal.getNumberOfDevices(context) > 0) {
1086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (DEBUG) Log.d(TAG, "Use DvbTunerHal");
1096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            tunerHal = new DvbTunerHal(context);
110721bd0da688cd552737fbb753a00597f95103b95Adrian Roos        }
1116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return tunerHal != null && tunerHal.openFirstAvailable() ? tunerHal : null;
112ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
113ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
11465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
11565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Gets the number of tuner devices currently present.
11665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
1176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    @WorkerThread
1186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static Pair<Integer, Integer> getTunerTypeAndCount(Context context) {
1196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (useBuiltInTuner(context)) {
1206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (getBuiltInTunerType(context) == BUILT_IN_TUNER_TYPE_LINUX_DVB) {
1216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                return new Pair<>(TUNER_TYPE_BUILT_IN, DvbTunerHal.getNumberOfDevices(context));
1226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
1236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        } else {
1246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            int usbTunerCount = DvbTunerHal.getNumberOfDevices(context);
1256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (usbTunerCount > 0) {
1266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                return new Pair<>(TUNER_TYPE_USB, usbTunerCount);
1276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
12865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
1296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return new Pair<>(null, 0);
1306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /**
1336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * Check a delivery system is for DVB or not.
1346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     */
1356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static boolean isDvbDeliverySystem(@DeliverySystemType int deliverySystemType) {
1366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return deliverySystemType == DELIVERY_SYSTEM_DVBC
1376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                || deliverySystemType == DELIVERY_SYSTEM_DVBS
1386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                || deliverySystemType == DELIVERY_SYSTEM_DVBS2
1396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                || deliverySystemType == DELIVERY_SYSTEM_DVBT
1406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                || deliverySystemType == DELIVERY_SYSTEM_DVBT2;
14165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
14265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
14365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
1446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * Returns if tuner input service would use built-in tuners instead of USB tuners or network
1456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * tuners.
14665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
1476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    static boolean useBuiltInTuner(Context context) {
1486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return getBuiltInTunerType(context) != 0;
1496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static @BuiltInTunerType int getBuiltInTunerType(Context context) {
1526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (sBuiltInTunerType == null) {
1536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            sBuiltInTunerType = 0;
1546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (TvCustomizationManager.hasLinuxDvbBuiltInTuner(context)
1556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                    && DvbTunerHal.getNumberOfDevices(context) > 0) {
1566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                sBuiltInTunerType = BUILT_IN_TUNER_TYPE_LINUX_DVB;
1576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
1586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return sBuiltInTunerType;
16065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
16165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
162ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected TunerHal(Context context) {
163ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mIsStreaming = false;
164ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mFrequency = -1;
165ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mModulation = null;
166ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
167ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
168ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected boolean isStreaming() {
169ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return mIsStreaming;
170ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
171ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
1726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    protected void getDeliverySystemTypeFromDevice() {
1736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mDeliverySystemType == DELIVERY_SYSTEM_UNDEFINED) {
1746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDeliverySystemType = nativeGetDeliverySystemType(getDeviceId());
1756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /**
1796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * Returns {@code true} if this tuner HAL can be reused to save tuning time between channels
1806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * of the same frequency.
1816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     */
1826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public boolean isReusable() {
1836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return true;
1846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
186ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    @Override
187ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected void finalize() throws Throwable {
188ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        super.finalize();
189ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        close();
190ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
191ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
192ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected native void nativeFinalize(long deviceId);
193ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
194ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
195ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Acquires the first available tuner device. If there is a tuner device that is available, the
196ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * tuner device will be locked to the current instance.
197ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *
198ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @return {@code true} if the operation was successful, {@code false} otherwise
199ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
200ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected abstract boolean openFirstAvailable();
201ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
202ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected abstract boolean isDeviceOpen();
203ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
204ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected abstract long getDeviceId();
205ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
206ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
207ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Sets the tuner channel. This should be called after acquiring a tuner device.
208ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *
209ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param frequency a frequency of the channel to tune to
210ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param modulation a modulation method of the channel to tune to
2116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * @param channelNumber channel number when channel number is already known. Some tuner HAL
2126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     *        may use channelNumber instead of frequency for tune.
213ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @return {@code true} if the operation was successful, {@code false} otherwise
214ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
2156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public synchronized boolean tune(int frequency, @ModulationType String modulation,
2166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            String channelNumber) {
217ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (!isDeviceOpen()) {
218ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            Log.e(TAG, "There's no available device");
219ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return false;
220ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
221ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (mIsStreaming) {
222ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            nativeCloseAllPidFilters(getDeviceId());
223ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mIsStreaming = false;
224ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
225ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
226ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        // When tuning to a new channel in the same frequency, there's no need to stop current tuner
227ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        // device completely and the only thing necessary for tuning is reopening pid filters.
228ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (mFrequency == frequency && Objects.equals(mModulation, modulation)) {
229ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
230ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
2316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (isDvbDeliverySystem(mDeliverySystemType)) {
2326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                addPidFilter(PID_DVB_SDT, FILTER_TYPE_OTHER);
2336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                addPidFilter(PID_DVB_EIT, FILTER_TYPE_OTHER);
2346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
235ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mIsStreaming = true;
236ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return true;
237ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
238ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        int timeout_ms = modulation.equals(MODULATION_8VSB) ? DEFAULT_VSB_TUNE_TIMEOUT_MS
239ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                : DEFAULT_QAM_TUNE_TIMEOUT_MS;
240ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (nativeTune(getDeviceId(), frequency, modulation, timeout_ms)) {
241ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            addPidFilter(PID_PAT, FILTER_TYPE_OTHER);
242ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            addPidFilter(PID_ATSC_SI_BASE, FILTER_TYPE_OTHER);
2436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            if (isDvbDeliverySystem(mDeliverySystemType)) {
2446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                addPidFilter(PID_DVB_SDT, FILTER_TYPE_OTHER);
2456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                addPidFilter(PID_DVB_EIT, FILTER_TYPE_OTHER);
2466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            }
247ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mFrequency = frequency;
248ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mModulation = modulation;
249ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            mIsStreaming = true;
250ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return true;
251ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
252ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return false;
253ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
254ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
255ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected native boolean nativeTune(long deviceId, int frequency,
256ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            @ModulationType String modulation, int timeout_ms);
257ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
258ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
259ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Sets a pid filter. This should be set after setting a channel.
260ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *
261ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param pid a pid number to be added to filter list
262ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param filterType a type of pid. Must be one of (FILTER_TYPE_XXX)
263ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @return {@code true} if the operation was successful, {@code false} otherwise
264ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
26565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public synchronized boolean addPidFilter(int pid, @FilterType int filterType) {
266ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (!isDeviceOpen()) {
267ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            Log.e(TAG, "There's no available device");
268ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return false;
269ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
270ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (pid >= 0 && pid <= 0x1fff) {
271ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            nativeAddPidFilter(getDeviceId(), pid, filterType);
272ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return true;
273ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
274ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return false;
275ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
276ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
277ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected native void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType);
278ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected native void nativeCloseAllPidFilters(long deviceId);
27965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    protected native void nativeSetHasPendingTune(long deviceId, boolean hasPendingTune);
2806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    protected native int nativeGetDeliverySystemType(long deviceId);
281ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
282ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
283ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Stops current tuning. The tuner device and pid filters will be reset by this call and make
284ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * the tuner ready to accept another tune request.
285ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
28665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public synchronized void stopTune() {
287ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (isDeviceOpen()) {
288ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            if (mIsStreaming) {
289ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko                nativeCloseAllPidFilters(getDeviceId());
290ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            }
291ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            nativeStopTune(getDeviceId());
292ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
293ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mIsStreaming = false;
294ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mFrequency = -1;
295ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        mModulation = null;
296ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
297ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
29865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void setHasPendingTune(boolean hasPendingTune) {
29965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        nativeSetHasPendingTune(getDeviceId(), hasPendingTune);
30065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
30165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
3026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public int getDeliverySystemType() {
3036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mDeliverySystemType;
3046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
3056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
306ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected native void nativeStopTune(long deviceId);
307ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
308ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
309ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * This method must be called after {@link TunerHal#tune} and before
31065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * {@link TunerHal#stopTune}. Writes at most maxSize TS frames in a buffer
311ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * provided by the user. The frames employ MPEG encoding.
312ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *
313ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param javaBuffer a buffer to write the video data in
314ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @param javaBufferSize the max amount of bytes to write in this buffer. Usually this number
315ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *            should be equal to the length of the buffer.
316ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * @return the amount of bytes written in the buffer. Note that this value could be 0 if no new
317ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *         frames have been obtained since the last call.
318ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
31965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public synchronized int readTsStream(byte[] javaBuffer, int javaBufferSize) {
320ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        if (isDeviceOpen()) {
321ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return nativeWriteInBuffer(getDeviceId(), javaBuffer, javaBufferSize);
322ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        } else {
323ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            return 0;
324ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
325ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
326ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
327ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected native int nativeWriteInBuffer(long deviceId, byte[] javaBuffer, int javaBufferSize);
328ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
329ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
330ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Opens Linux DVB frontend device. This method is called from native JNI and used only for
3316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * DvbTunerHal.
332ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
333ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected int openDvbFrontEndFd() {
334ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return -1;
335ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
336ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
337ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
338ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Opens Linux DVB demux device. This method is called from native JNI and used only for
3396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * DvbTunerHal.
340ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
341ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected int openDvbDemuxFd() {
342ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return -1;
343ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
344ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
345ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
346ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     * Opens Linux DVB dvr device. This method is called from native JNI and used only for
3476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * DvbTunerHal.
348ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
349ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    protected int openDvbDvrFd() {
350ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        return -1;
351ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
352ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko}
353