מסגרת הטיונר

ב-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 ל-framework באמצעות הממשקים IFrontend,‏ IDemux,‏ IDescrambler,‏ IFilter,‏ IDvr ו-ILnb.
  • כולל את הפונקציות לשילוב של Tuner HAL עם רכיבים אחרים של המסגרת, כמו MediaCodec ו- AudioTrack.

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

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

נוצרת קטגוריה של TRM.

  • מנהל משאבים מוגבלים של מקלט, כמו Frontend,‏ LNB,‏ CAS sessions ומכשיר קלט לטלוויזיה מ-TV input 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, ‏ Tuner SDK API תומך בתכונה חדשה ב-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(): מקבל מופע של descrambler.
  • openLnb(): קבלת מופע LNB פנימי.
  • 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 עוברת לתדר הזמין הבא ברשימת התדרים שלה.

הפונקציה 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 עוברת לתדר הזמין הבא ברשימת התדרים שלה.

הפונקציה 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's 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's 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) פעם אחת או יותר.

הנתונים מועתקים מ-MQ של HAL למאגר הלקוח.
חבילת 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) פעם אחת או יותר.

הנתונים מועתקים מ-MQ של HAL למאגר הלקוח.
הסינון בוצע 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 stream filled in 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) פעם אחת או יותר.

הנתונים מועתקים מ-MQ של HAL למאגר הלקוח.
הסינון בוצע 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) פעם אחת או יותר כדי לאחסן את הנתונים.
    הנתונים מועברים מ-HAL MQ לאחסון.
  • מריצים את הפקודה DvrRecord.write(buffer, adjustedSize) פעם אחת או יותר כדי ליצור מאגר.
    הנתונים מועתקים מ-HAL's MQ אל מאגר הלקוח.
לגבי נתוני אינדקס: מועברים במטען הייעודי (payload) של האירוע.

לתוכן מוקלט: הסטרימינג המוקלט המעורב מולא ב-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
הפידים של זרמי המשנה של הפרוטוקול שסוננו מוזנים למסנן הבא בשרשרת המסננים. לא רלוונטי
isPassthrough:
false
חובה:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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

הנתונים מועתקים מ-MQ של HAL למאגר הלקוח.
‫Filtered out protocol sub stream with protocol header is filled in 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 מספקת את ה-methods האלה להקלטה.

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

DvrPlayback מספקת את ה-methods האלה להפעלה.

  • 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. דיאגרמה של מנגנון ההחזרה לשימוש במקרה של קונפליקט בין משאבי מקלט