מסגרת הטיונר

ב-Android מגרסה 11 ואילך, אפשר להשתמש במסגרת Android Tuner כדי להציג תוכן אודיו/וידאו. המסגרת משתמשת בצינור הנתונים של החומרה מהספקים, ולכן היא מתאימה ל-SoC ברמה נמוכה וברמה גבוהה. המסגרת מספקת דרך מאובטחת להעברת תוכן אודיו/וידאו שמוגן על ידי סביבת ביצוע מהימנה (TEE) ונתיב מדיה מאובטח (SMP), ולכן אפשר להשתמש בה בסביבה מוגבלת מאוד להגנה על תוכן.

הממשק המתוקנן בין Tuner לבין Android CAS מאפשר שילוב מהיר יותר בין ספקי Tuner לבין ספקי CAS. ממשק הכוונון פועל עם MediaCodec ועם AudioTrack כדי ליצור פתרון עולמי ל-Android TV. ממשק הכוונון תומך בטלוויזיה דיגיטלית ובטלוויזיה אנלוגית על סמך תקני שידור עיקריים.

רכיבים

ב-Android 11, יש שלושה רכיבים שתוכננו במיוחד לפלטפורמת הטלוויזיה.

  • Tuner HAL: ממשק בין המסגרת לספקים
  • Tuner SDK API: ממשק בין המסגרת לבין האפליקציות
  • Tuner Resource Manager (TRM): מתאם משאבי חומרה של מקלט

ב-Android 11, הרכיבים הבאים שופרו:

  • CAS V2
  • TvInputService או שירות קלט לטלוויזיה (TIS)
  • TvInputManagerService או TV Input Manager Service (TIMS)
  • קודק MediaCodec או קודק מדיה
  • AudioTrack או טראק של אודיו
  • MediaResourceManager או מנהל משאבי מדיה (MRM)

תרשים זרימה של רכיבי Tuner framework.

איור 1. אינטראקציות בין רכיבי Android TV

תכונות

החלק הקדמי של המערכת תומך בתקני DTV הבאים.

  • ATSC
  • ATSC3
  • DVB C/S/T
  • ISDB S/S3/T
  • אנלוגי

החלק הקדמי ב-Android 12 עם Tuner HAL בגרסה 1.1 ומעלה תומך בתקן DTV שמופיע בהמשך.

  • DTMB

הכלי Demux תומך בפרוטוקולים הבאים של סטרימינג.

  • ‫Transport stream (TS)
  • פרוטוקול להעברת מדיה MPEG‏ (MMTP)
  • פרוטוקול אינטרנט (IP)
  • ערך אורך הסוג (TLV)
  • פרוטוקול שכבת הקישור (ALP) של ATSC

מפענח התוכן תומך באמצעי ההגנה על התוכן שמופיעים בהמשך.

  • נתיב מאובטח של מדיה
  • ניקוי נתיב המדיה
  • הקלטה מאובטחת של שיחות מקומיות
  • הפעלה מאובטחת של קבצים מקומיים

ממשקי Tuner API תומכים בתרחישי השימוש הבאים.

  • סריקה
  • בשידור חי
  • הפעלה
  • הקלטה

הכלים Tuner‏, MediaCodec ו-AudioTrack תומכים במצבי זרימת הנתונים שמופיעים בהמשך.

  • מטען ייעודי (payload) של ES עם מאגר נתונים זמני ברור בזיכרון
  • מטען ייעודי (payload) של ES עם טיפול בזיכרון מאובטח
  • שקופה

עיצוב כללי

ה-HAL של הכלי Tuner מוגדר בין מסגרת Android לבין החומרה של הספק.

  • מתאר מה נדרש מהספק במסגרת התקנים ואיך הספק יכול לעשות זאת.
  • מייצא את הפונקציות של חזית האתר, מפענח ה-demux ומפענח ה-descrambler אל המסגרת באמצעות הממשקים IFrontend,‏ IDemux,‏ IDescrambler,‏ IFilter,‏ IDvr ו-ILnb.
  • כולל את הפונקציות לשילוב של Tuner HAL עם רכיבים אחרים של המסגרת, כמו MediaCodec ו- AudioTrack.

נוצרות מחלקת Java ומחלקה מקורית של Tuner.

  • ממשק Tuner Java API מאפשר לאפליקציות לגשת ל-Tuner HAL דרך ממשקי API ציבוריים.
  • המחלקות המקוריות מאפשרות שליטה בהרשאות וטיפול בכמויות גדולות של נתוני הקלטה או הפעלה באמצעות Tuner HAL.
  • מודול Native Tuner הוא גשר בין מחלקת Tuner Java לבין Tuner HAL.

נוצרת כיתת TRM.

  • מנהל משאבי כוונון מוגבלים, כמו Frontend,‏ LNB, סשנים של CAS ומכשיר קלט לטלוויזיה מ-HAL של קלט לטלוויזיה.
  • החלת כללים להחזרת משאבים לא מספיקים מאפליקציות. כלל ברירת המחדל הוא שהצבע הקדמי מנצח.

התכונות הבאות משפרות את Media CAS ואת CAS HAL.

  • פתיחת סשנים של CAS לשימושים ולאלגוריתמים שונים.
  • תמיכה במערכות CAS דינמיות, כמו הסרה והוספה של CICAM.
  • הוא משתלב עם Tuner HAL על ידי אספקת אסימוני מפתח.

MediaCodec ו-AudioTrack משופרים באמצעות התכונות הבאות.

  • מקבל זיכרון מאובטח של אודיו ווידאו כקלט תוכן.
  • מוגדר לבצע סנכרון של אודיו ווידאו בחומרה בהפעלה במנהור.
  • הגדרת תמיכה ב-ES_payload ובמצב מעבר.

העיצוב הכללי של Tuner HAL.

איור 2. תרשים של הרכיבים ב-Tuner HAL

תהליך העבודה הכולל

בתרשימים הבאים אפשר לראות את רצפי הקריאות להפעלה של שידור חי.

הגדרה

תרשים של רצף ההגדרה של הפעלת שידור חי.

איור 3. הגדרת רצף להפעלת שידור חי

טיפול באודיו/בווידאו

תרשים של טיפול באודיו/בווידאו בהפעלה של שידור חי.

איור 4. טיפול באודיו ובווידאו בהפעלת שידור חי

טיפול בתוכן מבולבל

תרשים שמציג את הטיפול בתוכן מוצפן להפעלה של שידור חי.

איור 5. טיפול בתוכן מקושקש להפעלה בשידור חי

עיבוד נתוני אודיו ווידאו

תהליך עיבוד נתוני אודיו ווידאו לתרשים הפעלה של שידור חי.

איור 6. עיבוד של אודיו ווידאו להפעלת שידור חי

Tuner SDK API

ממשק ה-API של Tuner SDK מטפל באינטראקציות עם Tuner JNI,‏ Tuner HAL ו-TunerResourceManager. אפליקציית TIS משתמשת ב-Tuner SDK API כדי לגשת למשאבי Tuner ולרכיבי משנה כמו המסנן וה-descrambler. ה-Frontend וה-demux הם רכיבים פנימיים.

תרשים זרימה של Tuner SDK API.

איור 7. אינטראקציות עם Tuner SDK API

גרסאות

מ-Android 12, ה-API של Tuner SDK תומך בתכונה חדשה ב-Tuner HAL 1.1, שהיא שדרוג של Tuner 1.0 עם תאימות לאחור.

כדי לבדוק את גרסת ה-HAL שפועלת, משתמשים ב-API הבא.

  • android.media.tv.tuner.TunerVersionChecker.getTunerVersion()

אפשר למצוא את גרסת ה-HAL המינימלית הנדרשת במסמכים של ממשקי ה-API החדשים של Android 12.

חבילות

ממשק ה-API של Tuner SDK מספק את ארבעת החבילות הבאות.

  • android.media.tv.tuner
  • android.media.tv.tuner.frontend
  • android.media.tv.tuner.filter
  • android.media.tv.tuner.dvr

תרשים זרימה של חבילות Tuner SDK API.

איור 8. חבילות Tuner SDK API

Android.media.tv.tuner

חבילת Tuner היא נקודת כניסה לשימוש ב-Tuner framework. אפליקציית TIS משתמשת בחבילה כדי לאתחל ולקבל מופעי משאבים על ידי ציון ההגדרה הראשונית והקריאה החוזרת.

  • tuner(): מאתחל מופע של Tuner על ידי ציון הפרמטרים useCase ו-sessionId.
  • tune(): מקבלים משאב ומכוונים אותו על ידי ציון הפרמטר FrontendSetting.
  • openFilter(): מקבל מופע של מסנן על ידי ציון סוג המסנן.
  • openDvrRecorder(): מקבלים מופע הקלטה על ידי ציון גודל המאגר.
  • openDvrPlayback(): מקבל מופע הפעלה על ידי ציון גודל המאגר.
  • openDescrambler(): קבלת מופע של מפענח.
  • openLnb(): קבלת מופע פנימי של מאזן עומסים.
  • openLnbByName(): קבלת מופע LNB חיצוני.
  • openTimeFilter(): מקבל מופע של מסנן זמן.

חבילת Tuner מספקת פונקציות שלא נכללות בחבילות filter,‏ DVR ו-frontend. הפונקציות מפורטות בהמשך.

  • cancelTuning
  • scan מתוך cancelScanning
  • getAvSyncHwId
  • getAvSyncTime
  • connectCiCam1 מתוך disconnectCiCam
  • shareFrontendFromTuner
  • updateResourcePriority
  • setOnTuneEventListener
  • setResourceLostListener

Android.media.tv.tuner.frontend

חבילת ה-frontend כוללת אוספים של הגדרות, מידע, סטטוסים, אירועים ויכולות שקשורים ל-frontend.

שיעורים

הערך FrontendSettings נגזר מתקני DTV שונים לפי המחלקות שבהמשך.

  • AnalogFrontendSettings
  • Atsc3FrontendSettings
  • AtscFrontendSettings
  • DvbcFrontendSettings
  • DvbsFrontendSettings
  • DvbtFrontendSettings
  • Isdbs3FrontendSettings
  • IsdbsFrontendSettings
  • IsdbtFrontendSettings

מ-Android 12 עם Tuner HAL 1.1 ואילך, יש תמיכה בתקן DTV הבא.

  • DtmbFrontendSettings

FrontendCapabilities נגזר עבור תקני DTV שונים על ידי המחלקות שבהמשך.

  • AnalogFrontendCapabilities
  • Atsc3FrontendCapabilities
  • AtscFrontendCapabilities
  • DvbcFrontendCapabilities
  • DvbsFrontendCapabilities
  • DvbtFrontendCapabilities
  • Isdbs3FrontendCapabilities
  • IsdbsFrontendCapabilities
  • IsdbtFrontendCapabilities

מ-Android 12 עם Tuner HAL 1.1 ואילך, יש תמיכה בתקן DTV הבא.

  • DtmbFrontendCapabilities

FrontendInfo מאחזר את פרטי חזית האתר. ‫FrontendStatus מחזירה את הסטטוס הנוכחי של חזית האתר. ‫OnTuneEventListener מאזין לאירועים בחלק הקדמי של האתר. אפליקציית TIS משתמשת ב-ScanCallback כדי לעבד הודעות סריקה מהחלק הקדמי של האתר.

סריקת ערוצים

כדי להגדיר טלוויזיה, האפליקציה סורקת תדרים אפשריים ויוצרת רשימת ערוצים שהמשתמשים יכולים לגשת אליה. יכול להיות ש-TIS ישתמש ב-Tuner.tune, Tuner.scan(BLIND_SCAN) או ב-Tuner.scan(AUTO_SCAN) כדי להשלים את הסריקה של הערוץ.

אם ל-TIS יש מידע מדויק על המשלוח של האות, כמו תדר, תקן (למשל, T/T2,‏ S/S2) ומידע נוסף שנדרש (למשל, מזהה PLD), מומלץ להשתמש ב-Tuner.tune כי זו האפשרות המהירה יותר.

כשמשתמש מתקשר אל Tuner.tune, הפעולות הבאות מתבצעות:

  • מערכת TIS מאכלסת את FrontendSettings במידע הנדרש באמצעות Tuner.tune.
  • אם האות נעול, שכבת ה-HAL מדווחת על הודעות LOCKED.
  • מערכת TIS משתמשת ב-Frontend.getStatus כדי לאסוף את המידע הנדרש.
  • המערכת עוברת לתדר הזמין הבא ברשימת התדרים שלה.

ה-TIS קורא Tuner.tune שוב עד שכל התדרים מוצו.

במהלך ההגדרה, אפשר להתקשר אל stopTune() או אל close() כדי להשהות או לסיים את השיחה עם Tuner.tune.

‪Tuner.scan(AUTO_SCAN)

אם ל-TIS אין מספיק מידע כדי להשתמש ב-Tuner.tune, אבל יש לו רשימת תדרים וסוג סטנדרטי (לדוגמה, DVB T/C/S), מומלץ להשתמש ב-Tuner.scan(AUTO_SCAN).

כשמשתמש מתקשר אל Tuner.scan(AUTO_SCAN), הפעולות הבאות מתבצעות:

  • ב-TIS נעשה שימוש ב-Tuner.scan(AUTO_SCAN) עם FrontendSettings שממולא בתדירות.

  • אם האות נעול, ה-HAL מדווח על סריקת הודעות LOCKED. יכול להיות ש-HAL ידווח גם על הודעות סריקה אחרות כדי לספק מידע נוסף על האות.

  • ‫TIS משתמשת ב-Frontend.getStatus כדי לאסוף את המידע הנדרש.

  • ה-TIS קורא ל-Tuner.scan כדי שה-HAL ימשיך להגדרה הבאה באותה תדירות. אם המבנה של FrontendSettings ריק, HAL משתמש בהגדרה הבאה שזמינה. אחרת, HAL משתמש ב-FrontendSettings לסריקה חד-פעמית ושולח END כדי לציין שפעולת הסריקה הסתיימה.

  • הכלי TIS חוזר על הפעולות שלמעלה עד שכל ההגדרות בתדירות מסוימת מושלמות.

  • שכבת ה-HAL שולחת END כדי לציין שפעולת הסריקה הסתיימה.

  • המערכת עוברת לתדר הזמין הבא ברשימת התדרים שלה.

ה-TIS קורא Tuner.scan(AUTO_SCAN) שוב עד שכל התדרים מוצו.

במהלך הסריקה, אפשר להתקשר אל stopScan() או אל close() כדי להשהות או לסיים את הסריקה.

‪Tuner.scan(BLIND_SCAN)

אם ל-TIS אין רשימת תדרים ו-Vendor HAL יכול לחפש את התדר של הקצה הקדמי שצוין על ידי המשתמש כדי לקבל את משאב הקצה הקדמי, מומלץ להשתמש ב-Tuner.scan(BLIND_SCAN).

  • ב-TIS נעשה שימוש ב-Tuner.scan(BLIND_SCAN). אפשר לציין תדירות ב-FrontendSettings לתדירות התחלה, אבל TIS מתעלם מהגדרות אחרות ב-FrontendSettings.
  • אם האות נעול, ה-HAL מדווח על הודעת סריקה LOCKED.
  • ‫TIS משתמשת ב-Frontend.getStatus כדי לאסוף את המידע הנדרש.
  • TIS מתקשר Tuner.scan שוב כדי להמשיך בסריקה. (המערכת מתעלמת מFrontendSettings).
  • הכלי TIS חוזר על הפעולות שלמעלה עד שכל ההגדרות בתדירות מסוימת מושלמות. ה-HAL מגדיל את התדירות בלי שתידרש פעולה מצד TIS. דוחות HAL PROGRESS.

ה-TIS קורא Tuner.scan(AUTO_SCAN) שוב עד שכל התדרים מוצו. ה-HAL מדווח על END כדי לציין שפעולת הסריקה הסתיימה.

במהלך הסריקה, אפשר להתקשר אל stopScan() או אל close() כדי להשהות או לסיים את הסריקה.

תרשים זרימה של תהליך הסריקה של TIS.

איור 9. תרשים זרימה של סריקת TIS

Android.media.tv.tuner.filter

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

  • configure()
  • start()
  • stop()
  • flush()
  • read()

הרשימה המלאה מופיעה בקוד המקור של Android.

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

  • AlpFilterConfiguration
  • IpFilterConfiguration
  • MmtpFilterConfiguration
  • TlvFilterConfiguration
  • TsFilterConfiguration

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

  • SectionSettings
  • AvSettings
  • PesSettings
  • RecordSettings
  • DownloadSettings

FilterEvent נגזר מהמחלקות שבהמשך כדי לדווח על אירועים עבור סוגים שונים של נתונים.

  • SectionEvent
  • MediaEvent
  • PesEvent
  • TsRecordEvent
  • MmtpRecordEvent
  • TemiEvent
  • DownloadEvent
  • IpPayloadEvent

מגרסה Android 12 עם Tuner HAL 1.1 ואילך, המערכת תומכת באירועים הבאים.

  • IpCidChangeEvent
  • RestartEvent
  • ScramblingStatusEvent
אירועים ופורמט נתונים מהמסנן
סוג מסנן דגלים אירועים פעולת נתונים פורמט נתונים
TS.SECTION
MMTP.SECTION
IP.SECTION
TLV.SECTION
ALP.SECTION
isRaw:
true
חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מומלץ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
בהתאם לאירוע וללוח הזמנים הפנימי, מריצים את
Filter.read(buffer, offset, adjustedSize) פעם אחת או יותר.

הנתונים מועתקים מ-HAL MQ למאגר הלקוח.
חבילת סשן אחת שהורכבה מתמלאת ב-FMQ על ידי חבילת סשן אחרת.
isRaw:
false
מאפיינים חובה:
DemuxFilterEvent::DemuxFilterSectionEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מאפיינים אופציונליים:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterSectionEven[i].size)


הנתונים מועתקים מ-HAL MQ למאגר הלקוח.
TS.PES isRaw:
true
חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מומלץ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
בהתאם לאירוע וללוח הזמנים הפנימי, מריצים את
Filter.read(buffer, offset, adjustedSize) פעם אחת או יותר.

הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
חבילת PES אחת מורכבת מלאה ב-FMQ על ידי חבילת PES אחרת.
isRaw:
false
מאפיינים חובה:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מאפיינים אופציונליים:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
MMTP.PES isRaw:
true
חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מומלץ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
בהתאם לאירוע וללוח הזמנים הפנימי, מריצים את
Filter.read(buffer, offset, adjustedSize) פעם אחת או יותר.

הנתונים מועתקים מ-HAL MQ למאגר הלקוח.
חבילת MFU אחת מלאה ב-FMQ על ידי חבילת MFU אחרת.
isRaw:
false
מאפיינים חובה:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מאפיינים אופציונליים:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
TS.TS
לא רלוונטי חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מומלץ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
בהתאם לאירוע וללוח הזמנים הפנימי, מריצים את
Filter.read(buffer, offset, adjustedSize) פעם אחת או יותר.

הנתונים מועתקים מ-HAL MQ למאגר הלקוח.
הסינון בוצע ts עם ts כותרת
מלאה ב-FMQ.
TS.Audio
TS.Video
MMTP.Audio
MMTP.Video
isPassthrough:
true
אופציונלי:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
הלקוח יכול להתחיל MediaCodec אחרי שהוא מקבל DemuxFilterStatus::DATA_READY.
הלקוח יכול להתקשר אל Filter.flush אחרי שהוא מקבל את DemuxFilterStatus::DATA_OVERFLOW.
לא רלוונטי
isPassthrough:
false
מאפיינים חובה:
DemuxFilterEvent::DemuxFilterMediaEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מאפיינים אופציונליים:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
כדי להשתמש ב-MediaCodec:
for i=0; i<n; i++
linearblock = MediaEvent[i].getLinearBlock();
codec.startQueueLinearBlock(linearblock)
linearblock.recycle()


כדי להשתמש באודיו ישיר של AudioTrack:
for i=0; i<n; i++
audioHandle = MediaEvent[i].getAudioHandle();
audiotrack.write(encapsulated(audiohandle))
נתוני ES או נתוני ES חלקיים בזיכרון של ION.
TS.PCR
IP.NTP
ALP.PTP
לא רלוונטי מאפייני חובה: לא רלוונטי
מאפיינים אופציונליים: לא רלוונטי
לא רלוונטי לא רלוונטי
TS.RECORD לא רלוונטי חובה:
DemuxFilterEvent::DemuxFilterTsRecordEvent[n]
RecordStatus::DATA_READY
RecordStatus::DATA_OVERFLOW
RecordStatus::LOW_WATER
RecordStatus::HIGH_WATER

אופציונלי:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
לנתוני אינדקס:
for i=0; i<n; i++
DemuxFilterTsRecordEvent[i];


לתוכן מוקלט, בהתאם ל-RecordStatus::* ולתזמון הפנימי, מבצעים אחת מהפעולות הבאות:
  • מריצים את הפקודה DvrRecord.write(adustedSize) פעם אחת או יותר כדי לאחסן את הנתונים.
    הנתונים מועברים מ-HAL MQ לאחסון.
  • מריצים את הפקודה DvrRecord.write(buffer, adustedSize) פעם אחת או יותר כדי ליצור מאגר.
    הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
לגבי נתוני אינדקס: נכללים במטען הייעודי (payload) של האירוע.

לתוכן מוקלט: זרם Muxed TS שמולא ב-FMQ.
TS.TEMI לא רלוונטי חובה:
DemuxFilterEvent::DemuxFilterTemiEvent[n]

אופציונלי:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
DemuxFilterTemiEvent[i];
לא רלוונטי
MMTP.MMTP לא רלוונטי חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מומלץ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
בהתאם לאירוע וללוח הזמנים הפנימי, מריצים את
Filter.read(buffer, offset, adjustedSize) פעם אחת או יותר.

הנתונים מועתקים מ-HAL MQ למאגר הלקוח.
הסינון בוצע mmtp עם mmtp כותרת
מלאה ב-FMQ.
MMTP.RECORD לא רלוונטי חובה:
DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n]
RecordStatus::DATA_READY
RecordStatus::DATA_OVERFLOW
RecordStatus::LOW_WATER
RecordStatus::HIGH_WATER

אופציונלי:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
לנתוני אינדקס: for i=0; i<n; i++
DemuxFilterMmtpRecordEvent[i];


לתוכן מוקלט, בהתאם לRecordStatus::* ולתזמון הפנימי, מבצעים אחת מהפעולות הבאות:
  • מריצים את DvrRecord.write(adjustedSize) פעם אחת או יותר עד שמגיעים לאחסון.
    הנתונים מועברים מ-MQ של HAL לאחסון.
  • מריצים את DvrRecord.write(buffer, adjustedSize) פעם אחת או יותר כדי ליצור מאגר.
    הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
לגבי נתוני אינדקס: נכללים במטען הייעודי (payload) של האירוע.

לתוכן מוקלט: סטרימינג מוקלט עם אודיו וסרטון משולבים, מלא ב-FMQ. FMQ.

אם מקור הסינון להקלטה הוא TLV.TLV עד IP.IP עם העברה, לזרם המוקלט יש TLV וכותרת IP.
MMTP.DOWNLOAD לא רלוונטי מאפיינים חובה:
DemuxFilterEvent::DemuxFilterDownloadEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מאפיינים אופציונליים:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++ Filter.read(buffer, offset, DemuxFilterDownloadEvent[i].size)

הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
חבילת ההורדה מתמלאת ב-FMQ על ידי חבילת הורדה אחרת של כתובת IP.
IP.IP_PAYLOAD לא רלוונטי מאפיינים חובה:
DemuxFilterEvent::DemuxFilterIpPayloadEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מאפיינים אופציונליים:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++ Filter.read(buffer, offset, DemuxFilterIpPayloadEvent[i].size)

הנתונים מועתקים מ-HAL's MQ למאגר הלקוח.
חבילת מטען ייעודי (payload) של IP מתמלאת ב-FMQ על ידי חבילת מטען ייעודי (payload) אחרת של IP.
IP.IP
TLV.TLV
ALP.ALP
isPassthrough:
true
אופציונלי:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
הפידים של זרמי המשנה של הפרוטוקול שסוננו מוזנים למסנן הבא בשרשרת המסננים filter. לא רלוונטי
isPassthrough:
false
חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

מומלץ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
בהתאם לאירוע וללוח הזמנים הפנימי, מריצים את
Filter.read(buffer, offset, adjustedSize) פעם אחת או יותר.

הנתונים מועתקים מ-HAL MQ למאגר הלקוח.
הסינון של נתוני המשנה של הפרוטוקול עם כותרת הפרוטוקול הושלם FMQ.
IP.PAYLOAD_THROUGH
TLV.PAYLOAD_THROUGH
ALP.PAYLOAD_THROUGH
לא רלוונטי אופציונלי:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
הפידים של מטען הייעודי (payload) של הפרוטוקול שסוננו מוזנים למסנן הבא בשרשרת המסננים. לא רלוונטי
תרשים זרימה לדוגמה לשימוש במסנן כדי ליצור PSI/SI

תרשים זרימה לדוגמה לשימוש במסנן כדי ליצור PSI/SI.

איור 10. תהליך ליצירת PSI/SI

  1. פותחים מסנן.

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. מגדירים את המסנן ומתחילים להשתמש בו.

    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();
      filter.configure(config);
      filter.start();
    
  3. עיבוד SectionEvent.

    FilterCallback filterCallback = new FilterCallback() {
      @Override
      public void onFilterEvent(Filter filter, FilterEvent[] events) {
        for (FilterEvent event : events) {
          if (event instanceof SectionEvent) {
            SectionEvent sectionEvent = (SectionEvent) event;
            int tableId = sectionEvent.getTableId();
            int version = sectionEvent.getVersion();
            int dataLength = sectionEvent.getDataLength();
            int sectionNumber = sectionEvent.getSectionNumber();
            filter.read(buffer, 0, dataLength); }
          }
        }
    };
    
דוגמה לשימוש ב-MediaEvent מתוך מסנן

דוגמה לזרימת עבודה לשימוש ב-MediaEvent מתוך מסנן.

איור 11. Flow to use MediaEvent from filter

  1. פותחים את המסננים של האודיו והווידאו, מגדירים אותם ומתחילים להשתמש בהם.
  2. עיבוד MediaEvent.
  3. קבלת MediaEvent.
  4. הוספת הבלוק הליניארי לתור של codec.
  5. משחררים את ה-handle של האודיו והווידאו אחרי שהנתונים נצרכים.

Android.media.tv.tuner.dvr

DvrRecorder מספק את השיטות האלה להקלטה.

  • configure
  • attachFilter
  • detachFilter
  • start
  • flush
  • stop
  • setFileDescriptor
  • write

DvrPlayback מספק את השיטות האלה להפעלה.

  • configure
  • start
  • flush
  • stop
  • setFileDescriptor
  • read

DvrSettings משמש להגדרה של DvrRecorder ושל DvrPlayback. הערכים OnPlaybackStatusChangedListener ו-OnRecordStatusChangedListener משמשים לדיווח על הסטטוס של מופע DVR.

דוגמה לתהליך התחלת הקלטה

דוגמה לתהליך התחלת רשומה.

איור 12. תהליך ליצירת רשומה

  1. פותחים את DvrRecorder, מגדירים אותו ומתחילים להשתמש בו.

    DvrRecorder recorder = openDvrRecorder(/* bufferSize */ 1000, executor, listener);
    DvrSettings dvrSettings = DvrSettings
    .builder()
    .setDataFormat(DvrSettings.DATA_FORMAT_TS)
    .setLowThreshold(100)
    .setHighThreshold(900)
    .setPacketSize(188)
    .build();
    recorder.configure(dvrSettings);
    recorder.attachFilter(filter);
    recorder.setFileDescriptor(fd);
    recorder.start();
    
  2. מקבלים את RecordEvent ומאחזרים את פרטי האינדקס.

    FilterCallback filterCallback = new FilterCallback() {
      @Override
      public void onFilterEvent(Filter filter, FilterEvent[] events) {
        for (FilterEvent event : events) {
          if (event instanceof TsRecordEvent) {
            TsRecordEvent recordEvent = (TsRecordEvent) event;
            int tsMask = recordEvent.getTsIndexMask();
            int scMask = recordEvent.getScIndexMask();
            int packetId = recordEvent.getPacketId();
            long dataLength = recordEvent.getDataLength();
            // handle the masks etc. }
          }
        }
    };
    
  3. מאתחלים את OnRecordStatusChangedListener ומאחסנים את נתוני הרשומה.

      OnRecordStatusChangedListener listener = new OnRecordStatusChangedListener() {
        @Override
        public void onRecordStatusChanged(int status) {
          // a customized way to consume data efficiently by using status as a hint.
          if (status == Filter.STATUS_DATA_READY) {
            recorder.write(size);
          }
        }
      };
    

Tuner HAL

ה-HAL של הכרטיס הדיגיטלי לשידור (Tuner) פועל לפי HIDL ומגדיר את הממשק בין המסגרת לבין חומרת הספק. הספקים משתמשים בממשק כדי להטמיע את Tuner HAL, והמסגרת משתמשת בו כדי לתקשר עם ההטמעה של Tuner HAL.

מודולים

Tuner HAL 1.0

מודולים פקדים בסיסיים אמצעי בקרה ספציפיים למודול קובצי HAL
ITuner לא רלוונטי frontend(open, getIds, getInfo), openDemux, openDescrambler, openLnb, getDemuxCaps ITuner.hal
IFrontend setCallback, getStatus close tune, stopTune, scan, stopScan, setLnb IFrontend.hal
IFrontendCallback.hal
IDemux close setFrontendDataSource, openFilter, openDvr, getAvSyncHwId, getAvSyncTime, connect / disconnectCiCam IDemux.hal
IDvr close, start, stop, configure attach/detachFilters, flush getQueueDesc IDvr.hal
IDvrCallback.hal
IFilter close, start, stop, configure, getId flush, getQueueDesc, releaseAvHandle, setDataSource IFilter.hal
IFilterCallback.hal
ILnb close, setCallback setVoltage, setTone, setSatellitePosition, sendDiseqcMessage ILnb.hal
ILnbCallback.hal
IDescrambler close setDemuxSource, setKeyToken, addPid, removePid IDescrambler.hal

‫Tuner HAL 1.1 (נגזר מ-Tuner HAL 1.0)

מודולים פקדים בסיסיים אמצעי בקרה ספציפיים למודול קובצי HAL
ITuner לא רלוונטי getFrontendDtmbCapabilities @1.1::ITuner.hal
IFrontend tune_1_1, scan_1_1 getStatusExt1_1 link/unlinkCiCam @1.1::IFrontend.hal
@1.1::IFrontendCallback.hal
IFilter getStatusExt1_1 configureIpCid, configureAvStreamType, getAvSharedHandle, configureMonitorEvent @1.1::IFilter.hal
@1.1::IFilterCallback.hal

תרשים זרימה של אינטראקציות בין המודולים של Tuner HAL.

איור 13. תרשים של האינטראקציות בין מודולי Tuner HAL

קישור סינון

ה-HAL של Tuner תומך בקישור מסננים כך שאפשר לקשר מסננים למסננים אחרים לכמה שכבות. המסננים פועלים לפי הכללים הבאים.

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

בלוק הקוד שבהמשך ואיור 14 מציגים דוגמה לסינון של כמה שכבות.

demuxCaps = ITuner.getDemuxCap;
If (demuxCaps[IP][MMTP] == true) {
        ipFilter = ITuner.openFilter(<IP, ..>)
        mmtpFilter1 = ITuner.openFilter(<MMTP ..>)
        mmtpFilter2 = ITuner.openFilter(<MMTP ..>)
        mmtpFilter1.setDataSource(<ipFilter>)
        mmtpFilter2.setDataSource(<ipFilter>)
}

תרשים של דוגמה לקישור מסננים.

איור 14. תרשים זרימה של קישור מסנן למספר שכבות

Tuner Resource Manager

לפני Tuner Resource Manager ‏ (TRM), כדי לעבור בין שתי אפליקציות היה צריך להשתמש באותו חומרה של מקלט. ב-TV Input Framework ‏ (TIF) נעשה שימוש במנגנון 'הראשון זוכה', כלומר האפליקציה שמקבלת את המשאב ראשונה שומרת אותו. עם זאת, יכול להיות שהמנגנון הזה לא יתאים לתרחישי שימוש מורכבים.

ה-TRM פועל כשירות מערכת לניהול המשאבים של הכרטיס לשידורי טלוויזיה, TVInput וחומרת ה-CAS באפליקציות. הכלי לניהול תנועה משתמש במנגנון 'ניצחון במצב פעיל', שמחשב את העדיפות של האפליקציה על סמך הסטטוס שלה (פעילה או ברקע) וסוג תרחיש השימוש. מערכת TRM מעניקה או מבטלת את הגישה למשאב על סמך העדיפות. TRM מרכז את ניהול המשאבים של ATV לשידור, ל-OTT ול-DVR.

ממשק TRM

‫TRM חושף ממשקי AIDL ב-ITunerResourceManager.aidl עבור Tuner Framework‏, MediaCas ו-TvInputHardwareManager כדי לרשום, לבקש או לשחרר משאבים.

בהמשך מפורטים ממשקים לניהול לקוחות.

  • registerClientProfile(in ResourceClientProfile profile, IResourcesReclaimListener listener, out int[] clientId)
  • unregisterClientProfile(in int clientId)

בהמשך מפורטים הממשקים לבקשת משאבים ולשחרור משאבים.

  • requestFrontend(TunerFrontendRequest request, int[] frontendHandle) / releaseFrontend
  • requestDemux(TunerDemuxRequest request, int[] demuxHandle) / releaseDemux
  • requestDescrambler(TunerDescramblerRequest request, int[] descramblerHandle) / releaseDescrambler
  • requestCasSession(CasSessionRequest request, int[] casSessionHandle) / releaseCasSession
  • requestLnb(TunerLnbRequest request, int[] lnbHandle) מתוך releaseLnb

בהמשך מפורטים סוגי הלקוחות והבקשות.

  • ResourceClientProfile
  • ResourcesReclaimListener
  • TunerFrontendRequest
  • TunerDemuxRequest
  • TunerDescramblerRequest
  • CasSessionRequest
  • TunerLnbRequest

עדיפות של לקוחות

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

פרמטרים בפרופיל של הלקוח

המודול TRM מאחזר את מזהה התהליך מ-mTvInputSessionId כדי להחליט אם האפליקציה היא אפליקציה שפועלת בחזית או ברקע. כדי ליצור mTvInputSessionId,‏ TvInputService.onCreateSession או TvInputService.onCreateRecordingSession, המודול מאתחל סשן TIS.

mUseCase מציין את תרחיש השימוש בסשן. תרחישי השימוש המוגדרים מראש מפורטים בהמשך.

TvInputService.PriorityHintUseCaseType  {
  PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK
  PRIORITY_HINT_USE_CASE_TYPE_LIVE
  PRIORITY_HINT_USE_CASE_TYPE_RECORD,
  PRIORITY_HINT_USE_CASE_TYPE_SCAN,
  PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND
}

קובץ תצורה

קובץ תצורה שמוגדר כברירת מחדל

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

תרחיש לדוגמה חזית רקע
LIVE 490 400
PLAYBACK 480 300
RECORD 600 500
SCAN 450 200
BACKGROUND 180 100
קובץ הגדרות בהתאמה אישית

ספקים יכולים להתאים אישית את קובץ ההגדרות /vendor/etc/tunerResourceManagerUseCaseConfig.xml. הקובץ הזה משמש להוספה, להסרה או לעדכון של סוגי תרחישי השימוש וערכי העדיפות של תרחישי השימוש. אפשר להשתמש בקובץ המותאם אישית בתור תבנית ב-platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml.

לדוגמה, תרחיש שימוש של ספק חדש הוא VENDOR_USE_CASE__[A-Z0-9]+, [0 - 1000]. הפורמט צריך להיות platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd.

ערך עדיפות שרירותי וערך nice

ה-TRM מספק updateClientPriority ללקוח כדי לעדכן את ערך העדיפות השרירותי ואת ערך ה-nice. ערך העדיפות השרירותי מחליף את ערך העדיפות שחושב לפי סוג תרחיש השימוש ומזהה הסשן.

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

מנגנון ההחזרה

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

תרשים של תהליך מנגנון ההחזרה.

איור 15. דיאגרמה של מנגנון ההחזרה של משאבי Tuner במקרה של קונפליקט