Reproductores
Cómo configurar Shaka Player y Video.js para reproducir tu contenido protegido.
Lo que necesitas #
¿Prefieres no montarlo tú?
Dos cosas: la URL del manifiesto y las URLs del servidor de licencias. El reproductor elige por sí solo qué sistema DRM usar; tú solo le das las tres direcciones.
- Widevine
https://drm.airi.live/v2/widevine- PlayReady
https://drm.airi.live/v2/playready- FairPlay
https://drm.airi.live/fairplay- WisePlay
https://drm.airi.live/v2/wiseplay
Estas URLs son públicas, y está bien
Si aún no tienes contenido empaquetado, en Cifrar tu vídeo tienes un script, en Node y en Python, que hace todo el camino: pide las claves, transcodifica con ffmpeg y cifra en cbcs.
Shaka Player #
Es el más completo para DASH y HLS, y el que recomendamos si empiezas de cero.
import shaka from 'shaka-player/dist/shaka-player.compiled.js'; shaka.polyfill.installAll(); const video = document.querySelector('video'); const player = new shaka.Player(); await player.attach(video); player.configure({ drm: { servers: { 'com.widevine.alpha': 'https://drm.airi.live/v2/widevine', 'com.microsoft.playready': 'https://drm.airi.live/v2/playready', 'com.apple.fps': 'https://drm.airi.live/fairplay' } } }); await player.load('https://tu-bucket.s3.amazonaws.com/pelicula/manifest.mpd'); video.play();
Eso es todo para Widevine y PlayReady. FairPlay necesita además el certificado de Apple:
player.configure({ drm: { servers: { 'com.apple.fps': 'https://drm.airi.live/fairplay' }, advanced: { 'com.apple.fps': { // Certificado emitido por Apple a tu cuenta de desarrollador serverCertificateUri: 'https://tu-bucket.s3.amazonaws.com/fairplay.cer' } } } }); // FairPlay solo funciona sobre HLS await player.load('https://tu-bucket.s3.amazonaws.com/pelicula/master.m3u8');
Cuál sistema elige el navegador, y por qué importa
Si el dispositivo tiene más de uno, el reproductor elige por su cuenta — y lo hace antes de saber qué va a exigir tu regla. Edge tiene Widevine y PlayReady: suele coger Widevine, que en escritorio es solo software (L3). Si tu regla pide hardware, la licencia se deniega, aunque PlayReady sí hubiera podido servirla.
No cambia de sistema solo
Tienes dos formas de dirigirlo. La primera es declarar una preferencia:
player.configure({ drm: { servers: { /* ... */ }, preferredKeySystems: ['com.microsoft.playready'] } });
La segunda es mejor si lo que quieres es que el navegador descarte solo los que no sirven: declara la robustez que necesitas, y será el propio navegador quien rechace un sistema que no la alcanza, dejando que el reproductor pase al siguiente.
player.configure({ drm: { servers: { /* ... */ }, advanced: { 'com.widevine.alpha': { videoRobustness: 'HW_SECURE_DECODE' }, 'com.microsoft.playready': { videoRobustness: '3000' } } } });
En Windows, pedir SL3000 así no basta — y falla de la peor manera
com.microsoft.playready a secas te da el de software, cuyo certificado es SL2000 por muy capaz que sea la máquina. Pide SL3000 con él y el servidor de licencias rechaza — correctamente, porque el cliente que le presentaste no llega — en un equipo que sí podía reproducir.
El cliente de hardware solo responde si lo nombras, y el nombre se cambia con keySystemsMapping, no con preferredKeySystems: este último solo reordena candidatos que ya estén en el manifiesto, y el manifiesto trae el nombre base. Si prefieres un nombre ausente, Shaka vuelve al orden del manifiesto y puede acabar en otro DRM sin avisarte.// Comprueba primero si existe el cliente de hardware; si no, no lo pidas. const hw = await navigator.requestMediaKeySystemAccess( 'com.microsoft.playready.recommendation.3000', [{ initDataTypes: ['cenc'], videoCapabilities: [{ contentType: 'video/mp4; codecs="avc1.640028"', robustness: '3000' }] }] ).then(() => true, () => false); if (hw) { player.configure('drm.keySystemsMapping', { 'com.microsoft.playready': 'com.microsoft.playready.recommendation.3000' }); }
Y si no hay cliente de hardware, retira la calidad antes de pedirla
player.configure('restrictions.maxHeight', 720) antes de load(). La razón es que PlayReady no deniega, contesta un error de servidor, y recuperarse de eso a mitad de carga es un problema abierto de Shaka (#5421, #2135): la calidad se descarta pero la reproducción no arranca. Además, cada intento rechazado es una licencia que se te factura.
Un aviso sobre ese tope: si deja fuera todas las variantes —maxHeight 720 sobre un contenido que solo tiene 1080p, por ejemplo— Shaka lanza RESTRICTIONS_CANNOT_BE_MET (4012), que es un error crítico y no una degradación. Calcula el tope desde las alturas que existen, no desde un número fijo.Esa robustez tiene que coincidir con tu regla
En la demo puedes forzar cada sistema y ver el efecto en tu propio equipo.
Saber qué está pasando
Cuando algo falle, esto es lo que querrás mirar:
player.addEventListener('error', (event) => { console.error('código', event.detail.code, event.detail.data); }); // Ya reproduciendo: player.drmInfo(); // { keySystem, encryptionScheme, keyIds } player.getKeyStatuses(); // { '<kid>': 'usable' | 'output-restricted' | ... } player.getStats(); // width, height, streamBandwidth
`output-restricted` no es un error de configuración
Video.js #
Si ya usas Video.js, el DRM llega con el plugin videojs-contrib-eme. No viene incluido.
npm install video.js videojs-contrib-eme
import videojs from 'video.js'; import 'videojs-contrib-eme'; const player = videojs('mi-video'); player.eme(); // hay que activarlo explícitamente player.src({ src: 'https://tu-bucket.s3.amazonaws.com/pelicula/manifest.mpd', type: 'application/dash+xml', keySystems: { 'com.widevine.alpha': 'https://drm.airi.live/v2/widevine', 'com.microsoft.playready': 'https://drm.airi.live/v2/playready' } });
Olvidar `player.eme()` es el error más común
src().FairPlay en Video.js necesita más trabajo manual, porque hay que entregarle el certificado y transformar el reto:
player.src({ src: 'https://tu-bucket.s3.amazonaws.com/pelicula/master.m3u8', type: 'application/x-mpegURL', keySystems: { 'com.apple.fps.1_0': { certificateUri: 'https://tu-bucket.s3.amazonaws.com/fairplay.cer', licenseUri: 'https://drm.airi.live/fairplay' } } });
Para FairPlay, Shaka es más fácil
Cuando no reproduce #
Casi todos los fallos son uno de estos cinco. Van en orden de frecuencia.
1. Nada carga, y la consola habla de CORS
El bucket donde están los segmentos no permite peticiones desde tu dominio. Es lo primero que hay que descartar, porque el síntoma parece un problema de DRM y no lo es. Configura CORS con GET y HEAD permitidos.
2. Funciona en Chrome pero no en Safari
Dos causas posibles, y conviene comprobarlas en este orden: el contenido está cifrado en cenc en lugar de cbcs —FairPlay no entiende cenc—, o falta el certificado de Apple. Lo primero obliga a volver a empaquetar; lo segundo es configuración.
3. Reproduce, pero se queda en la calidad baja
Está funcionando como debe. El dispositivo no alcanza el nivel de seguridad que exige la calidad alta, así que el servidor de licencias le da la que sí puede. Compruébalo en la demo: te dice qué nivel tiene tu propio equipo.
4. El servidor de licencias devuelve 400 o 403
El keyId del vídeo no corresponde a ninguna clave tuya. Suele pasar cuando se empaquetó con una clave de prueba y luego se pidió otra, o cuando el key_id se pasó en base64 en lugar de hexadecimal al empaquetador.
5. Da un error de robustez al cargar
El navegador no ofrece el nivel que pide el contenido. En Chrome de escritorio es lo normal para cualquier cosa que exija hardware: ese navegador es L3.
La demo diagnostica tu dispositivo
cenc, cbcs o ambos. Cuando algo no reproduce, empieza por ahí.