เฟรมเวิร์กระบบการเข้าถึงแบบมีเงื่อนไขของสื่อ (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 และถอดรหัส Tuner Framework จะให้ข้อมูลเฉพาะโปรแกรม (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);
ลงทะเบียนเครื่องมือฟังเหตุการณ์และอนุญาตให้แอประบุตัวแฮนเดิลที่มีการใช้ Looper
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);
ปิดออบเจ็กต์ Media 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);