HdmiRecordSources.java revision 0c5c24f23468aa71ccf10c2b6b31f6922222f15a
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.hdmi;
18
19import android.annotation.Nullable;
20import android.annotation.SystemApi;
21import android.util.Log;
22
23/**
24 * Container for record source used for one touch record.
25 * Use one of helper method by source type.
26 * <ul>
27 * <li>Own source: {@link #ofOwnSource()}
28 * <li>Digital service(channel id): {@link #ofDigitalChannelId(int, DigitalChannelData)}
29 * <li>Digital service(ARIB): {@link #ofArib(int, AribData)}
30 * <li>Digital service(ATSC): {@link #ofAtsc(int, AtscData)}
31 * <li>Digital service(DVB): {@link #ofDvb(int, DvbData)}
32 * <li>Analogue: {@link #ofAnalogue(int, int, int)}
33 * <li>External plug: {@link #ofExternalPlug(int)}
34 * <li>External physical address: {@link #ofExternalPhysicalAddress(int)}.
35 * <ul>
36 *
37 * @hide
38 */
39@SystemApi
40public final class HdmiRecordSources {
41    private static final String TAG = "HdmiRecordSources";
42
43    /** Record source type for "Own Source". */
44    private static final int RECORD_SOURCE_TYPE_OWN_SOURCE = 1;
45    /** Record source type for "Digital Service". */
46    private static final int RECORD_SOURCE_TYPE_DIGITAL_SERVICE = 2;
47    /** Record source type for "Analogue Service". */
48    private static final int RECORD_SOURCE_TYPE_ANALOGUE_SERVICE = 3;
49    /** Record source type for "Exteranl Plug". */
50    private static final int RECORD_SOURCE_TYPE_EXTERNAL_PLUG = 4;
51    /** Record source type for "External Physical Address". */
52    private static final int RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 5;
53
54    private HdmiRecordSources() {}
55
56    /**
57     * Base class for each record source.
58     * @hide
59     */
60    @SystemApi
61    public static abstract class RecordSource {
62        protected final int mSourceType;
63        protected final int mExtraDataSize;
64
65        protected RecordSource(int sourceType, int extraDataSize) {
66            mSourceType = sourceType;
67            mExtraDataSize = extraDataSize;
68        }
69
70        abstract int extraParamToByteArray(byte[] data, int index);
71
72        final int getDataSize(boolean includeType)  {
73            return includeType ? mExtraDataSize + 1 : mExtraDataSize;
74        }
75
76        final int toByteArray(boolean includeType, byte[] data, int index) {
77            if (includeType) {
78                // 1 to 8 bytes (depends on source).
79                // {[Record Source Type]} |
80                // {[Record Source Type] [Digital Service Identification]} |
81                // {[Record Source Type] [Analogue Broadcast Type] [Analogue Frequency]
82                // [Broadcast System]} |
83                // {[Record Source Type] [External Plug]} |
84                // {[Record Source Type] [External Physical Address]}
85                // The first byte is used for record source type.
86                data[index++] = (byte) mSourceType;
87            }
88            extraParamToByteArray(data, index);
89            return getDataSize(includeType);
90        }
91    }
92
93    // ---------------------------------------------------------------------------------------------
94    // ---- Own source -----------------------------------------------------------------------------
95    // ---------------------------------------------------------------------------------------------
96    /**
97     * Create {@link OwnSource} of own source.
98     */
99    public static OwnSource ofOwnSource() {
100        return new OwnSource();
101    }
102
103    /**
104     * @hide
105     */
106    @SystemApi
107    public static final class OwnSource extends RecordSource {
108        private static final int EXTRA_DATA_SIZE = 0;
109
110        private OwnSource() {
111            super(RECORD_SOURCE_TYPE_OWN_SOURCE, EXTRA_DATA_SIZE);
112        }
113
114        @Override
115        int extraParamToByteArray(byte[] data, int index) {
116            return 0;
117        }
118    }
119
120
121    // ---------------------------------------------------------------------------------------------
122    // ---- Digital service data -------------------------------------------------------------------
123    // ---------------------------------------------------------------------------------------------
124    /**
125     * Digital broadcast general types
126     */
127    /** @hide */
128    public static final int DIGITAL_BROADCAST_TYPE_ARIB = 0x0;
129    /** @hide */
130    public static final int DIGITAL_BROADCAST_TYPE_ATSC = 0x1;
131    /** @hide */
132    public static final int DIGITAL_BROADCAST_TYPE_DVB = 0x2;
133
134    /**
135     * Digital broadcast specific types
136     */
137    /** @hide */
138    public static final int DIGITAL_BROADCAST_TYPE_ARIB_BS = 0x8;
139    /** @hide */
140    public static final int DIGITAL_BROADCAST_TYPE_ARIB_CS = 0x9;
141    /** @hide */
142    public static final int DIGITAL_BROADCAST_TYPE_ARIB_T = 0xA;
143    /** @hide */
144    public static final int DIGITAL_BROADCAST_TYPE_ATSC_CABLE = 0x10;
145    /** @hide */
146    public static final int DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE = 0x11;
147    /** @hide */
148    public static final int DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL = 0x12;
149    /** @hide */
150    public static final int DIGITAL_BROADCAST_TYPE_DVB_C = 0x18;
151    /** @hide */
152    public static final int DIGITAL_BROADCAST_TYPE_DVB_S = 0x19;
153    /** @hide */
154    public static final int DIGITAL_BROADCAST_TYPE_DVB_S2 = 0x1A;
155    /** @hide */
156    public static final int DIGITAL_BROADCAST_TYPE_DVB_T = 0x1B;
157
158    /** Channel number formats. */
159    private static final int CHANNEL_NUMBER_FORMAT_1_PART = 0x01;
160    private static final int CHANNEL_NUMBER_FORMAT_2_PART = 0x02;
161
162    /**
163     * Interface for digital source identification.
164     */
165    private interface DigitalServiceIdentification {
166        int toByteArray(byte[] data, int index);
167    }
168
169    /**
170     * Digital service identification for ARIB.
171     * <p>
172     * It consists of the following fields
173     * <ul>
174     * <li>transport stream id: 2bytes
175     * <li>service id: 2bytes
176     * <li>original network id: 2bytes
177     * </ul>
178     * @hide
179     */
180    public static final class AribData implements DigitalServiceIdentification {
181        /** The transport_stream_ID of the transport stream carrying the required service */
182        private final int mTransportStreamId;
183        /** The service_ID of the required service */
184        private final int mServiceId;
185        /**
186         * The original_network_ID of the network carrying the transport stream for the required
187         * service
188         */
189        private final int mOriginalNetworkId;
190
191        public AribData(int transportStreamId, int serviceId, int originalNetworkId) {
192            mTransportStreamId = transportStreamId;
193            mServiceId = serviceId;
194            mOriginalNetworkId = originalNetworkId;
195        }
196
197        @Override
198        public int toByteArray(byte[] data, int index) {
199            return threeFieldsToSixBytes(mTransportStreamId, mServiceId, mOriginalNetworkId, data,
200                    index);
201        }
202    }
203
204    /**
205     * Digital service identification for ATSC.
206     * <p>
207     * It consists of the following fields
208     * <ul>
209     * <li>transport stream id: 2bytes
210     * <li>program number: 2bytes
211     * <li>reserved: 2bytes
212     * </ul>
213     * @hide
214     */
215    public static final class AtscData implements DigitalServiceIdentification {
216        /** The transport_stream_ID of the transport stream carrying the required service */
217        private final int mTransportStreamId;
218        /** The Program_number of the required service */
219        private final int mProgramNumber;
220
221        public AtscData(int transportStreamId, int programNumber) {
222            mTransportStreamId = transportStreamId;
223            mProgramNumber = programNumber;
224        }
225
226        @Override
227        public int toByteArray(byte[] data, int index) {
228            return threeFieldsToSixBytes(mTransportStreamId, mProgramNumber, 0, data, index);
229        }
230    }
231
232    /**
233     * Digital service identification for DVB.
234     * <p>
235     * It consists of the following fields
236     * <ul>
237     * <li>transport stream id: 2bytes
238     * <li>service id: 2bytes
239     * <li>original network id: 2bytes
240     * </ul>
241     * @hide
242     */
243    public static final class DvbData implements DigitalServiceIdentification {
244        /** The transport_stream_ID of the transport stream carrying the required service */
245        private final int mTransportStreamId;
246        /** The service_ID of the required service */
247        private final int mServiceId;
248        /**
249         * The original_network_ID of the network carrying the transport stream for the required
250         * service
251         */
252        private final int mOriginalNetworkId;
253
254        public DvbData(int transportStreamId, int serviceId, int originalNetworkId) {
255            mTransportStreamId = transportStreamId;
256            mServiceId = serviceId;
257            mOriginalNetworkId = originalNetworkId;
258        }
259
260        @Override
261        public int toByteArray(byte[] data, int index) {
262            return threeFieldsToSixBytes(mTransportStreamId, mServiceId, mOriginalNetworkId, data,
263                    index);
264        }
265    }
266
267    /**
268     * Identifies a 1-part Logical or Virtual Channel Number or a 2-part Major and Minor channel
269     * combination.
270     */
271    private static final class ChannelIdentifier {
272        /** Identifies Channel Format */
273        private final int mChannelNumberFormat;
274        /**
275         * Major Channel Number (if Channel Number Format is 2-part). If format is
276         * CHANNEL_NUMBER_FORMAT_1_PART, this will be ignored(0).
277         */
278        private final int mMajorChannelNumber;
279        /**
280         * 1-part Channel Number, or a Minor Channel Number (if Channel Number Format is 2-part).
281         */
282        private final int mMinorChannelNumber;
283
284        private ChannelIdentifier(int format, int majorNumber, int minorNumer) {
285            mChannelNumberFormat = format;
286            mMajorChannelNumber = majorNumber;
287            mMinorChannelNumber = minorNumer;
288        }
289
290        private int toByteArray(byte[] data, int index) {
291            // The first 6 bits for format, the 10 bits for major number.
292            data[index] = (byte) (((mChannelNumberFormat << 2) | (mMajorChannelNumber >>> 8) & 0x3));
293            data[index + 1] = (byte) (mMajorChannelNumber & 0xFF);
294            // Minor number uses the next 16 bits.
295            shortToByteArray((short) mMinorChannelNumber, data, index + 2);
296            return 4;
297        }
298    }
299
300    /**
301     * Digital channel id.
302     * <p>
303     * It consists of the following fields
304     * <ul>
305     * <li>channel number format: 6bits
306     * <li>major number: 10bits
307     * <li>minor number: 16bits
308     * <li>reserved: 2bytes
309     * </ul>
310     * @hide
311     */
312    public static final class DigitalChannelData implements DigitalServiceIdentification {
313        /** Identifies the logical or virtual channel number of a service. */
314        private ChannelIdentifier mChannelIdentifier;
315
316        public static DigitalChannelData ofTwoNumbers(int majorNumber, int minorNumber) {
317            return new DigitalChannelData(
318                    new ChannelIdentifier(CHANNEL_NUMBER_FORMAT_2_PART, majorNumber, minorNumber));
319        }
320
321        public static DigitalChannelData ofOneNumber(int number) {
322            return new DigitalChannelData(
323                    new ChannelIdentifier(CHANNEL_NUMBER_FORMAT_1_PART, 0, number));
324        }
325
326        private DigitalChannelData(ChannelIdentifier id) {
327            mChannelIdentifier = id;
328        }
329
330        @Override
331        public int toByteArray(byte[] data, int index) {
332            mChannelIdentifier.toByteArray(data, index);
333            // The last 2 bytes is reserved for future use.
334            data[index + 4] = 0;
335            data[index + 5] = 0;
336            return 6;
337        }
338    }
339
340    /**
341     * Create {@link DigitalServiceSource} with channel type.
342     *
343     * @param broadcastSystem digital broadcast system. It should be one of
344     *            <ul>
345     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB}
346     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC}
347     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB}
348     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_BS}
349     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_CS}
350     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_T}
351     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_CABLE}
352     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE}
353     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL}
354     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_C}
355     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S}
356     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S2}
357     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_T}
358     *            </ul>
359     * @hide
360     */
361    public static DigitalServiceSource ofDigitalChannelId(int broadcastSystem,
362            DigitalChannelData data) {
363        if (data == null) {
364            throw new IllegalArgumentException("data should not be null.");
365        }
366        switch (broadcastSystem) {
367            case DIGITAL_BROADCAST_TYPE_ARIB:
368            case DIGITAL_BROADCAST_TYPE_ATSC:
369            case DIGITAL_BROADCAST_TYPE_DVB:
370            case DIGITAL_BROADCAST_TYPE_ARIB_BS:
371            case DIGITAL_BROADCAST_TYPE_ARIB_CS:
372            case DIGITAL_BROADCAST_TYPE_ARIB_T:
373            case DIGITAL_BROADCAST_TYPE_ATSC_CABLE:
374            case DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE:
375            case DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL:
376            case DIGITAL_BROADCAST_TYPE_DVB_C:
377            case DIGITAL_BROADCAST_TYPE_DVB_S:
378            case DIGITAL_BROADCAST_TYPE_DVB_S2:
379            case DIGITAL_BROADCAST_TYPE_DVB_T:
380                return new DigitalServiceSource(
381                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL,
382                        broadcastSystem,
383                        data);
384            default:
385                Log.w(TAG, "Invalid broadcast type:" + broadcastSystem);
386                throw new IllegalArgumentException(
387                        "Invalid broadcast system value:" + broadcastSystem);
388        }
389    }
390
391    /**
392     * Create {@link DigitalServiceSource} of ARIB type.
393     *
394     * @param aribType ARIB type. It should be one of
395     *            <ul>
396     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB}
397     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_BS}
398     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_CS}
399     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_T}
400     *            </ul>
401     * @hide
402     */
403    @Nullable
404    public static DigitalServiceSource ofArib(int aribType, AribData data) {
405        if (data == null) {
406            throw new IllegalArgumentException("data should not be null.");
407        }
408        switch (aribType) {
409            case DIGITAL_BROADCAST_TYPE_ARIB:
410            case DIGITAL_BROADCAST_TYPE_ARIB_BS:
411            case DIGITAL_BROADCAST_TYPE_ARIB_CS:
412            case DIGITAL_BROADCAST_TYPE_ARIB_T:
413                return new DigitalServiceSource(
414                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID,
415                        aribType, data);
416            default:
417                Log.w(TAG, "Invalid ARIB type:" + aribType);
418                throw new IllegalArgumentException("type should not be null.");
419        }
420    }
421
422    /**
423     * Create {@link DigitalServiceSource} of ATSC type.
424     *
425     * @param atscType ATSC type. It should be one of
426     *            <ul>
427     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC}
428     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_CABLE}
429     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE}
430     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL}
431     *            </ul>
432     * @hide
433     */
434    @Nullable
435    public static DigitalServiceSource ofAtsc(int atscType, AtscData data) {
436        if (data == null) {
437            throw new IllegalArgumentException("data should not be null.");
438        }
439        switch (atscType) {
440            case DIGITAL_BROADCAST_TYPE_ATSC:
441            case DIGITAL_BROADCAST_TYPE_ATSC_CABLE:
442            case DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE:
443            case DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL:
444                return new DigitalServiceSource(
445                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID,
446                        atscType, data);
447            default:
448                Log.w(TAG, "Invalid ATSC type:" + atscType);
449                throw new IllegalArgumentException("Invalid ATSC type:" + atscType);
450        }
451    }
452
453    /**
454     * Create {@link DigitalServiceSource} of ATSC type.
455     *
456     * @param dvbType DVB type. It should be one of
457     *            <ul>
458     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB}
459     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_C}
460     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S}
461     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S2}
462     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_T}
463     *            </ul>
464     * @hide
465     */
466    @Nullable
467    public static DigitalServiceSource ofDvb(int dvbType, DvbData data) {
468        if (data == null) {
469            throw new IllegalArgumentException("data should not be null.");
470        }
471        switch (dvbType) {
472            case DIGITAL_BROADCAST_TYPE_DVB:
473            case DIGITAL_BROADCAST_TYPE_DVB_C:
474            case DIGITAL_BROADCAST_TYPE_DVB_S:
475            case DIGITAL_BROADCAST_TYPE_DVB_S2:
476            case DIGITAL_BROADCAST_TYPE_DVB_T:
477                return new DigitalServiceSource(
478                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID,
479                        dvbType, data);
480            default:
481                Log.w(TAG, "Invalid DVB type:" + dvbType);
482                throw new IllegalArgumentException("Invalid DVB type:" + dvbType);
483        }
484    }
485
486    /**
487     * Record source container for "Digital Service".
488     * <ul>
489     * <li>[Record Source Type] - 1 byte
490     * <li>[Digital Identification] - 7 bytes
491     * </ul>
492     * @hide
493     */
494    @SystemApi
495    public static final class DigitalServiceSource extends RecordSource {
496        /** Indicates that a service is identified by digital service IDs. */
497        private static final int DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID = 0;
498        /** Indicates that a service is identified by a logical or virtual channel number. */
499        private static final int DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL = 1;
500
501        static final int EXTRA_DATA_SIZE = 7;
502
503        /**
504         * Type of identification. It should be one of DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID and
505         * DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL
506         */
507        private final int mIdentificationMethod;
508        /**
509         * Indicates the Digital Broadcast System of required service. This is present irrespective
510         * of the state of [Service Identification Method].
511         */
512        private final int mBroadcastSystem;
513
514        /**
515         * Extra parameter for digital service identification.
516         */
517        private final DigitalServiceIdentification mIdentification;
518
519        private DigitalServiceSource(int identificatinoMethod, int broadcastSystem,
520                DigitalServiceIdentification identification) {
521            super(RECORD_SOURCE_TYPE_DIGITAL_SERVICE, EXTRA_DATA_SIZE);
522            mIdentificationMethod = identificatinoMethod;
523            mBroadcastSystem = broadcastSystem;
524            mIdentification = identification;
525        }
526
527        @Override
528        int extraParamToByteArray(byte[] data, int index) {
529            data[index] = (byte) ((mIdentificationMethod << 7) | (mBroadcastSystem & 0x7F));
530            mIdentification.toByteArray(data, index + 1);
531            return EXTRA_DATA_SIZE;
532
533        }
534    }
535
536
537    // ---------------------------------------------------------------------------------------------
538    // ---- Analogue service data ------------------------------------------------------------------
539    // ---------------------------------------------------------------------------------------------
540    /**
541     * Analogue broadcast types.
542     */
543    /** @hide */
544    public static final int ANALOGUE_BROADCAST_TYPE_CABLE = 0x0;
545    /** @hide */
546    public static final int ANALOGUE_BROADCAST_TYPE_SATELLITE = 0x1;
547    /** @hide */
548    public static final int ANALOGUE_BROADCAST_TYPE_TERRESTRIAL = 0x2;
549
550    /**
551     * Broadcast system values.
552     */
553    /** @hide */
554    public static final int BROADCAST_SYSTEM_PAL_BG = 0;
555    /** @hide */
556    public static final int BROADCAST_SYSTEM_SECAM_LP = 1;
557    /** @hide */
558    public static final int BROADCAST_SYSTEM_PAL_M = 2;
559    /** @hide */
560    public static final int BROADCAST_SYSTEM_NTSC_M = 3;
561    /** @hide */
562    public static final int BROADCAST_SYSTEM_PAL_I = 4;
563    /** @hide */
564    public static final int BROADCAST_SYSTEM_SECAM_DK = 5;
565    /** @hide */
566    public static final int BROADCAST_SYSTEM_SECAM_BG = 6;
567    /** @hide */
568    public static final int BROADCAST_SYSTEM_SECAM_L = 7;
569    /** @hide */
570    public static final int BROADCAST_SYSTEM_PAL_DK = 8;
571    /** @hide */
572    public static final int BROADCAST_SYSTEM_PAL_OTHER_SYSTEM = 31;
573
574    /**
575     * Create {@link AnalogueServiceSource} of analogue service.
576     *
577     * @param broadcastType
578     * @param frequency
579     * @param broadcastSystem
580     * @hide
581     */
582    @Nullable
583    public static AnalogueServiceSource ofAnalogue(int broadcastType, int frequency,
584            int broadcastSystem){
585        if (broadcastType < ANALOGUE_BROADCAST_TYPE_CABLE
586                || broadcastType > ANALOGUE_BROADCAST_TYPE_TERRESTRIAL) {
587            Log.w(TAG, "Invalid Broadcast type:" + broadcastType);
588            throw new IllegalArgumentException("Invalid Broadcast type:" + broadcastType);
589        }
590        if (frequency < 0 || frequency > 0xFFFF) {
591            Log.w(TAG, "Invalid frequency value[0x0000-0xFFFF]:" + frequency);
592            throw new IllegalArgumentException(
593                    "Invalid frequency value[0x0000-0xFFFF]:" + frequency);
594        }
595        if (broadcastSystem < BROADCAST_SYSTEM_PAL_BG
596                || broadcastSystem > BROADCAST_SYSTEM_PAL_OTHER_SYSTEM) {
597
598            Log.w(TAG, "Invalid Broadcast system:" + broadcastSystem);
599            throw new IllegalArgumentException(
600                    "Invalid Broadcast system:" + broadcastSystem);
601        }
602
603        return new AnalogueServiceSource(broadcastType, frequency, broadcastSystem);
604    }
605
606    /**
607     * Record source for analogue service data. It consists of
608     * <ul>
609     * <li>[Record Source Type] - 1 byte
610     * <li>[Analogue Broadcast Type] - 1 byte
611     * <li>[Analogue Frequency] - 2 bytes
612     * <li>[Broadcast System] - 1 byte
613     * </ul>
614     * @hide
615     */
616    @SystemApi
617    public static final class AnalogueServiceSource extends RecordSource {
618        static final int EXTRA_DATA_SIZE = 4;
619
620        /** Indicates the Analogue broadcast type. */
621        private final int mBroadcastType;
622        /** Used to specify the frequency used by an analogue tuner. 0x0000<N<0xFFFF. */
623        private final int mFrequency;
624        /**
625         * This specifies information about the color system, the sound carrier and the
626         * IF-frequency.
627         */
628        private final int mBroadcastSystem;
629
630        private AnalogueServiceSource(int broadcastType, int frequency, int broadcastSystem) {
631            super(RECORD_SOURCE_TYPE_ANALOGUE_SERVICE, EXTRA_DATA_SIZE);
632            mBroadcastType = broadcastType;
633            mFrequency = frequency;
634            mBroadcastSystem = broadcastSystem;
635        }
636
637        @Override
638        protected int extraParamToByteArray(byte[] data, int index) {
639            // [Analogue Broadcast Type] - 1 byte
640            data[index] = (byte) mBroadcastType;
641            // [Analogue Frequency] - 2 bytes
642            shortToByteArray((short) mFrequency, data, index + 1);
643            // [Broadcast System] - 1 byte
644            data[index + 3] = (byte) mBroadcastSystem;
645            return EXTRA_DATA_SIZE;
646        }
647    }
648
649
650    // ---------------------------------------------------------------------------------------------
651    // ---- External plug data ---------------------------------------------------------------------
652    // ---------------------------------------------------------------------------------------------
653    /**
654     * Create {@link ExternalPlugData} of external plug type.
655     *
656     * @param plugNumber plug number. It should be in range of [1, 255]
657     * @hide
658     */
659    public static ExternalPlugData ofExternalPlug(int plugNumber) {
660        if (plugNumber < 1 || plugNumber > 255) {
661            Log.w(TAG, "Invalid plug number[1-255]" + plugNumber);
662            throw new IllegalArgumentException("Invalid plug number[1-255]" + plugNumber);
663        }
664        return new ExternalPlugData(plugNumber);
665    }
666
667    /**
668     * Record source for external plug (external non-HDMI device connect) type.
669     * <ul>
670     * <li>[Record Source Type] - 1 byte
671     * <li>[External Plug] - 1 byte
672     * </ul>
673     * @hide
674     */
675    @SystemApi
676    public static final class ExternalPlugData extends RecordSource {
677        static final int EXTRA_DATA_SIZE = 1;
678
679        /** External Plug number on the Recording Device. */
680        private final int mPlugNumber;
681
682        private ExternalPlugData(int plugNumber) {
683            super(RECORD_SOURCE_TYPE_EXTERNAL_PLUG, EXTRA_DATA_SIZE);
684            mPlugNumber = plugNumber;
685        }
686
687        @Override
688        int extraParamToByteArray(byte[] data, int index) {
689            data[index] = (byte) mPlugNumber;
690            return EXTRA_DATA_SIZE;
691        }
692    }
693
694    // ---------------------------------------------------------------------------------------------
695    // ---- External physical address --------------------------------------------------------------
696    // ---------------------------------------------------------------------------------------------
697    /**
698     * Create {@link ExternalPhysicalAddress} of external physical address.
699     *
700     * @param physicalAddress
701     * @hide
702     */
703    public static ExternalPhysicalAddress ofExternalPhysicalAddress(int physicalAddress) {
704        if ((physicalAddress & ~0xFFFF) != 0) {
705            Log.w(TAG, "Invalid physical address:" + physicalAddress);
706            throw new IllegalArgumentException("Invalid physical address:" + physicalAddress);
707        }
708
709        return new ExternalPhysicalAddress(physicalAddress);
710    }
711
712    /**
713     * Record source for external physical address.
714     * <ul>
715     * <li>[Record Source Type] - 1 byte
716     * <li>[Physical address] - 2 byte
717     * </ul>
718     * @hide
719     */
720    @SystemApi
721    public static final class ExternalPhysicalAddress extends RecordSource {
722        static final int EXTRA_DATA_SIZE = 2;
723
724        private final int mPhysicalAddress;
725
726        private ExternalPhysicalAddress(int physicalAddress) {
727            super(RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS, EXTRA_DATA_SIZE);
728            mPhysicalAddress = physicalAddress;
729        }
730
731        @Override
732        int extraParamToByteArray(byte[] data, int index) {
733            shortToByteArray((short) mPhysicalAddress, data, index);
734            return EXTRA_DATA_SIZE;
735        }
736    }
737
738
739    // ---------------------------------------------------------------------------------------------
740    // ------- Helper methods ----------------------------------------------------------------------
741    // ---------------------------------------------------------------------------------------------
742    private static int threeFieldsToSixBytes(int first, int second, int third, byte[] data,
743            int index) {
744        shortToByteArray((short) first, data, index);
745        shortToByteArray((short) second, data, index + 2);
746        shortToByteArray((short) third, data, index + 4);
747        return 6;
748    }
749
750    private static int shortToByteArray(short value, byte[] byteArray, int index) {
751        byteArray[index] = (byte) ((value >>> 8) & 0xFF);
752        byteArray[index + 1] = (byte) (value & 0xFF);
753        return 2;
754    }
755
756    /**
757     * Check the byte array of record source.
758     * @hide
759     */
760    @SystemApi
761    public static boolean checkRecordSource(byte[] recordSource) {
762        int recordSourceType = recordSource[0];
763        int extraDataSize = recordSource.length - 1;
764        switch (recordSourceType) {
765            case RECORD_SOURCE_TYPE_OWN_SOURCE:
766                return extraDataSize == OwnSource.EXTRA_DATA_SIZE;
767            case RECORD_SOURCE_TYPE_DIGITAL_SERVICE:
768                return extraDataSize == DigitalServiceSource.EXTRA_DATA_SIZE;
769            case RECORD_SOURCE_TYPE_ANALOGUE_SERVICE:
770                return extraDataSize == AnalogueServiceSource.EXTRA_DATA_SIZE;
771            case RECORD_SOURCE_TYPE_EXTERNAL_PLUG:
772                return extraDataSize == ExternalPlugData.EXTRA_DATA_SIZE;
773            case RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS:
774                return extraDataSize == ExternalPhysicalAddress.EXTRA_DATA_SIZE;
775            default:
776                return false;
777        }
778    }
779}
780