กรอบงานจูนเนอร์

สำหรับ 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 และโหมดพาสทรู

การออกแบบโดยรวมของ Tuner HAL

รูปที่ 2 ไดอะแกรมของส่วนประกอบภายใน Tuner HAL

ขั้นตอนการทำงานโดยรวม

แผนภาพด้านล่างแสดงลำดับการโทรสำหรับการเล่นการถ่ายทอดสด

ติดตั้ง

ลำดับการตั้งค่าแผนภาพการเล่นการถ่ายทอดสด

รูปที่ 3 ลำดับการตั้งค่าสำหรับการเล่นการถ่ายทอดสด

การจัดการ A/V

การจัดการ A/V สำหรับแผนภาพการเล่นการถ่ายทอดสด

รูปที่ 4 การจัดการ A/V สำหรับการเล่นการถ่ายทอดสด

การจัดการเนื้อหาที่มีสัญญาณรบกวน

การจัดการเนื้อหาที่มีสัญญาณรบกวนสำหรับแผนภาพการเล่นการถ่ายทอดสด

รูปที่ 5 การจัดการเนื้อหาที่มีสัญญาณรบกวนสำหรับการเล่นการถ่ายทอดสด

กำลังประมวลผลข้อมูล A/V

ประมวลผลข้อมูล A/V สำหรับแผนภาพการเล่นการถ่ายทอดสด

รูปที่ 6 การประมวลผล A/V สำหรับการเล่นการถ่ายทอดสด

จูนเนอร์ SDK API

Tuner SDK API จัดการการโต้ตอบกับ Tuner JNI, Tuner HAL และ TunerResourceManager แอป TIS ใช้ Tuner SDK API เพื่อเข้าถึงทรัพยากร Tuner และส่วนประกอบย่อย เช่น ตัวกรองและตัวถอดรหัส ส่วนหน้าและ demux เป็นส่วนประกอบภายใน

แผนภาพโฟลว์ของ Tuner SDK API

รูปที่ 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

ไดอะแกรมโฟลว์ของแพ็คเกจ Tuner SDK API

รูปที่ 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() เพื่อหยุดชั่วคราวหรือสิ้นสุดการสแกนได้

แผนภาพการไหลของกระบวนการสแกน 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) หนึ่งครั้งหรือมากกว่า

ข้อมูลถูกคัดลอกจาก 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 ไปยังบัฟเฟอร์ไคลเอ็นต์
แพ็คเกจ 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)


ข้อมูลถูกคัดลอกจาก 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
ไคลเอนต์สามารถเรียก 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) หนึ่งครั้งหรือมากกว่าเพื่อจัดเก็บข้อมูล
    ข้อมูลจะถูกถ่ายโอนจาก MQ ของ HAL ไปยังที่จัดเก็บข้อมูล
  • เรียกใช้ DvrRecord.write(buffer, adustedSize) หนึ่งครั้งหรือมากกว่าเพื่อบัฟเฟอร์
    ข้อมูลจะถูกคัดลอกจาก MQ ของ HAL ไปยังบัฟเฟอร์ไคลเอ็นต์
สำหรับข้อมูลดัชนี: ดำเนินการในเพย์โหลดเหตุการณ์

สำหรับเนื้อหาที่บันทึก: สตรีม Muxed TS ที่เติมใน FMQ
TS.TEMI ไม่มี บังคับ:
DemuxFilterEvent::DemuxFilterTemiEvent[n]

ไม่จำเป็น:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
DemuxFilterTemiEvent[i];
ไม่มี
MMTP.MMTP ไม่มี บังคับ:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

ที่แนะนำ:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
ตามงานและกำหนดการภายในงานวิ่ง
Filter.read(buffer, offset, adjustedSize) หนึ่งครั้งหรือมากกว่า

ข้อมูลจะถูกคัดลอกจาก 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 ไปยังบัฟเฟอร์ไคลเอ็นต์
สำหรับข้อมูลดัชนี: ดำเนินการในเพย์โหลดเหตุการณ์

สำหรับเนื้อหาที่บันทึก: สตรีมที่บันทึกแบบ 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:
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
เพย์โหลดโปรโตคอลที่ถูกกรองออกจะฟีดตัวกรองถัดไปในห่วงโซ่ตัวกรอง ไม่มี
ตัวอย่างโฟลว์การใช้ตัวกรองเพื่อสร้าง 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. ปล่อยที่จับ 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 โฟลว์เพื่อเริ่มเรกคอร์ด

  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);
          }
        }
      };
    

จูนเนอร์ 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

แผนภาพการไหลของการโต้ตอบระหว่างโมดูลของ Tuner 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