สำหรับ Android 11 ขึ้นไป คุณสามารถใช้เฟรมเวิร์ก Android Tuner เพื่อส่งเนื้อหา A/V เฟรมเวิร์กนี้ใช้ไปป์ไลน์ฮาร์ดแวร์จากผู้ให้บริการ จึงเหมาะสำหรับทั้ง SoC ระดับล่างและระดับสูง เฟรมเวิร์กนี้มีวิธีที่ปลอดภัยในการส่งเนื้อหา A/V ที่ได้รับการปกป้องโดย สภาพแวดล้อมการดำเนินการที่เชื่อถือได้ (TEE) และเส้นทางสื่อที่ปลอดภัย (SMP) ซึ่งช่วยให้สามารถ ใช้ในสภาพแวดล้อมการปกป้องเนื้อหาที่มีการจำกัดสูง
อินเทอร์เฟซที่ได้มาตรฐานระหว่างจูนเนอร์กับผลลัพธ์ของ Android CAS ช่วยให้การผสานรวมระหว่างผู้ให้บริการจูนเนอร์กับผู้ให้บริการ CAS เร็วขึ้น
อินเทอร์เฟซของจูนเนอร์ทำงานร่วมกับ MediaCodec
และ AudioTrack
เพื่อสร้างโซลูชันเดียวสำหรับ Android TV
อินเทอร์เฟซจูนเนอร์รองรับทั้งทีวีดิจิทัลและทีวีอนาล็อกตามมาตรฐานการออกอากาศหลัก
คอมโพเนนต์
สำหรับ Android 11 มีคอมโพเนนต์ 3 อย่างที่ออกแบบมาสำหรับแพลตฟอร์มทีวีโดยเฉพาะ
- Tuner HAL: อินเทอร์เฟซระหว่างเฟรมเวิร์กและผู้ให้บริการ
- Tuner SDK API: อินเทอร์เฟซระหว่างเฟรมเวิร์กกับแอป
- ตัวจัดการทรัพยากรของจูนเนอร์ (TRM): ประสานงานทรัพยากร HW ของจูนเนอร์
สำหรับ Android 11 เราได้ปรับปรุงคอมโพเนนต์ต่อไปนี้
- CAS V2
TvInputService
หรือบริการอินพุตทีวี (TIS)TvInputManagerService
หรือบริการตัวจัดการอินพุตทีวี (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
Demux รองรับโปรโตคอลสตรีมด้านล่าง
- สตรีมการนำส่ง (TS)
- โปรโตคอลการนำส่งสื่อ MPEG (MMTP)
- Internet Protocol (IP)
- ค่าความยาวประเภท (TLV)
- โปรโตคอลเลเยอร์ลิงก์ ATSC (ALP)
โปรแกรมถอดรหัสรองรับการปกป้องเนื้อหาด้านล่าง
- เส้นทางสื่อที่ปลอดภัย
- เส้นทางสื่อที่ชัดเจน
- บันทึกในเครื่องอย่างปลอดภัย
- การเล่นในเครื่องอย่างปลอดภัย
Tuner API รองรับกรณีการใช้งานต่อไปนี้
- สแกน
- Live
- การเล่น
- บันทึก
Tuner, MediaCodec
และ AudioTrack
รองรับโหมดการไหลของข้อมูลด้านล่าง
- เพย์โหลด ES ที่มีบัฟเฟอร์หน่วยความจำที่ชัดเจน
- เพย์โหลด 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
ได้รับการปรับปรุงด้วยฟีเจอร์ด้านล่าง
- ใช้หน่วยความจำ A/V ที่ปลอดภัยเป็นอินพุตเนื้อหา
- กำหนดค่าให้ซิงค์ A/V ของฮาร์ดแวร์ในการเล่นแบบอุโมงค์
- รองรับ
ES_payload
และโหมดส่งผ่าน
รูปที่ 2 แผนภาพของคอมโพเนนต์ภายใน Tuner HAL
เวิร์กโฟลว์โดยรวม
แผนภาพด้านล่างแสดงลำดับการเรียกสำหรับการเล่นการถ่ายทอดสด
ตั้งค่า
รูปที่ 3 ลำดับการตั้งค่าสำหรับการเล่นการออกอากาศสด
การจัดการ A/V
รูปที่ 4 การจัดการ A/V สำหรับการเล่นการถ่ายทอดสด
การจัดการเนื้อหาที่เข้ารหัส
รูปที่ 5 การจัดการเนื้อหาที่เข้ารหัสสำหรับการเล่นการถ่ายทอดสด
การประมวลผลข้อมูลภาพและเสียง
รูปที่ 6 กำลังประมวลผล A/V สำหรับการเล่นการถ่ายทอดสด
Tuner SDK API
API ของ Tuner SDK จะจัดการการโต้ตอบกับ Tuner JNI, Tuner HAL
และ TunerResourceManager
แอป TIS ใช้ Tuner SDK API เพื่อเข้าถึงแหล่งข้อมูลและคอมโพเนนต์ย่อยของจูนเนอร์ เช่น ฟิลเตอร์และตัวถอดรหัส Frontend และ
demux เป็นคอมโพเนนต์ภายใน
รูปที่ 7 การโต้ตอบกับ Tuner SDK API
เวอร์ชัน
ตั้งแต่ Android 12 เป็นต้นไป API ของ Tuner SDK จะรองรับฟีเจอร์ใหม่ใน Tuner HAL 1.1 ซึ่ง เป็นการอัปเกรดเวอร์ชัน Tuner 1.0 ที่เข้ากันได้แบบย้อนหลัง
ใช้ API ต่อไปนี้เพื่อตรวจสอบเวอร์ชัน HAL ที่ทำงานอยู่
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
ดูเวอร์ชัน HAL ขั้นต่ำที่จำเป็นได้ในเอกสารประกอบของ API ใหม่ของ Android 12
แพ็กเกจ
API ของ Tuner SDK มีแพ็กเกจ 4 รายการด้านล่าง
android.media.tv.tuner
android.media.tv.tuner.frontend
android.media.tv.tuner.filter
android.media.tv.tuner.dvr
รูปที่ 8 แพ็กเกจ API ของ Tuner SDK
Android.media.tv.tuner
แพ็กเกจ Tuner เป็นจุดแรกเข้าในการใช้เฟรมเวิร์ก Tuner แอป TIS ใช้แพ็กเกจเพื่อเริ่มต้นและรับอินสแตนซ์ทรัพยากรโดยการระบุ การตั้งค่าเริ่มต้นและการเรียกกลับ
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 ที่มี 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 calls
Tuner.scan
for the HAL to continue to the next setting on the same frequency. หากโครงสร้างFrontendSettings
ว่างเปล่า HAL จะใช้การตั้งค่าถัดไป ที่พร้อมใช้งาน ไม่เช่นนั้น HAL จะใช้FrontendSettings
สำหรับการสแกนแบบครั้งเดียว และส่งEND
เพื่อระบุว่าการดำเนินการสแกนเสร็จสิ้นแล้วTIS จะทำซ้ำการดำเนินการข้างต้นจนกว่าการตั้งค่าทั้งหมดในความถี่จะ หมด
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
จะ ไม่สนใจ) - 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) อย่างน้อย 1 ครั้ง
ตามกิจกรรมและกำหนดการภายในระบบจะคัดลอกข้อมูลจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ |
แพ็กเกจเซสชันที่ประกอบขึ้น 1 รายการจะได้รับการส่งใน 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) อย่างน้อย 1 ครั้ง
ตามกิจกรรมและกำหนดการภายในระบบจะคัดลอกข้อมูลจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ |
แพ็กเกจ PES ที่ประกอบแล้ว 1 แพ็กเกจจะได้รับการเติมใน 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) อย่างน้อย 1 ครั้ง
ตามกิจกรรมและกำหนดการภายในระบบจะคัดลอกข้อมูลจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ |
แพ็กเกจ MFU ที่ประกอบแล้ว 1 แพ็กเกจจะได้รับการเติมใน 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) อย่างน้อย 1 ครั้ง
ตามกิจกรรมและกำหนดการภายในระบบจะคัดลอกข้อมูลจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ |
ts ที่กรองออกจะได้รับการกรอกใน FMQ ts |
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::* และกำหนดการภายใน ให้ทำ
อย่างใดอย่างหนึ่งต่อไปนี้
|
สำหรับข้อมูลดัชนี: อยู่ในเพย์โหลดของเหตุการณ์ สำหรับเนื้อหาที่บันทึกไว้: สตรีม 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) อย่างน้อย 1 ครั้ง
ตามกิจกรรมและกำหนดการภายในระบบจะคัดลอกข้อมูลจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ |
mmtp ที่กรองออกจะได้รับการกรอกใน FMQ mmtp |
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::* และกำหนดการภายใน ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้
|
สำหรับข้อมูลดัชนี: อยู่ในเพย์โหลดของเหตุการณ์ สำหรับเนื้อหาที่บันทึกไว้: สตรีมที่บันทึกไว้ซึ่งมัลติเพล็กซ์แล้ว 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 |
สตรีมย่อยของโปรโตคอลที่กรองแล้วจะป้อนตัวกรองถัดไปในเชน filter | ไม่มี |
isPassthrough: |
ต้องระบุ:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW แนะนำ: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER |
เรียกใช้Filter.read(buffer, offset, adjustedSize) อย่างน้อย 1 ครั้ง
ตามกิจกรรมและกำหนดการภายในระบบจะคัดลอกข้อมูลจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์ |
กรองสตรีมย่อยของโปรโตคอลออกและกรอกส่วนหัวของโปรโตคอล FMQ | |
IP.PAYLOAD_THROUGH TLV.PAYLOAD_THROUGH ALP.PAYLOAD_THROUGH |
ไม่มี | ไม่บังคับ:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
ฟีดเพย์โหลดของโปรโตคอลที่กรองออกจะส่งไปยังตัวกรองถัดไปในเชน filter | ไม่มี |
ตัวอย่างโฟลว์ในการใช้ตัวกรองเพื่อสร้าง 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 Flow ในการใช้ 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
โมดูล
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 |
รูปที่ 13 แผนภาพการโต้ตอบระหว่างโมดูล 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) การสลับระหว่าง 2 แอปต้องใช้ฮาร์ดแวร์จูนเนอร์เดียวกัน TV Input Framework (TIF) ใช้กลไก "ใครได้ก่อนชนะ" ซึ่งหมายความว่าแอปใดก็ตามที่ได้รับทรัพยากรก่อนจะเก็บทรัพยากรนั้นไว้ อย่างไรก็ตาม กลไกนี้อาจไม่เหมาะกับ Use Case ที่ซับซ้อนบางอย่าง
TRM ทำงานเป็นบริการของระบบเพื่อจัดการฮาร์ดแวร์จูนเนอร์ 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
ระบุกรณีการใช้งานของเซสชัน Use Case ที่กำหนดไว้ล่วงหน้ามีดังนี้
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
ได้ ไฟล์นี้ใช้สำหรับ
เพิ่ม นำออก หรืออัปเดตประเภท Use Case และค่าลำดับความสำคัญของ Use Case
ไฟล์ที่ปรับแต่งแล้วสามารถใช้
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 จะลดค่าลำดับความสำคัญของไคลเอ็นต์ ก่อนที่จะเปรียบเทียบค่าลำดับความสำคัญกับไคลเอ็นต์ที่ท้าทาย
กลไกการเรียกคืน
แผนภาพด้านล่างแสดงวิธีเรียกคืนและกำหนดทรัพยากรใหม่เมื่อ เกิดความขัดแย้งของทรัพยากร
รูปที่ 15 แผนภาพของกลไกการเรียกคืนสำหรับความขัดแย้งระหว่างทรัพยากรของจูนเนอร์