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

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

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

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

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

ספריית TIF Companion זמינה לשימוש מדור קודם על ידי יצרני ציוד מקורי במאגר androidtv-sample-inputs. במאגר הזה יש דוגמה לאופן שבו אפשר לכלול את הספרייה באפליקציה.

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

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

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

בהצהרת השירות, צריך לכלול מסנן Intent שמציין את TvInputService כפעולה לביצוע באמצעות ה-Intent. צריך גם להצהיר על מטא-נתונים של השירות כמשאב 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 class. המחלקת האבסטרקטית הזו מאפשרת ליצור שירות משימות שיוצר ומעדכן ערוצים במסד הנתונים של המערכת.

במחלקת המשנה, יוצרים ומחזירים את הרשימה המלאה של הערוצים ב-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 Companion מספקת שיטה נוספת עם עומס יתר של requestImmediateSync שמאפשרת לציין את משך הזמן של נתוני הערוץ לסנכרון באלפיות השנייה. שיטת ברירת המחדל מסנכרנת נתונים של ערוץ אחד למשך שעה.

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

לפרטים נוספים על נתוני ערוצים וה-EPG, ראו עבודה עם נתוני ערוצים.

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

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

תת-המחלקה BaseTvInputService שלך יוצרת סשנים (sessions) המטפלים בבקשות כוונון. מבטלים את השיטה 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;
}

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

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

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

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

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

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

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

צריך גם:

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

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

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

השיטה onCreate מאתחלת ומפעילה את ה-HandlerThread, המספק תהליך נפרד מהליך ממשק המשתמש לטיפול בפעולות המונעות על ידי המערכת. בדוגמה הבאה, ה-method‏ onCreate מאתחל את 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 האלה מפורטות בהמשך ההדרכה במאמרים שליטה בתוכן ובחירת רצועות.

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

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

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

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