מסגרת טיונר

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

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

רכיבים

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

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

הרכיבים הבאים עברו שיפור ל-Android 11.

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

תרשים זרימה של רכיבי מסגרת הטיונר.

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

תכונות

הקצה הקדמי תומך בתקני ה-DTV שמפורטים בהמשך.

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

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

  • DTMB

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

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

ה-Descrambler תומך באמצעי ההגנה הבאים על תוכן:

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

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

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

בטיונר, MediaCodec ו-AudioTrack תומכים במצבי זרימת הנתונים שבהמשך.

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

העיצוב הכללי

HAL של הטיונר מוגדר בין ה-framework של Android לבין החומרה של הספק.

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

המערכת יוצרת כיתת טיונר Java ומחלקה נייטיב.

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

נוצרת מחלקה של TRM.

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

אישורי CAS ו-CAS HAL משופרים בעזרת התכונות שמפורטות בהמשך.

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

התכונות הבאות כוללות את MediaCodec ואת AudioTrack.

  • מקבל זיכרון A/V מאובטח כקלט תוכן.
  • מוגדר לביצוע סנכרון אודיו/וידאו של חומרה בהפעלה עם מנהרה.
  • הגדרת תמיכה ב-ES_payload ובמצב העברה (passthrough).

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

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

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

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

הגדרה

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

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

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

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

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

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

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

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

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

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

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

API של טיונר SDK

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

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

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

גרסאות

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

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

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

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

חבילות

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

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

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

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

Android.media.tv.כוונוןr

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

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

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

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

Android.media.tv.tuner.frontend

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

שיעורים

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

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

החל מ-Android 12 עם Tiunr 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 כדי לציין שפעולת הסריקה הסתיימה.

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

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

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

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

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

Tuner.scan(BLIND_SCAN)

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

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

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

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

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

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

Android.media.tv.כוונוןr.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) פעם אחת או יותר.

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


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

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

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


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


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

לתוכן שהוקלט: שידור 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) פעם אחת או יותר.

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

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

הנתונים מועתקים מה-MQ של HAL למאגר הנתונים הזמני של הלקוח.
חבילת נתוני ה-IP נטענת ב-FMQ על ידי חבילת נתוני 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 למאגר הנתונים של הלקוח.
מקור הנתונים המשני של הפרוטוקול שעבר סינון עם כותרת הפרוטוקול מתמלא ב-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. זרימה לשימוש ב-MediaEvent ממסנן

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

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

  • המסננים מקושרים כעץ, אסור לסגור את הנתיב.
  • צומת הרמה הבסיסית (root) הוא 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‏ (TRM), כדי לעבור בין שתי אפליקציות היה צורך באותה חומרה של Tuner. במסגרת הטלוויזיה של קלט (TIF) נעשה שימוש במנגנון של 'קודם לזכייה', כלומר, כל אפליקציה שמקבלת את המשאב קודם משאירה אותו. עם זאת, יכול להיות שהמנגנון הזה לא יהיה אידיאלי במקרים מורכבים מסוימים.

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

ממשק TRM

TRM חושפת ממשקי AIDL ב-ITunerResourceManager.aidl בשביל ה-framework של הטיונר, MediaCas ו-TvInputHardwareManager כדי לרשום, לבקש או לשחרר משאבים.

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

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

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

  • 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.

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

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

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

מנגנון להחזרת מספרים

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

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

איור 15. תרשים של מנגנון ההחזרה להתנגשות בין משאבי טיונר