เฟรมเวิร์กระบบการเข้าถึงแบบมีเงื่อนไขของสื่อ (Media CAS) มี API มาตรฐานเพื่อเปิดใช้บริการการเข้าถึงแบบมีเงื่อนไข (CA) ในฮาร์ดแวร์ทีวีดิจิทัลที่หลากหลาย ซึ่งรวมถึงระบบเคเบิล ดาวเทียม ระบบภาคพื้นดิน และ IPTV ดิจิทัล เฟรมเวิร์กนี้ทำงานร่วมกับเฟรมเวิร์กอินพุต Android TV และเฟรมเวิร์กตัวรับสัญญาณ Android TV โดยให้บริการ Java API ที่เรียกใช้จากแอปบริการอินพุตทีวี (TIS)
วัตถุประสงค์หลักของ Media CAS มีดังนี้
- ให้บริการ Java API สาธารณะและเฟรมเวิร์กปลั๊กอินเนทีฟที่นักพัฒนาแอปบุคคลที่สามและ OEM สามารถใช้เพื่อรองรับ CAS สำหรับทีวีแบบออกอากาศใน Android
- ให้บริการเฟรมเวิร์ก CAS ภายใน Android ซึ่งช่วยให้ OEM ของ ATV ทำงานร่วมกันกับผู้ให้บริการ CAS หลายรายได้อย่างสอดคล้องกัน
- รองรับผู้ให้บริการ CAS บุคคลที่สามหลายรายโดยใช้ปลั๊กอินแบบเนทีฟ ปลั๊กอิน CAS อาจใช้โปรโตคอลเครือข่ายเฉพาะของผู้ให้บริการ รูปแบบข้อความการจัดการการให้สิทธิ์ (EMM)/ข้อความควบคุมการให้สิทธิ์ (ECM) และโปรแกรมถอดรหัส
- รองรับการรักษาความปลอดภัยด้วยฮาร์ดแวร์ เช่น บันไดคีย์
- รองรับสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ (TEE) เช่น TrustZone
การกำหนดค่าที่รองรับ
การกำหนดค่าตัวรับสัญญาณฮาร์ดแวร์
หากฮาร์ดแวร์มีหน้าที่รับผิดชอบในการแยกข้อมูลหลายรายการออกจากสตรีมการขนส่ง MPEG และการถอดรหัส เฟรมเวิร์กตัวรับสัญญาณจะส่งข้อมูล PSI (ข้อมูลเฉพาะโปรแกรมที่มีการเข้าถึงแบบมีเงื่อนไข) ไปยังแอป TIS เพื่อเชื่อมต่อกับตัวรับสัญญาณทีวีแบบฮาร์ดแวร์
ข้อมูล PSI ของสิทธิ์เข้าถึงแบบมีเงื่อนไขประกอบด้วยข้อบ่งชี้ CA, ECM และ EMM โครงสร้างเหล่านี้ช่วยให้ปลั๊กอิน CAS รับคีย์ที่จําเป็นในการถอดรหัสสตรีมเนื้อหาได้
รูปที่ 1 การกำหนดค่าตัวรับสัญญาณฮาร์ดแวร์
การกำหนดค่าฮาร์ดแวร์อาจมีเลเยอร์ TEE เช่น TrustZone ดังที่แสดงในรูปที่ 1 หากไม่มีเลเยอร์ TEE ปลั๊กอินไคลเอ็นต์ CAS จะสื่อสารกับบริการบันไดคีย์ฮาร์ดแวร์ที่แพลตฟอร์มให้บริการได้ เนื่องจากอินเทอร์เฟซเหล่านี้มีรูปแบบเฉพาะสำหรับผู้ให้บริการแต่ละราย Media CAS จึงไม่ได้กำหนดมาตรฐานให้
การกำหนดค่าซอฟต์แวร์
ก่อน Android 11 เฟรมเวิร์ก Media CAS ยังคงใช้ประมวลผลเนื้อหาที่ทำงานด้วยซอฟต์แวร์ได้ เช่น IPTV จาก IP multicast/unicast แอป TIS มีหน้าที่สร้างอินสแตนซ์และจัดสรรออบเจ็กต์ Java ของ Media CAS อย่างถูกต้อง
แอปอาจใช้ MediaExtractor หรือโปรแกรมแยกวิเคราะห์ MPEG2-TS อื่นๆ เพื่อดึงข้อมูล PSI ที่เกี่ยวข้องกับ CA เช่น ตัวบ่งชี้ CA, ECM และ EMM หากแอปใช้เฟรมเวิร์ก MediaExtractor ก็จะมอบสิทธิ์การจัดการเซสชัน CAS เช่น การเปิดเซสชันและการประมวลผล EMM/ECM ให้กับเฟรมเวิร์ก MediaExtractor ได้ จากนั้น MediaExtractor จะกําหนดค่าเซสชัน CAS โดยใช้ API เดิมโดยตรง
ไม่เช่นนั้น แอปจะต้องรับผิดชอบในการดึงข้อมูล PSI ที่เกี่ยวข้องกับ CA และการกำหนดค่าเซสชัน CAS โดยใช้ Media CAS Java API (เช่น เมื่อแอปใช้โปรแกรมแยกวิเคราะห์ MPEG2-TS ของตนเอง)
รูปที่ 2 การกำหนดค่าอินพุต IPTV, CAS และโปรแกรมถอดรหัสโดยใช้เฟรมเวิร์ก MediaExtractor
ในสถานการณ์ตัวแยกซอฟต์แวร์ ตัวแยกต้องใช้ออบเจ็กต์โปรแกรมถอดรหัสหรือฮาร์ดแวร์ถอดรหัสสำหรับแต่ละแทร็กที่มีการเข้ารหัส ไม่ว่าแทร็กจะเรียกใช้โปรแกรมถอดรหัสที่ปลอดภัยหรือไม่ก็ตาม สาเหตุมีดังนี้
- หากแทร็กไม่จำเป็นต้องใช้การถอดรหัสที่ปลอดภัย โปรแกรมแยกจะถอดรหัสกลุ่มเข้าถึงเพื่อล้างบัฟเฟอร์และดึงตัวอย่างออกราวกับว่ามาจากสตรีมที่ชัดเจน วิธีนี้ช่วยให้
MediaCodec
ไม่ต้องมีส่วนร่วมในการถอดรหัส หากแทร็กต้องใช้การถอดรหัสที่ปลอดภัย เครื่องมือแยกไฟล์อาจยังคงต้องใช้โปรแกรมถอดรหัส ปัญหานี้เกิดขึ้นเมื่อสตรีมการโอนย้ายมีการเข้ารหัสที่ระดับแพ็กเก็ตการโอนย้าย ซึ่งมีการเข้ารหัสส่วนหัวสตรีมพื้นฐาน (PES) ที่แพ็กเก็ต เครื่องมือแยกต้องเข้าถึงส่วนหัว PES เพื่อส่งต่อข้อมูลบางอย่าง (เช่น การประทับเวลาของการแสดง)
โปรแกรมแยกข้อมูลจะไม่ใช้โปรแกรมถอดรหัสหากสตรีมการขนส่งได้รับการถอดรหัสที่ระดับแพ็กเก็ต PES โดยที่ส่วนหัว PES ยังคงอยู่ อย่างไรก็ตาม คุณจะยืนยันไม่ได้ว่าการสับสนเกิดขึ้นเมื่อใดจนกว่าแพ็กเก็ตที่มีการสับสนจริงจะมาถึง เพื่อความง่าย สมมติว่าระบบจะใช้โปรแกรมถอดรหัสหากระบบพิจารณาว่ามีการทำให้ข้อมูลในแทร็กสับสนตามตารางการแมปโปรแกรม (PMT)
ข้อจำกัดในการกำหนดค่าซอฟต์แวร์
เมื่อแทร็กต้องมีการถอดรหัสที่ปลอดภัย โปรแกรมถอดรหัสจะต้องระมัดระวังเมื่ออนุญาตให้การดำเนินการถอดรหัสไปยังบัฟเฟอร์ที่ชัดเจน เนื่องจากต้องมีการถอดรหัสเสียงที่ไม่ปลอดภัย หากการถอดรหัสวิดีโอต้องใช้โปรแกรมถอดรหัสที่ไม่ปลอดภัย ก็ควรมีการสับเปลี่ยนรหัสในเซสชันอื่นจากเสียง ECM สำหรับเซสชันต้องส่งสัญญาณไปยังปลั๊กอินว่าต้องใช้โปรแกรมถอดรหัสที่ปลอดภัย
หรือปลั๊กอินต้องสามารถเชื่อมโยงคีย์กับนโยบายความปลอดภัยได้อย่างน่าเชื่อถือ ไม่เช่นนั้น แอปจะดึงเฟรมวิดีโอได้อย่างง่ายดายด้วยโปรแกรมถอดรหัสเสียง
แม้ว่าเซสชันจะต้องใช้โปรแกรมถอดรหัสที่ปลอดภัย แต่ตัวแยกข้อมูลอาจขอให้ส่งออกข้อมูลเพียงเล็กน้อยเพื่อล้างบัฟเฟอร์เพื่อประมวลผลส่วนหัว PES ปลั๊กอินต้องแยกวิเคราะห์เพย์โหลดการขนส่งเพื่อให้แน่ใจว่าเพย์โหลดเริ่มต้นด้วยส่วนหัว PES ของสตรีมประเภทที่เหมาะสม เพื่อป้องกันไม่ให้แอปที่เป็นอันตรายทําให้ปลั๊กอินแสดงผลหน่วยการเข้าถึงทั้งหมด ไม่เช่นนั้น ปลั๊กอินควรปฏิเสธคำขอ
ลำดับการปรับ CA
เมื่อปรับช่องใหม่ โมดูล TIS จะลงทะเบียนเพื่อรับข้อบ่งชี้ CA, ECM และ EMM จากเฟรมเวิร์ก PSI Tuner ตัวบ่งชี้ CA จะมีรหัสระบบ CA ซึ่งระบุผู้ให้บริการ CA ที่เฉพาะเจาะจงและข้อมูลอื่นๆ เฉพาะผู้ให้บริการ TIS จะค้นหา Media CAS เพื่อดูว่ามีปลั๊กอิน CAS ที่จัดการข้อบ่งชี้ CA ได้หรือไม่
รูปที่ 3 การปรับแต่งเนื้อหา CAS
หากระบบรองรับรหัส CA ระบบจะสร้างอินสแตนซ์ของ Media CAS และส่งข้อมูลส่วนตัวของผู้ให้บริการจากข้อบ่งชี้ CA ไปยังปลั๊กอิน จากนั้นระบบจะเปิดเซสชันใหม่ใน Media CAS เพื่อจัดการสตรีมเสียงและวิดีโอ เซสชันที่เปิดใหม่จะได้รับ ECM และ EMM สำหรับปลั๊กอิน
ตัวอย่างขั้นตอนของปลั๊กอิน CAS
TIS จะส่ง ECM ไปยังปลั๊กอิน CAS โดยใช้ Media CAS API ECM มีคําควบคุมที่เข้ารหัส ซึ่งต้องถอดรหัสโดยใช้ข้อมูลจาก EMM ปลั๊กอิน CAS จะกำหนดวิธีรับ EMM สำหรับเนื้อหาโดยอิงตามข้อมูลเฉพาะของผู้ให้บริการในข้อบ่งชี้ CA ซึ่งได้จากเมธอด setPrivateData()
EMM อาจส่งในแบนด์ของสตรีมเนื้อหาหรือนอกแบนด์โดยใช้คำขอเครือข่ายที่เริ่มต้นโดยปลั๊กอิน CA TIS ใช้processEMM()
เพื่อส่ง EMM ในแบนด์ให้กับปลั๊กอิน CA
หากต้องใช้คําขอเครือข่ายเพื่อรับ EMM ปลั๊กอิน CA จะมีหน้าที่รับผิดชอบในธุรกรรมเครือข่ายกับเซิร์ฟเวอร์ใบอนุญาต
รูปที่ 4 ตัวอย่างปลั๊กอิน CAS สำหรับการดำเนินการ EMM และ ECM
เมื่อได้รับ EMM แล้ว ปลั๊กอิน CA จะแยกวิเคราะห์เพื่อรับคีย์ที่เข้ารหัสเพื่อถอดรหัสคําควบคุม ระบบอาจโหลดคีย์ EMM ที่เข้ารหัสและคำควบคุมที่เข้ารหัสลงในลําดับคีย์หรือสภาพแวดล้อมที่เชื่อถือได้เพื่อถอดรหัสคําควบคุมและถอดรหัสสตรีมเนื้อหาในภายหลัง
Media CAS Java API
Media CAS Java API มีเมธอดต่อไปนี้
แสดงรายการปลั๊กอิน CA ทั้งหมดที่ใช้ได้บนอุปกรณ์
class MediaCas.PluginDescriptor { public String getName(); public int getSystemId(); } static PluginDescriptor[] enumeratePlugins();
สร้างอินสแตนซ์ Media CAS สำหรับระบบ CA ที่ระบุ ซึ่งหมายความว่าเฟรมเวิร์ก CAS ของสื่อจะจัดการระบบ CAS ได้หลายระบบพร้อมกัน
MediaCas(int CA_system_id); MediaCas(@NonNull Context context, int casSystemId, @Nullable String tvInputServiceSessionId, @PriorityHintUseCaseType int priorityHint);
ลงทะเบียนโปรแกรมรับฟังเหตุการณ์และอนุญาตให้แอประบุตัวแฮนเดิลที่ใช้ลูปเปอร์
interface MediaCas.EventListener { void onEvent(MediaCas, int event, int arg, byte[] data); void onSessionEvent(@NonNull MediaCas mediaCas, @NonNull Session session, int event, int arg, @Nullable byte[] data); void onPluginStatusUpdate(@NonNull MediaCas mediaCas, @PluginStatus int status, int arg); void onResourceLost(@NonNull MediaCas mediaCas); } void setEventListener(MediaCas.EventListener listener, Handler handler);
ส่งข้อมูลส่วนตัวสำหรับระบบ CA ข้อมูลส่วนตัวอาจมาจากข้อบ่งชี้ CA, ตารางการเข้าถึงแบบมีเงื่อนไข หรือแหล่งที่มานอกแบนด์ ซึ่งไม่ได้เชื่อมโยงกับเซสชันใดเซสชันหนึ่ง
void setPrivateData(@NonNull byte[] data);
ประมวลผลแพ็กเก็ต EMM
void processEmm(@NonNull byte[] data, int offset, int length);
ส่งเหตุการณ์ไปยังระบบ CA รูปแบบของเหตุการณ์จะเจาะจงสำหรับสคีมาและมองไม่เห็นเฟรมเวิร์ก
void sendEvent(int event, int arg, @Nullable byte[] data);
เริ่มการดำเนินการจัดสรรประเภทที่ระบุสำหรับระบบ CA เมื่ออุปกรณ์ลงชื่อสมัครใช้บริการทีวีแบบชำระเงินเป็นครั้งแรก อุปกรณ์จะต้องได้รับการจัดสรรให้กับเซิร์ฟเวอร์ CAS ก่อน ระบุชุดพารามิเตอร์ที่เกี่ยวข้องให้กับอุปกรณ์เพื่อการจัดสรร
void provision(String provisionString);
ทริกเกอร์การรีเฟรชการให้สิทธิ์ เมื่อผู้ใช้สมัครใช้บริการช่องใหม่ (เช่น โดยการตอบสนองต่อโฆษณาหรือเพิ่มช่องในคู่มือโปรแกรมอิเล็กทรอนิกส์ (EPG)) แอปควรบอกไคลเอ็นต์ CA ให้รีเฟรชคีย์การให้สิทธิ์
void refreshEntitlements(int refreshType);
ปิดออบเจ็กต์ CAS ของสื่อ
void close();
เปิดเซสชัน
Session openSession(); Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode);
ปิดเซสชันที่เปิดไว้ก่อนหน้านี้
void Session#close();
ระบุข้อมูลส่วนตัวของ CA จากข้อบ่งชี้ CA ใน PMT ซึ่งอาจมาจากส่วนข้อมูลโปรแกรมหรือข้อมูล ES ไปยังเซสชัน CAS
void Session#setPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data);
ประมวลผลแพ็กเก็ต ECM สำหรับเซสชัน
void Session#processEcm(@NonNull byte[] data, int offset, int length);
รับรหัสเซสชัน
byte[] Session#getSessionId();
ส่งเหตุการณ์เซสชันไปยังระบบ CA รูปแบบของเหตุการณ์จะเจาะจงสำหรับสคีมานั้นๆ และจะไม่แสดงในเฟรมเวิร์ก
void Session#sendSessionEvent(int event, int arg, @Nullable byte[] data);