import 'package:audio_session/audio_session.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/servicios/servicio_audio_session.dart'; class _ObjetivoFake implements ObjetivoAudioInterrumpible { bool intencion = false; bool reproduciendo = false; int pausas = 0; int reanudaciones = 0; final List atenuaciones = []; @override bool get intencionReproducir => intencion; @override bool get estaReproduciendo => reproduciendo; @override Future pausar() async { pausas++; reproduciendo = false; intencion = false; } @override Future reanudar() async { reanudaciones++; reproduciendo = true; intencion = true; } @override Future setAtenuado(bool atenuado) async { atenuaciones.add(atenuado); } } /// S3-R1: audio-session interruptions (phone call, transient loss, duck) and /// becoming-noisy (headphones unplugged) must pause/duck and auto-resume. void main() { test('interrupcion begin/pause pausa y baja la intencion (S3-R1)', () async { final objetivo = _ObjetivoFake() ..reproduciendo = true ..intencion = true; final servicio = ServicioAudioSession(objetivo: objetivo); await servicio.manejarInterrupcion( AudioInterruptionEvent(true, AudioInterruptionType.pause), ); expect(objetivo.pausas, 1); expect( objetivo.intencionReproducir, isFalse, reason: 'el reconnect de S7 no debe pelear con la llamada en curso', ); }); test( 'interrupcion end/shouldResume reanuda la reproduccion (S3-R1)', () async { final objetivo = _ObjetivoFake() ..reproduciendo = true ..intencion = true; final servicio = ServicioAudioSession(objetivo: objetivo); await servicio.manejarInterrupcion( AudioInterruptionEvent(true, AudioInterruptionType.pause), ); await servicio.manejarInterrupcion( AudioInterruptionEvent(false, AudioInterruptionType.pause), ); expect(objetivo.reanudaciones, 1); expect(objetivo.intencionReproducir, isTrue); }, ); test('end sin pausa previa por interrupcion NO reanuda', () async { final objetivo = _ObjetivoFake(); final servicio = ServicioAudioSession(objetivo: objetivo); await servicio.manejarInterrupcion( AudioInterruptionEvent(false, AudioInterruptionType.pause), ); expect( objetivo.reanudaciones, 0, reason: 'si el usuario ya estaba en pausa, el fin de llamada no arranca audio', ); }); test('duck atenua al comenzar y restaura al terminar', () async { final objetivo = _ObjetivoFake() ..reproduciendo = true ..intencion = true; final servicio = ServicioAudioSession(objetivo: objetivo); await servicio.manejarInterrupcion( AudioInterruptionEvent(true, AudioInterruptionType.duck), ); await servicio.manejarInterrupcion( AudioInterruptionEvent(false, AudioInterruptionType.duck), ); expect(objetivo.atenuaciones, [true, false]); expect(objetivo.pausas, 0); }); test('becoming-noisy (auriculares desconectados) pausa (S3-R1)', () async { final objetivo = _ObjetivoFake() ..reproduciendo = true ..intencion = true; final servicio = ServicioAudioSession(objetivo: objetivo); await servicio.manejarDesconexionSalida(); expect(objetivo.pausas, 1); // A later interruption end must NOT resume: unplugging is a hard pause. await servicio.manejarInterrupcion( AudioInterruptionEvent(false, AudioInterruptionType.pause), ); expect(objetivo.reanudaciones, 0); }); }