פיתוח שירות קלט לטלוויזיה

שירות קלט טלוויזיה מייצג מקור זרם מדיה ומאפשר לכם להציג את תוכן המדיה אופנה לינארית משודרת בטלוויזיה כערוצים ותוכניות. באמצעות שירות קלט של טלוויזיה, ניתן לספק אמצעי בקרת הורים, מידע על לוח השידורים וסיווגי תוכן. שירות הקלט של הטלוויזיה פועל עם אפליקציית מערכת ההפעלה Android TV. האפליקציה הזו שולטת בתוכן של הערוץ ומציגה אותו בסופו של דבר בטלוויזיה. אפליקציית המערכת לטלוויזיה פותחה במיוחד למכשיר ולא ניתנת לשינוי באמצעות אפליקציות של צד שלישי. למידע נוסף על מסגרת קלט הטלוויזיה (TIF) של הארכיטקטורה והרכיבים שלה, מסגרת קלט לטלוויזיה.

יצירת שירות קלט לטלוויזיה באמצעות הספרייה הנלווית של TIF

הספרייה הנלווית של TIF היא מסגרת שמאפשרת הרחבה של תכונות נפוצות של שירות קלט טלוויזיה. היא מיועדת לשימוש של יצרני ציוד מקורי (OEM) כדי ליצור ערוצים ל-Android 5.0 (רמת API 21) עד Android 7.1 (רמת API 25) בלבד.

עדכון הפרויקט

הספרייה הנלווית של TIF זמינה לשימוש של יצרני ציוד מקורי (OEM) מדור קודם קלט android-sample-input של מאגר הנתונים. במאגר הזה תוכלו לראות דוגמה לאופן שבו אפשר לכלול את הספרייה באפליקציה.

הצהרה על שירות הקלט של הטלוויזיה במניפסט

באפליקציה צריך לספק מספר תואם ל-TvInputService השירות שבו המערכת משתמשת כדי לגשת לאפליקציה. ה-TIF הספרייה הנלווית מספקת את המחלקה BaseTvInputService, מספק יישום ברירת מחדל של TvInputService שאפשר להתאים אישית. יוצרים מחלקה משנית של BaseTvInputService, ולהצהיר על המחלקה המשנית במניפסט כשירות.

בהצהרת המניפסט, מציינים את הרשאה מסוג BIND_TV_INPUT כדי לאפשר שירות לחיבור קלט הטלוויזיה למערכת. שירות מערכת מבצע את הקישור, ויש לו ההרשאה BIND_TV_INPUT. אפליקציית המערכת של הטלוויזיה שולחת בקשות לשירותי קלט של טלוויזיה דרך הממשק של TvInputManager.

בהצהרת השירות, צריך לכלול מסנן Intent שמציין TvInputService כפעולה שיש לבצע עם בכוונה טובה. בנוסף, מצהירים על המטא-נתונים של השירות כמשאב XML נפרד. מוצגים הצהרת שירות, מסנן Intent והצהרת מטא-נתונים של שירות בדוגמה הבאה:

<service android:name=".rich.RichTvInputService"
    android:label="@string/rich_input_label"
    android:permission="android.permission.BIND_TV_INPUT">
    <!-- Required filter used by the system to launch our account service. -->
    <intent-filter>
        <action android:name="android.media.tv.TvInputService" />
    </intent-filter>
    <!-- An XML file which describes this input. This provides pointers to
    the RichTvInputSetupActivity to the system/TV app. -->
    <meta-data
        android:name="android.media.tv.input"
        android:resource="@xml/richtvinputservice" />
</service>

מגדירים את המטא-נתונים של השירות בקובץ XML נפרד. השירות קובץ ה-XML של המטא-נתונים חייב לכלול ממשק הגדרה שמתאר את הקלט של הטלוויזיה הגדרה ראשונית וסריקת ערוצים. קובץ המטא-נתונים צריך להכיל גם סימון שמציין אם המשתמשים יכולים להקליט תוכן. לקבלת מידע נוסף לקבלת מידע על תמיכה בהקלטת תוכן באפליקציה שלך, הקלטת תוכן לתמיכה.

קובץ המטא-נתונים של השירות נמצא בספריית משאבי ה-XML של האפליקציה, והערך שלו חייב להיות זהה לשם המשאב שעליו הצהרת . על סמך ערכי המניפסט מהדוגמה הקודמת, ליצור את קובץ ה-XML ב-res/xml/richtvinputservice.xml, עם המאפיין פריטי התוכן הבאים:

<?xml version="1.0" encoding="utf-8"?>
<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
  android:canRecord="true"
  android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />

הגדרת ערוצים ויצירת פעילות הגדרה

שירות הקלט של הטלוויזיה חייב להגדיר לפחות ערוץ אחד שמשתמשים גישה דרך אפליקציית המערכת של טלוויזיה. עליך לרשום את הערוצים שלך במסד הנתונים של המערכת, ותספק פעילות הגדרה שהמערכת מופעל כשלא ניתן למצוא ערוץ לאפליקציה.

ראשית, צריך לאפשר לאפליקציה לקרוא ולכתוב במערכת אלקטרוניקה של המערכת מדריך תכנות (EPG), שהנתונים שלו כוללים ערוצים ותוכניות זמינים למשתמש. כדי לאפשר לאפליקציה לבצע את הפעולות האלה, צריך לסנכרן עם EPG אחרי הפעלה מחדש של המכשיר, מוסיפים את הרכיבים הבאים לקובץ המניפסט של האפליקציה:

<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>

צריך להוסיף את הרכיב הבא כדי לוודא שהאפליקציה מופיעה חנות Google Play כאפליקציה שמספקת ערוצי תוכן ב-Android TV:

<uses-feature
    android:name="android.software.live_tv"
    android:required="true" />

בשלב הבא יוצרים כיתה שמרחיבה את EpgSyncJobService בכיתה. שיעור מופשט זה מאפשר ליצור בקלות שירות משימות יוצר ומעדכן ערוצים במסד הנתונים של המערכת.

במחלקה המשנית, יצירה והחזרה של רשימת הערוצים המלאה ב- getChannels() אם הערוצים מגיעים מקובץ XMLTV, להשתמש במחלקה XmlTvParser. אחרת, ערוצים באופן פרוגרמטי באמצעות המחלקה Channel.Builder.

המערכת קוראת לכל ערוץ getProgramsForChannel() כשנדרשת רשימה של תוכניות שניתן לצפות בהן במסגרת חלון זמן נתון בערוץ. החזרת רשימה של Program אובייקטים עבור . להשתמש בכיתה XmlTvParser כדי לקבל תוכניות מ XMLTV, או ליצור אותם באופן פרוגרמטי באמצעות כיתה אחת (Program.Builder).

לכל אובייקט Program משתמשים InternalProviderData כדי להגדיר פרטי תוכנית, כמו סוג הסרטון של התוכנה. אם יש לך רק מספר מוגבל של תוכניות אני רוצה שהערוץ יחזור על עצמו בלולאה, השתמשו השיטה InternalProviderData.setRepeatable() עם ערך של true כשמגדירים את המידע על התוכנית.

אחרי שמטמיעים את שירות המשימה, מוסיפים אותו לקובץ המניפסט של האפליקציה:

<service
    android:name=".sync.SampleJobService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="true" />

לבסוף, יוצרים פעילות הגדרה. פעילות ההגדרה אמורה לספק אפשרות כדי לסנכרן את נתוני הערוץ והתוכנה. אחת מהדרכים לעשות זאת היא על ידי המשתמש דרך ממשק המשתמש בפעילות. יכול להיות שגם האפליקציה תבצע את הפעולה הזו באופן אוטומטי כשהפעילות מתחילה. כאשר פעילות ההגדרה צריכה לסנכרן את הערוץ פרטי תוכנית, האפליקציה צריכה להתחיל את שירות העבודה:

Kotlin

val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID)
EpgSyncJobService.cancelAllSyncRequests(getActivity())
EpgSyncJobService.requestImmediateSync(
        getActivity(),
        inputId,
        ComponentName(getActivity(), SampleJobService::class.java)
)

Java

String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
EpgSyncJobService.cancelAllSyncRequests(getActivity());
EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
        new ComponentName(getActivity(), SampleJobService.class));

שימוש בשיטה requestImmediateSync() כדי לסנכרן את שירות העבודה. המשתמש צריך להמתין לסיום הסנכרון, לכן עליך שתקופת הבקשה תהיה קצרה יחסית.

משתמשים בשיטה setUpPeriodicSync() כדי לקבל את שירות המשימה לסנכרן מדי פעם את נתוני הערוץ והתוכנית ברקע:

Kotlin

EpgSyncJobService.setUpPeriodicSync(
        context,
        inputId,
        ComponentName(context, SampleJobService::class.java)
)

Java

EpgSyncJobService.setUpPeriodicSync(context, inputId,
        new ComponentName(context, SampleJobService.class));

הספרייה הנלווית של TIF מספקת שיטה נוספת של עומס יתר requestImmediateSync() שמאפשר לציין את משך הזמן של כדי לסנכרן אותם באלפיות השנייה. שיטת ברירת המחדל מסנכרנת הערך של נתוני הערוץ.

הספרייה הנלווית של TIF מספקת גם שיטה של עומס יתר setUpPeriodicSync() שמאפשר לציין את משך הזמן של של נתוני הערוץ לסנכרון, ובאיזו תדירות אמור להתבצע הסנכרון התקופתי. שיטת ברירת המחדל מסנכרנת 48 שעות של נתוני הערוץ כל 12 שעות.

למידע נוסף על נתוני הערוץ ועל EPG: עבודה עם נתוני הערוץ.

טיפול בבקשות כוונון ובהפעלת מדיה

כשמשתמש בוחר ערוץ ספציפי, אפליקציית המערכת של YouTube TV משתמשת Session, שנוצרה על ידי האפליקציה שלך, כדי לכוון לערוץ המבוקש ולהפעיל את התוכן. בספרייה הנלווית של TIF יש כמה שיעורים שניתן להרחיב כדי לטפל בשיחות בערוצים ובסשנים מהמערכת.

תת-המחלקה BaseTvInputService יוצרת סשנים שמטפלים לבקשות כוונון. לשנות את השיטה onCreateSession(), יצירת סשן מורחב מ- את הכיתה BaseTvInputService.Session, super.sessionCreated() עם הסשן החדש שלך. בתוך לדוגמה, הפונקציה onCreateSession() מחזירה אובייקט RichTvInputSessionImpl מורחב BaseTvInputService.Session:

Kotlin

override fun onCreateSession(inputId: String): Session =
        RichTvInputSessionImpl(this, inputId).apply {
            setOverlayViewEnabled(true)
        }

Java

@Override
public final Session onCreateSession(String inputId) {
    RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
    session.setOverlayViewEnabled(true);
    return session;
}

כשהמשתמש משתמש באפליקציית המערכת לטלוויזיה כדי להתחיל לצפות באחד מהערוצים, המערכת קוראת ל-method onPlayChannel() של הסשן. שינוי מברירת המחדל בשיטה הזאת אם צריך לבצע אתחול ערוץ מיוחד לפני מתחילה לפעול.

לאחר מכן המערכת מקבלת את התוכנית המתוזמנת הנוכחית ומתקשרת השיטה onPlayProgram() של הסשן, מציין את התוכנה ושעת ההתחלה באלפיות השנייה. משתמשים ב ממשק TvPlayer כדי להתחיל להפעיל את התוכנה.

קוד נגן המדיה שלך צריך להטמיע TvPlayer כדי לטפל אירועי הפעלה ספציפיים. הכיתה TvPlayer מטפלת בתכונות כמו פקדי להזזת זמן בלי להוסיף מורכבות הטמעת BaseTvInputService.

בשיטה getTvPlayer() של הסשן, חוזרים נגן המדיה שבו מוטמע TvPlayer. באפליקציה לדוגמה של TV Credentials Service מיושמת נגן מדיה שמשתמש ExoPlayer.

יצירת שירות קלט של טלוויזיה באמצעות מסגרת הקלט של הטלוויזיה

אם שירות הקלט של הטלוויזיה לא יכול להשתמש בספרייה הנלווית של TIF, תצטרכו כדי להטמיע את הרכיבים הבאים:

  • TvInputService מספק זמינות לטווח ארוך וזמינות ברקע את קלט הטלוויזיה
  • TvInputService.Session שומר על מצב הקלט של הטלוויזיה ומתקשר עם אפליקציית האירוח
  • בTvContract מתוארים הערוצים והתוכניות שזמינים בטלוויזיה קלט
  • TvContract.Channels מייצג מידע על ערוץ טלוויזיה
  • בTvContract.Programs מתואר תוכנית טלוויזיה עם נתונים כמו תוכנית שם ושעת התחלה
  • TvTrackInfo מייצג טראק של אודיו, וידאו או כתוביות
  • TvContentRating מתאר סיווג תוכן, מאפשר תוכן מותאם אישית הונאות דירוג
  • TvInputManager מספק API לאפליקציית המערכת לטלוויזיה ומנהל האינטראקציה עם אפליקציות הקלט והטלוויזיה

צריך לבצע גם את הפעולות הבאות:

  1. להצהיר על שירות הקלט של הטלוויזיה במניפסט, כפי שמתואר במאמר להצהיר על שירות הקלט של הטלוויזיה מניפסט.
  2. יוצרים את קובץ המטא-נתונים של השירות.
  3. יוצרים ורושמים את פרטי הערוץ והתוכנית.
  4. יוצרים את פעילות ההגדרה.

הגדרת שירות הקלט של הטלוויזיה

כדי להשתמש בשירות שלך, עליך להרחיב את הכיתה TvInputService. א' ההטמעה של TvInputService שירות כריכה שבו שירות המערכת הוא הלקוח שמקושר אליו. שיטות למחזור החיים של השירות שצריך ליישם, אפשר לראות באיור 1.

ה-method onCreate() מאתחלת ומפעילה את HandlerThread, מספק שרשור תהליך נפרד מה-thread של ממשק המשתמש טיפול בפעולות שמונעות על ידי המערכת. בדוגמה הבאה, הפרמטר onCreate() ה-method מאתחלת את CaptioningManager ומתכוננת לטפל ACTION_BLOCKED_RATINGS_CHANGED ו-ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED פעולות. האלה הפעולות מתארות את כוונות המערכת שהופעלו כשהמשתמש משנה את ההגדרות של אמצעי בקרת ההורים, ומתי יש שינוי ברשימת הדירוגים החסומים.

Kotlin

override fun onCreate() {
    super.onCreate()
    handlerThread = HandlerThread(javaClass.simpleName).apply {
        start()
    }
    dbHandler = Handler(handlerThread.looper)
    handler = Handler()
    captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager

    setTheme(android.R.style.Theme_Holo_Light_NoActionBar)

    sessions = mutableListOf<BaseTvInputSessionImpl>()
    val intentFilter = IntentFilter().apply {
        addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED)
        addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED)
    }
    registerReceiver(broadcastReceiver, intentFilter)
}

Java

@Override
public void onCreate() {
    super.onCreate();
    handlerThread = new HandlerThread(getClass()
      .getSimpleName());
    handlerThread.start();
    dbHandler = new Handler(handlerThread.getLooper());
    handler = new Handler();
    captioningManager = (CaptioningManager)
      getSystemService(Context.CAPTIONING_SERVICE);

    setTheme(android.R.style.Theme_Holo_Light_NoActionBar);

    sessions = new ArrayList<BaseTvInputSessionImpl>();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(TvInputManager
      .ACTION_BLOCKED_RATINGS_CHANGED);
    intentFilter.addAction(TvInputManager
      .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
    registerReceiver(broadcastReceiver, intentFilter);
}

איור 1.מחזור החיים של TVInputService.

ראו לשלוט בתוכן כדי לקבל מידע נוסף על עבודה עם תוכן חסום בקרת הורים. ראו TvInputManager לגבי פעולות נוספות שמבוססות על המערכת ייתכן שכדאי לטפל בו בשירות הקלט של הטלוויזיה.

השדה TvInputService יוצר TvInputService.Session שבו מוטמע Handler.Callback כדי לטפל בשינויים במצב הנגן. ב- onSetSurface(), TvInputService.Session מגדיר את Surface עם תוכן וידאו. למידע נוסף, ראו שילוב הנגן עם הפלטפורמה למידע נוסף על עבודה עם Surface כדי לעבד את הסרטון.

TvInputService.Session מטפל onTune() כשמשתמש בוחר ערוץ ומודיע לאפליקציית המערכת על שינויים בתוכן המטא-נתונים של התוכן. השיטות האלה של notify() מתוארות ב שליטה בתוכן וניהול הטראקים בהכשרה הזאת.

הגדרת פעילות ההגדרה

אפליקציית המערכת של הטלוויזיה פועלת עם פעילות ההגדרה שהגדרת לקלט הטלוויזיה. ההגדרה נדרשת, ועלינו לספק לפחות רשומת ערוץ אחת עבור מסד הנתונים של המערכת. אפליקציית מערכת TV מפעילה את פעילות ההגדרה כשהיא לא מוצאת ערוץ לקלט הטלוויזיה.

פעילות ההגדרה מתארת לאפליקציית המערכת לטלוויזיה שבה הערוצים הופכים לזמינים דרך הטלוויזיה את הקלט, כמו שמודגם בשיעור הבא, צרו ולעדכן את נתוני הערוץ.

הפניות נוספות