You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/decisions/design-media-quality.md

5.2 KiB

Diseño — la calidad de reproducción en el MediaPlayer

Estado: ESPECIFICADO, NO IMPLEMENTADO. Fecha: 2026-08-04. Decisión del usuario: escribir el contrato antes de tocar código.

Este documento existe porque la parte settings-button del morfo lleva declarada desde el principio prometiendo «velocidad / calidad / pista», y al ir a implementarla se descubrió que dos de los tres ejes ya no le corresponden y el tercero no existe. Aquí queda por qué, y qué haría falta exactamente para que existiera.

1. El hallazgo: la calidad no está en ninguna parte

Auditado el 2026-08-04 sobre el código, no sobre la memoria:

Superficie Campos de calidad
MediaSnapshot (soma/components/media-player/media-provider.ts) 0 de 14
MediaProvider (mismo fichero) 0 de 9 miembros
SoundMediaSnapshot / SoundMediaHandle (arts/sound/types.ts) 0, espejo exacto

Grep de quality|bitrate|resolution|level|representation sobre el puerto: cero coincidencias. No es que esté a medias — es que el concepto no ha entrado nunca.

2. Por qué no es un descuido

La calidad no es intrínseca al <video>. Un <video src="pelicula.mp4"> no tiene niveles: tiene un fichero. Los niveles aparecen cuando hay un manifiesto (HLS o MPEG-DASH) y un motor que elige representación según ancho de banda.

Y este framework no vendoriza motores (regla de dependencia cero): hls.js o dash.js los enchufa el consumidor por createProvider. Así que la lista de calidades sólo puede venir del consumidor, nunca del componente.

Consecuencia: cualquier contrato de calidad que se escriba será, para el 90 % de los usos, una lista vacía. Eso no lo invalida, pero sí decide la forma — el control tiene que desaparecer, no salir vacío.

3. El contrato mínimo, si se abre

Nada especulativo: sólo lo que hace falta para poblar una lista y elegir.

3.1 MediaSnapshot — tres campos

/** Una representación que el motor ofrece. `id` es opaco: lo acuña el motor. */
interface MediaQuality {
	id: string;
	height?: number;
	bitrate?: number;
	/** Etiqueta ya legible («1080p»); si falta, la pinta el chrome desde height. */
	label?: string;
}

qualities: readonly MediaQuality[];   // vacío = el medio no tiene niveles
qualityId: string | null;             // la EFECTIVA ahora mismo; null = desconocida
qualityAuto: boolean;                 // true = manda el motor (ABR)

qualityId y qualityAuto son dos cosas distintas a propósito: en modo automático el motor sigue reproduciendo alguna representación concreta, y un menú honesto muestra «Auto (1080p)», no «Auto» a secas.

3.2 MediaProvider — un método

/** `null` devuelve el control al motor (auto). */
setQuality(id: string | null): void;

3.3 Los espejos de $arts/sound

SoundMediaSnapshot y SoundMediaHandle repiten la forma del puerto. Extender uno solo deja al otro sin poder rellenarlo, así que van los dos o ninguno.

3.4 El morfo — aquí está el coste real

Fijar una calidad es un valor aplicado: commit.set, igual que commit-set-rate. Eso obliga a:

  • Un evento nuevo, commit-set-quality. Rompe el test que fija los 11 eventos (morfo/components/media-player.test.ts) — es cambio de canon, no de implementación.
  • Decidir su target. No hay parte quality-button; anclaría en settings-button.
  • Una regla en el pack de sema del componente.
  • Textos: quality y auto.

⚠️ Y una trampa que ya nos mordió con la velocidad: el commit debe cabalgar el RESULTADO, no el clic. Pedir 1080p no es haberlo conseguido — el motor puede negarse o tardar. El commit tiene que salir cuando el snapshot refleje el cambio de qualityId, igual que commit-set-rate cabalga ratechange.

4. La forma del control

Cuando qualities esté vacío el control no se pinta. Ni deshabilitado ni vacío: ausente. Es la misma doctrina que el waveform sin picos — sin datos no se inventa una forma. Un menú de ajustes con una entrada «Calidad ▸ (nada)» miente sobre lo que el reproductor puede hacer.

Con eso, settings-button recupera su razón de ser: dos ejes reales (calidad + pista de subtítulos) cuando hay motor, y ninguno cuando no lo hay.

5. Lo que queda fuera, y por qué

  • Selector de pista de audio. HTMLMediaElement.audioTracks no lo implementan ni Chrome ni Firefox. Saldría vacío en casi todos los navegadores.
  • Duplicar velocidad dentro de ajustes. Tiene su lista propia desde ee51172d8 (RateFloat).
  • Una tecla rápida para abrir ajustes. El provider declara 15 teclas y ninguna es ésta. Añadirla es cambio de contrato, no un detalle.

6. Estado de settings-button mientras tanto

Sigue declarado en el morfo y sin implementar, que es lo honesto: hoy sólo podría contener una sección (la pista de subtítulos) y eso ya lo resuelve <MediaPlayer.CaptionFloat>. Un engranaje con un solo cajón sería el CaptionFloat disfrazado.

Se implementa cuando este documento deje de ser un plan.

Powered by TurnKey Linux.