สำหรับ Android 11 หรือสูงกว่า คุณสามารถใช้เฟรมเวิร์ก Android Tuner เพื่อส่งเนื้อหา A/V ได้ เฟรมเวิร์กใช้ไปป์ไลน์ฮาร์ดแวร์จากผู้ขาย ทำให้เหมาะสำหรับ SoC ทั้งระดับล่างและระดับสูง เฟรมเวิร์กนี้มอบวิธีการที่ปลอดภัยในการส่งเนื้อหา A/V ที่ได้รับการปกป้องโดยสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ (TEE) และเส้นทางสื่อที่ปลอดภัย (SMP) ทำให้สามารถใช้ในสภาพแวดล้อมการป้องกันเนื้อหาที่มีข้อจำกัดสูง
อินเทอร์เฟซมาตรฐานระหว่าง Tuner และ Android CAS ส่งผลให้มีการผสานรวมระหว่างผู้จำหน่าย Tuner และผู้จำหน่าย CAS ได้เร็วขึ้น อินเทอร์เฟซจูนเนอร์ทำงานร่วมกับ MediaCodec
และ AudioTrack
เพื่อสร้างโซลูชันระดับโลกสำหรับ Android TV อินเทอร์เฟซจูนเนอร์รองรับทั้งทีวีดิจิทัลและทีวีแอนะล็อกตามมาตรฐานการออกอากาศหลัก
ส่วนประกอบ
สำหรับ Android 11 องค์ประกอบ 3 อย่างได้รับการออกแบบมาโดยเฉพาะสำหรับแพลตฟอร์มทีวี
- Tuner HAL: อินเทอร์เฟซระหว่างเฟรมเวิร์กและผู้ขาย
- Tuner SDK API: อินเทอร์เฟซระหว่างเฟรมเวิร์กและแอป
- Tuner Resource Manager (TRM): ประสานงานทรัพยากร Tuner HW
สำหรับ Android 11 ส่วนประกอบต่อไปนี้ได้รับการปรับปรุง
- CASV2
-
TvInputService
หรือ TV Input Service (TIS) -
TvInputManagerService
หรือ TV Input Manager Service (TIMS) -
MediaCodec
หรือตัวแปลงสัญญาณสื่อ -
AudioTrack
หรือแทร็กเสียง -
MediaResourceManager
หรือตัวจัดการทรัพยากรสื่อ (MRM)
รูปที่ 1. การโต้ตอบระหว่างส่วนประกอบของ Android TV
คุณสมบัติ
ส่วนหน้ารองรับมาตรฐาน DTV ด้านล่าง
- เอทีเอสซี
- ATSC3
- DVB-C/S/T
- ISDB S/S3/T
- อนาล็อก
ฟรอนต์เอนด์ใน Android 12 ที่มี Tuner HAL 1.1 ขึ้นไปรองรับมาตรฐาน DTV ด้านล่าง
- ดีทีเอ็มบี
Demux รองรับโปรโตคอลสตรีมด้านล่าง
- กระแสการขนส่ง (TS)
- โปรโตคอลการขนส่งสื่อ MPEG (MMTP)
- อินเทอร์เน็ตโปรโตคอล (IP)
- ประเภทค่าความยาว (TLV)
- โปรโตคอลลิงค์เลเยอร์ ATSC (ALP)
Descrambler รองรับการป้องกันเนื้อหาด้านล่าง
- เส้นทางสื่อที่ปลอดภัย
- ล้างเส้นทางสื่อ
- บันทึกท้องถิ่นที่ปลอดภัย
- การเล่นในเครื่องอย่างปลอดภัย
Tuner API รองรับกรณีการใช้งานด้านล่าง
- สแกน
- สด
- การเล่น
- บันทึก
Tuner, MediaCodec
และ AudioTrack
รองรับโหมดการรับส่งข้อมูลด้านล่าง
- เพย์โหลด ES พร้อมบัฟเฟอร์หน่วยความจำที่ชัดเจน
- เพย์โหลด ES พร้อมที่จับหน่วยความจำที่ปลอดภัย
- ทะลุผ่าน
การออกแบบโดยรวม
Tuner HAL ถูกกำหนดไว้ระหว่างเฟรมเวิร์ก Android และฮาร์ดแวร์ของผู้จำหน่าย
- อธิบายสิ่งที่กรอบงานคาดหวังจากผู้ขายและวิธีที่ผู้ขายสามารถทำได้
- ส่งออกฟังก์ชันการทำงานของส่วนหน้า, demux และ descrambler ไปยังเฟรมเวิร์กผ่านอินเทอร์เฟ
IFrontend
,IDemux
,IDescrambler
,IFilter
,IDvr
และILnb
- รวมฟังก์ชันเพื่อรวม Tuner HAL เข้ากับส่วนประกอบเฟรมเวิร์กอื่นๆ เช่น
MediaCodec
และAudioTrack
มีการสร้างคลาส Tuner Java และคลาสเนทิฟ
- 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
ได้รับการปรับปรุงด้วยคุณสมบัติด้านล่าง
- ใช้หน่วยความจำ A/V ที่ปลอดภัยเป็นอินพุตเนื้อหา
- กำหนดค่าให้ทำการซิงค์ A/V ของฮาร์ดแวร์ในการเล่นแบบทันเนล
- กำหนดค่าการสนับสนุนสำหรับ
ES_payload
และโหมดพาสทรู
รูปที่ 2 ไดอะแกรมของส่วนประกอบภายใน Tuner HAL
ขั้นตอนการทำงานโดยรวม
แผนภาพด้านล่างแสดงลำดับการโทรสำหรับการเล่นการถ่ายทอดสด
ติดตั้ง
รูปที่ 3 ลำดับการตั้งค่าสำหรับการเล่นการถ่ายทอดสด
การจัดการ A/V
รูปที่ 4 การจัดการ A/V สำหรับการเล่นการถ่ายทอดสด
การจัดการเนื้อหาที่มีสัญญาณรบกวน
รูปที่ 5 การจัดการเนื้อหาที่มีสัญญาณรบกวนสำหรับการเล่นการถ่ายทอดสด
กำลังประมวลผลข้อมูล A/V
รูปที่ 6 การประมวลผล A/V สำหรับการเล่นการถ่ายทอดสด
จูนเนอร์ SDK API
Tuner SDK API จัดการการโต้ตอบกับ Tuner JNI, Tuner HAL และ TunerResourceManager
แอป TIS ใช้ Tuner SDK API เพื่อเข้าถึงทรัพยากร Tuner และส่วนประกอบย่อย เช่น ตัวกรองและตัวถอดรหัส ส่วนหน้าและ demux เป็นส่วนประกอบภายใน
รูปที่ 7 การโต้ตอบกับ Tuner SDK API
รุ่นต่างๆ
ตั้งแต่ Android 12 เป็นต้นไป Tuner SDK API รองรับฟีเจอร์ใหม่ใน Tuner HAL 1.1 ซึ่งเป็นเวอร์ชันที่เข้ากันได้แบบย้อนหลังของ Tuner 1.0
ใช้ API ต่อไปนี้เพื่อตรวจสอบเวอร์ชัน HAL ที่ทำงานอยู่
-
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
ดูเวอร์ชัน HAL ขั้นต่ำที่จำเป็นได้ในเอกสารประกอบของ Android 12 API ใหม่
แพ็คเกจ
Tuner SDK API มีแพ็คเกจสี่แพ็คเกจด้านล่าง
-
android.media.tv.tuner
-
android.media.tv.tuner.frontend
-
android.media.tv.tuner.filter
-
android.media.tv.tuner.dvr
รูปที่ 8 แพ็คเกจ Tuner SDK API
Android.media.tv.tuner
แพ็คเกจ Tuner เป็นจุดเริ่มต้นในการใช้เฟรมเวิร์ก Tuner แอป TIS ใช้แพ็คเกจเพื่อเริ่มต้นและรับอินสแตนซ์ทรัพยากรโดยระบุการตั้งค่าเริ่มต้นและการโทรกลับ
-
tuner()
: เริ่มต้นอินสแตนซ์ Tuner โดยการระบุพารามิเตอร์useCase
และsessionId
-
tune()
: รับทรัพยากรส่วนหน้าและปรับแต่งโดยการระบุพารามิเตอร์FrontendSetting
-
openFilter()
: รับอินสแตนซ์ตัวกรองโดยการระบุประเภทตัวกรอง -
openDvrRecorder()
: รับอินสแตนซ์การบันทึกโดยการระบุขนาดบัฟเฟอร์ -
openDvrPlayback()
: รับอินสแตนซ์การเล่นโดยการระบุขนาดบัฟเฟอร์ -
openDescrambler()
: รับอินสแตนซ์ descrambler -
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 ที่ใช้ 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 ID) แนะนำให้ใช้ Tuner.tune
เป็นตัวเลือกที่เร็วกว่า .
เมื่อผู้ใช้เรียก Tuner.tune
การกระทำต่อไปนี้จะเกิดขึ้น:
- TIS เติม
FrontendSettings
ด้วยข้อมูลที่จำเป็นโดยใช้Tuner.tune
- HAL รายงานการปรับแต่งข้อความ
LOCKED
หากสัญญาณถูกล็อค - TIS ใช้
Frontend.getStatus
เพื่อรวบรวมข้อมูลที่จำเป็น - TIS ย้ายไปยังความถี่ถัดไปที่มีอยู่ในรายการความถี่
TIS จะเรียก Tuner.tune
อีกครั้งจนกว่าความถี่ทั้งหมดจะหมด
ระหว่างการจูน คุณสามารถเรียก stopTune()
หรือ close()
เพื่อหยุดชั่วคราวหรือวางสายการเรียก Tuner.tune
จูนเนอร์.สแกน(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()
เพื่อหยุดชั่วคราวหรือสิ้นสุดการสแกนได้
จูนเนอร์.สแกน(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
จะถูกละเว้น) - TIS ทำซ้ำการกระทำข้างต้นจนกว่าการตั้งค่าความถี่ทั้งหมดจะหมด HAL เพิ่มความถี่โดยไม่จำเป็นต้องดำเนินการใดๆ จาก TIS HAL รายงาน
PROGRESS
TIS จะเรียก Tuner.scan(AUTO_SCAN)
อีกครั้งจนกว่าความถี่ทั้งหมดจะหมด HAL รายงาน END
เพื่อระบุว่าการสแกนเสร็จสิ้นแล้ว
ในระหว่างการสแกน คุณสามารถเรียก stopScan()
หรือ close()
เพื่อหยุดชั่วคราวหรือสิ้นสุดการสแกนได้
รูปที่ 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: | บังคับ:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ที่แนะนำ: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | ตามงานและกำหนดการภายในงานวิ่งFilter.read(buffer, offset, adjustedSize) หนึ่งครั้งหรือมากกว่าข้อมูลถูกคัดลอกจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ | แพคเกจเซสชั่นที่ประกอบหนึ่งชุดถูกเติมใน FMQ โดยแพ็คเกจเซสชั่นอื่น |
isRaw: | บังคับ:DemuxFilterEvent::DemuxFilterSectionEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ไม่จำเป็น: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ ข้อมูลถูกคัดลอกจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ | ||
TS.PES | isRaw: | บังคับ:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ที่แนะนำ: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | ตามงานและกำหนดการภายในงานวิ่งFilter.read(buffer, offset, adjustedSize) หนึ่งครั้งหรือมากกว่าข้อมูลจะถูกคัดลอกจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ | แพ็คเกจ PES ที่ประกอบแล้วหนึ่งชุดจะถูกเติมใน FMQ ด้วยแพ็คเกจ PES อีกชุดหนึ่ง |
isRaw: | บังคับ:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ไม่จำเป็น: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ ข้อมูลถูกคัดลอกจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ | ||
MMTP.PES | isRaw: | บังคับ:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ที่แนะนำ: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | ตามงานและกำหนดการภายในงานวิ่งFilter.read(buffer, offset, adjustedSize) หนึ่งครั้งหรือมากกว่าข้อมูลจะถูกคัดลอกจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ | แพ็คเกจ MFU ที่ประกอบแล้วหนึ่งแพ็คเกจถูกเติมใน FMQ ด้วยแพ็คเกจ MFU อื่น |
isRaw: | บังคับ:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ไม่จำเป็น: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ ข้อมูลจะถูกคัดลอกจาก 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: | ไม่จำเป็น:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | ไคลเอนต์สามารถเริ่ม MediaCodec หลังจากได้รับ DemuxFilterStatus::DATA_READY ไคลเอนต์สามารถเรียก Filter.flush หลังจากได้รับ DemuxFilterStatus::DATA_OVERFLOW | ไม่มี |
isPassthrough: | บังคับ:DemuxFilterEvent::DemuxFilterMediaEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW ไม่จำเป็น: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | วิธีใช้ MediaCodec :for i=0; i<n; i++ วิธีใช้เสียงโดยตรงของ AudioTrack :for i=0; i<n; i++ | 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++ สำหรับเนื้อหาที่บันทึก ตาม RecordStatus::* และกำหนดการภายใน ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้:
| สำหรับข้อมูลดัชนี: ดำเนินการในเพย์โหลดเหตุการณ์ สำหรับเนื้อหาที่บันทึก: สตรีม 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++ | ไม่มี |
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++ สำหรับเนื้อหาที่บันทึก ตาม RecordStatus::* และกำหนดการภายใน ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้:
| สำหรับข้อมูลดัชนี: ดำเนินการในเพย์โหลดเหตุการณ์ สำหรับเนื้อหาที่บันทึก: สตรีมที่บันทึกแบบ Muxed เต็มไปด้วย 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: | ไม่จำเป็น:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | สตรีมย่อยโปรโตคอลที่ถูกกรองออกจะฟีดตัวกรองถัดไปในห่วงโซ่ตัวกรอง | ไม่มี |
isPassthrough: | บังคับ: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 | เพย์โหลดโปรโตคอลที่ถูกกรองออกจะฟีดตัวกรองถัดไปในห่วงโซ่ตัวกรอง | ไม่มี |
ตัวอย่างโฟลว์การใช้ตัวกรองเพื่อสร้าง PSI/SI
รูปที่ 10 ขั้นตอนการสร้าง PSI/SI
เปิดตัวกรอง
Filter filter = tuner.openFilter( Filter.TYPE_TS, Filter.SUBTYPE_SECTION, /* bufferSize */1000, executor, filterCallback );
กำหนดค่าและเริ่มตัวกรอง
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();
ประมวลผล
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 จากตัวกรอง
รูปที่ 11 ขั้นตอนการใช้ MediaEvent จากตัวกรอง
- เปิด กำหนดค่า และเริ่มตัวกรอง A/V
- ประมวลผล
MediaEvent
- รับ
MediaEvent
เว้นท์ - จัดคิวบล็อกเชิงเส้นเป็น
codec
- ปล่อยที่จับ A/V เมื่อข้อมูลถูกใช้ไป
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 โฟลว์เพื่อเริ่มเรกคอร์ด
เปิด กำหนดค่า และเริ่ม
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();
รับ
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. } } } };
เริ่มต้น
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); } } };
จูนเนอร์ HAL
Tuner HAL ติดตาม HIDL และกำหนดอินเทอร์เฟซระหว่างเฟรมเวิร์กและฮาร์ดแวร์ของผู้จำหน่าย ผู้จำหน่ายใช้อินเทอร์เฟซเพื่อใช้งาน Tuner HAL และเฟรมเวิร์กใช้เพื่อสื่อสารกับการใช้งาน Tuner HAL
โมดูล
จูนเนอร์ 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 |
จูนเนอร์ HAL 1.1 (มาจากจูนเนอร์ 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 |
รูปที่ 13 แผนผังของการโต้ตอบระหว่างโมดูล Tuner HAL
การเชื่อมโยงตัวกรอง
Tuner HAL รองรับการเชื่อมโยงตัวกรองเพื่อให้สามารถเชื่อมโยงตัวกรองกับตัวกรองอื่นสำหรับหลายเลเยอร์ได้ ตัวกรองเป็นไปตามกฎด้านล่าง
- ตัวกรองเชื่อมโยงกันเป็นต้นไม้ ไม่อนุญาตให้ใช้เส้นทางปิด
- โหนดรูทคือ 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 เดียวกัน TV Input Framework (TIF) ใช้กลไก "การได้รับชัยชนะก่อน" ซึ่งหมายความว่าแอปใดก็ตามที่ได้รับทรัพยากรก่อนจะเก็บทรัพยากรไว้ อย่างไรก็ตาม กลไกนี้อาจไม่เหมาะสำหรับกรณีการใช้งานที่ซับซ้อนบางกรณี
TRM ทำงานเป็นบริการระบบเพื่อจัดการทรัพยากรฮาร์ดแวร์ Tuner, TVInput
และ CAS สำหรับแอป TRM ใช้กลไก "การชนะในเบื้องหน้า" ซึ่งจะคำนวณลำดับความสำคัญของแอปตามสถานะเบื้องหน้าหรือเบื้องหลังของแอปและประเภทกรณีการใช้งาน TRM ให้หรือเพิกถอนทรัพยากรตามลำดับความสำคัญ TRM รวมศูนย์การจัดการทรัพยากร ATV สำหรับการออกอากาศ OTT และ DVR
อินเตอร์เฟซ TRM
TRM เปิดเผยอินเทอร์เฟซ AIDL ใน ITunerResourceManager.aidl
สำหรับเฟรมเวิร์ก Tuner, 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
ค่าลำดับความสำคัญตามอำเภอใจและความคุ้มค่าที่ดี
TRM จัดให้มี updateClientPriority
สำหรับไคลเอนต์เพื่ออัปเดตค่าลำดับความสำคัญตามอำเภอใจและค่าที่ดี ค่าลำดับความสำคัญที่กำหนดเองจะเขียนทับค่าลำดับความสำคัญที่คำนวณจากประเภทกรณีการใช้งานและรหัสเซสชัน
ค่าที่ดีบ่งชี้ว่าพฤติกรรมของลูกค้ามีความผ่อนปรนเพียงใดเมื่อขัดแย้งกับลูกค้ารายอื่น ค่าที่ดีจะลดค่าลำดับความสำคัญของลูกค้าก่อนที่จะเปรียบเทียบกับค่าลำดับความสำคัญกับลูกค้าที่ท้าทาย
กลไกการเรียกคืน
แผนภาพด้านล่างแสดงวิธีการเรียกคืนและมอบหมายทรัพยากรเมื่อเกิดข้อขัดแย้งด้านทรัพยากร
รูปที่ 15. แผนผังกลไกการเรียกคืนข้อขัดแย้งระหว่างทรัพยากรของ Tuner