Los canales FAST ganan dinero con las pausas comerciales. Todo el modelo de negocio se basa en una única suposición: cuando el canal dice "cut to ad", todos los sistemas downstream que escuchan —el ad server, el SSAI splicer, el reproductor de smart TV— lo oyen exactamente en el mismo momento, con la misma duración exacta. SCTE-35 es el protocolo estándar que lleva ese mensaje. Si se hace mal en silencio —y el silencio es el modo de fallo predeterminado— los anuncios o no se renderizan, se activan en el fotograma incorrecto o duran el tiempo equivocado. El espectador ve una pizarra. Los ingresos simplemente no existen.
Esta es la historia de ingeniería de cómo los canales FAST de mStudio emiten señales SCTE-35 conformes a los estándares desde entradas fáciles de usar para el operador, y por qué lo construimos como tres señales por pausa en lugar de una.
Resumen rápido
| Aspecto | Detalle |
|---|---|
| Dominio | Señalización de pausas publicitarias SCTE-35 para canales FAST de AWS MediaLive |
| Flujo de trabajo del operador | Editor de pausas publicitarias por programa — posición en segundos, duración en segundos |
| Señales emitidas por pausa | Tres — TimeSignal de inicio de anuncio, SpliceInsert, TimeSignal de fin de anuncio |
| Restricciones de duración | 10–120 segundos, validados en la capa de datos |
| Consumidores downstream | Los reproductores, los ad servers y AWS MediaTailor (diseñado pero aún no conectado) son ejemplos. |
| Estado | Emisión de señales SCTE-35 en producción; integración de SSAI en diseño |
El Problema de Negocio
Cada pausa comercial en un canal FAST es un evento de ingresos. El canal emite un marcador que dice "aquí irá un anuncio, durará 30 segundos, por favor prepárese." Los sistemas downstream —Google Ad Manager, AWS MediaTailor, ad servers regionales, SDKs de reproductores de smart TV— leen ese marcador y deciden qué insertar.
Cuando el marcador es correcto, la pausa publicitaria se ejecuta limpiamente, la impresión cuenta y el operador recibe el pago. Cuando el marcador es incorrecto —duración equivocada, forma equivocada, formato equivocado— el sistema publicitario lo rechaza (no se sirve ningún anuncio) o lo acepta incorrectamente (anuncio de duración incorrecta, o uno que se extiende al siguiente programa). Ambos resultados cuestan dinero real, y ambos fallan silenciosamente. El canal sigue transmitiendo. El espectador ve una pizarra o un corte incómodo. La pipeline de monetización simplemente produce números más bajos y ningún mensaje de error que perseguir.
El objetivo de ingeniería no es "soportar anuncios". Es: cada pausa publicitaria que el operador define debe llegar a cada consumidor downstream como una señal SCTE-35 conforme a los estándares, en el fotograma exacto que el operador eligió, cada vez.
Qué es realmente SCTE-35 (la versión de 90 segundos)
SCTE-35 es un estándar para insertar mensajes de señalización en un flujo de video. Las señales no llevan contenido publicitario; llevan señales — "la pausa publicitaria comienza aquí", "la pausa publicitaria termina aquí", "este segmento dura N segundos". El sistema downstream lee esas señales y actúa sobre ellas: una capa SSAI inserta una creatividad publicitaria real en el manifiesto HLS, un reproductor de smart TV activa una superposición, un ad server registra una oportunidad de slot.
Dos formas de señal son importantes para nuestro caso de uso:
- SpliceInsert — la señal SCTE-35 original. Lleva un SpliceEventId, una duración en segundos, y un flag de "fuera de la red". La mayoría de los ad servers clásicos leen esto.
- TimeSignal — la señal más nueva y expresiva. Lleva un SegmentationDescriptor con un SegmentationTypeId (52 = Provider Ad Start, 53 = Provider Ad End) y una SegmentationDuration en unidades de 90,000 ticks. Los sistemas SSAI y los reproductores modernos prefieren esta forma porque se empareja limpiamente entre el inicio y el final.
Ambas formas son SCTE-35 correctas. Diferentes consumidores downstream prefieren unas u otras. Emitir solo una forma deja dinero sobre la mesa.
Por qué esto importa. Una implementación ingenua emite un SpliceInsert por pausa publicitaria y lo da por terminado. La pausa publicitaria funciona en reproductores antiguos y falla silenciosamente en SSAI. La mitad de tu inventario publicitario monetiza; la otra mitad no. No sabrás cuál es cuál hasta que tus números de ingresos sean bajos.
Por qué fallan los enfoques ingenuos
Los atajos son tentadores porque todos casi funcionan.
- "En el momento de la codificación, insertar anuncios en el video original." No hay margen para la flexibilidad. El operador no puede realizar pruebas A/B de ubicación, no puede cambiar los anuncios después del despliegue, no puede ejecutar anuncios regionales o dirigidos a la audiencia. La razón principal de la existencia de los canales FAST es monetizar el mismo contenido de múltiples maneras; grabar los anuncios en el momento de la codificación impide esto.
- "Utilizar la inserción de anuncios del lado del cliente." El bloqueo de anuncios es sencillo. Ruta de código diferente por dispositivo. Sin personalización del lado del servidor. Y bypassa completamente SSAI, lo que significa CPMs más bajos.
- "Simplemente emitir un SpliceInsert por pausa." El error de producción más común. Funciona en algunos reproductores, pero es ignorado silenciosamente por los sistemas SSAI que requieren señales TimeSignal para emparejar inicio/fin. Monetización parcial, sin errores que investigar.
- "Expresar todo en ticks de 90 kHz porque la especificación los menciona." La especificación es más molesta que eso. SpliceInsert.Duration está en segundos. SegmentationDuration está en ticks de 90 kHz. Mezclarlos produce señales que pasan la validación de esquema y se envían, para luego fallar en el reproductor como duraciones mal formadas. El codificador no lo detectará. El reproductor simplemente omite la pausa.
- "Permitir que MediaLive confirme." No lo hará. MediaLive acepta pausas superpuestas, pausas de duración cero y duraciones de segmentación imposibles sin quejarse. La confirmación debe producirse antes de que MediaLive vea la acción.
La palanca que teníamos era el límite entre la UI del operador — donde las pausas publicitarias son solo pares {position, duration} — y la programación de MediaLive, donde cada señal tiene que ser perfecta.
Nuestra Solución
Tratar la pausa publicitaria como un objeto de datos de primera clase de principio a fin. El operador la define en los términos más simples posibles. El backend la valida una vez en la capa de esquema. La Lambda la traduce en un stack de tres señales en el momento del despliegue, con cada señal expresada en la base de tiempo que exige su propia especificación. Ninguna otra parte del stack tiene que saber sobre SCTE-35; la traducción reside en una única función, en la misma Lambda que posee todas las demás acciones de programación.
Diagrama 1 · Pipeline de Marcadores de Anuncios de Extremo a Extremo

Arquitectura
- Editor de pausas publicitarias frontend — los operadores añaden pausas publicitarias por programa especificando un desplazamiento de posición (segundos desde el inicio del programa) y una duración (segundos). Los slots de bumpers son parte del modelo de datos y están listos para la capa de reproducción.
- Colección AdMarker (MongoDB) — un documento por programa con pausas publicitarias, referenciando el video. El array adBreaks[] almacena {position, duration} con Mongoose aplicando 10 ≤ duration ≤ 120 en el momento de guardar. Los bumpers llevan una referencia adBreakId para el emparejamiento downstream.
- Backend NestJS (schedule.service.ts) — en el momento del despliegue, une cada programa a su AdMarker y renombra los campos al contrato de la Lambda (position → offsetSeconds, duration → durationSeconds). Una única consulta masiva, sin N+1.
- Orquestador Lambda (fastChannel-lambda-fun/index.js) — gestiona la traducción SCTE-35. Para cada pausa publicitaria, emite el stack de tres señales en el mismo BatchUpdateScheduleCommand que lleva los cambios de entrada y las marcas de agua. Los nombres de las acciones se versionan por programa para que el barrido de huérfanos pueda emparejarlas después de un despliegue parcial.
- AWS MediaLive — recibe las acciones, emite marcadores #EXT-SCTE35 en el manifiesto HLS en el segundo elegido por el operador.
Decisiones clave de ingeniería
1. Tres señales por pausa publicitaria, no una
Cada pausa publicitaria emite tres acciones discretas para el mismo momento lógico en el programa.
Diagrama 2 · Ciclo de Vida de una Única Pausa Publicitaria

Las señales de inicio y fin TimeSignal comparten un SegmentationUpid para que los sistemas downstream puedan emparejarlas de forma determinista. El SpliceInsert lleva un SpliceEventId único para la deduplicación a nivel de reproductor. Diferentes consumidores leen diferentes señales. La emisión de las tres cubre cada contrato que nos importa hoy y cada uno plausible mañana.
Error de producción común. Emitir un SpliceInsert y asumir que el resto del ecosistema lo resolverá. Los sistemas SSAI descartan silenciosamente las pausas que carecen de señales TimeSignal coincidentes; los ad servers clásicos ignoran las señales solo TimeSignal. Sin las tres, cada pausa publicitaria es monetizada por algunos de tus sistemas downstream y perdida por el resto —y te enteras por el informe de ingresos, no por los logs.
2. Dos bases de tiempo, conciliadas en una función
SpliceInsert.Duration está en segundos. SegmentationDuration dentro de un descriptor TimeSignal está en unidades de 90,000 ticks. Misma duración lógica, dos codificaciones — y el error SCTE-35 más común en la práctica es confundirlas.
Diagrama 3 · Lógica de Conversión de Tiempo

La conversión reside en buildProgramActions y solo allí. Hay un lugar canónico donde buscar cuando la duración de una señal es incorrecta, y un lugar donde cambiar si la especificación evoluciona.
Compromiso que hicimos intencionalmente. Podríamos haber almacenado ambas bases de tiempo en el documento AdMarker y dejar que la Lambda las copiara. Deliberadamente no lo hicimos: almacenar solo el valor en segundos significa que solo hay un número que el operador debe establecer, solo un número que validar y solo un número que puede ser incorrecto. El valor de 90 kHz es derivado, nunca almacenado. Los datos derivados no pueden desviarse.
3. La posición es relativa, el tiempo de activación es absoluto
El operador dice "pausa publicitaria a los 720 segundos del programa." La Lambda calcula el tiempo de activación UTC real como programStartTime + offsetSeconds × 1000 y lo marca en la acción. Todas las demás acciones de programación —cambio de entrada, marca de agua activada, fin de programa— utilizan la misma pipeline de offset a timestamp. Las señales de anuncios aterrizan en los mismos límites de fotograma que todo lo demás, sin ambigüedad sobre qué reloj posee la línea de tiempo.
4. Validación en la capa de datos, no en el flujo
El esquema AdMarker aplica duration ∈ [10, 120] segundos en el momento de guardar con Mongoose. Una pausa fuera de rango nunca llega a la Lambda. Las pausas publicitarias que se extenderían más allá del final del programa se recortan en el momento de la construcción en lugar de ser rechazadas —los operadores no pierden su trabajo por una sola pausa defectuosa. Las clases de errores que no pueden ocurrir son más interesantes que las que sí pueden.
5. Emisión de señales desacoplada de SSAI
Lo que entregamos hoy es la capa de señalización. La inserción de anuncios del lado del servidor a través de AWS MediaTailor —que consumiría estas señales para insertar creatividades publicitarias reales en el manifiesto HLS— está completamente diseñada pero aún no está conectada. El orden deliberado: obtener la capa de señales correcta primero, en producción, utilizada por canales reales, antes de activar SSAI. Cuando la integración entre en funcionamiento, las señales ya estarán allí. El sistema downstream obtiene un contrato limpio para consumir desde el primer día.
Por qué este orden importa. La depuración de SSAI es brutal cuando tus señales son incorrectas, porque cada fallo parece un fallo de SSAI incluso cuando las señales son las culpables. Al entregar la capa de señales de forma aislada primero y validarla contra reproductores y ad servers reales, eliminamos toda una categoría de confusión de integración antes de que pudiera ocurrir.
Resultados
- Cada pausa publicitaria que define un operador emite un stack SCTE-35 de tres señales conforme a los estándares en el manifiesto HLS del canal — en el segundo correcto, contra la base de tiempo correcta.
- La capa de traducción reside en una función. Los cambios en la especificación o los nuevos consumidores downstream son un cambio de un solo archivo, no una búsqueda en todo el código base.
- La validación de la duración se ejecuta en la capa de datos, antes de que cualquier señal llegue al codificador. Los errores del operador aparecen en la UI, no silenciosamente en el momento de la emisión — las señales mal formadas no pueden llegar a MediaLive.
- La generación de señales es determinista: una entrada idéntica del operador produce acciones SCTE-35 idénticas, por lo que la misma pausa se comporta de la misma manera en cada despliegue y en cada canal.
- La capa de señalización está implementada y en vivo. El consumidor de SSAI (MediaTailor) está diseñado y listo para ser conectado — y cuando lo esté, las señales de cada canal existente ya estarán allí esperándolo.
Pila Tecnológica: AWS MediaLive · AWS Lambda · NestJS · MongoDB · TypeScript · Node 18 · SCTE-35 (Scte35TimeSignalSettings, Scte35SpliceInsertSettings) · AWS SDK v3

