Pubblicazione e sottoscrizione con l'SDK di trasmissione Web IVS | Streaming in tempo reale - Amazon IVS

Pubblicazione e sottoscrizione con l'SDK di trasmissione Web IVS | Streaming in tempo reale

Questo documento illustra i passaggi necessari per pubblicare e sottoscrivere una fase utilizzando l'SDK di trasmissione web IVS per lo streaming in tempo reale.

Concetti

La funzionalità in tempo reale si basa su tre concetti fondamentali: fase, strategia ed eventi. L'obiettivo di progettazione è ridurre al minimo la quantità di logica lato client necessaria per creare un prodotto funzionante.

Stage

La classe Stage è il principale punto di interazione tra l'applicazione host e l'SDK. Rappresenta lo stage stesso e serve per entrare e uscire dallo stage. La creazione e la partecipazione a uno stage richiedono una stringa di token valida e non scaduta dal piano di controllo (control-plane) (rappresentata come token). Entrare e uscire da uno stage è semplice:

const stage = new Stage(token, strategy) try { await stage.join(); } catch (error) { // handle join exception } stage.leave();

Strategia

L'interfaccia StageStrategy consente all'applicazione host di comunicare lo stato desiderato dello stage all'SDK. È necessario implementare tre funzioni: shouldSubscribeToParticipant, shouldPublishParticipant e stageStreamsToPublish. Sono tutte analizzate di seguito.

Per utilizzare una strategia definita, passala al costruttore Stage. Quello che segue è un esempio completo di applicazione che utilizza una strategia per pubblicare la webcam di un partecipante sullo stage ed eseguire la sottoscrizione a tutti i partecipanti. Lo scopo di ciascuna funzione strategica necessaria è spiegato in modo dettagliato nelle sezioni seguenti.

const devices = await navigator.mediaDevices.getUserMedia({ audio: true, video: { width: { max: 1280 }, height: { max: 720 }, } }); const myAudioTrack = new LocalStageStream(devices.getAudioTracks()[0]); const myVideoTrack = new LocalStageStream(devices.getVideoTracks()[0]); // Define the stage strategy, implementing required functions const strategy = { audioTrack: myAudioTrack, videoTrack: myVideoTrack, // optional updateTracks(newAudioTrack, newVideoTrack) { this.audioTrack = newAudioTrack; this.videoTrack = newVideoTrack; }, // required stageStreamsToPublish() { return [this.audioTrack, this.videoTrack]; }, // required shouldPublishParticipant(participant) { return true; }, // required shouldSubscribeToParticipant(participant) { return SubscribeType.AUDIO_VIDEO; } }; // Initialize the stage and start publishing const stage = new Stage(token, strategy); await stage.join(); // To update later (e.g. in an onClick event handler) strategy.updateTracks(myNewAudioTrack, myNewVideoTrack); stage.refreshStrategy();

Sottoscrizione ai partecipanti

shouldSubscribeToParticipant(participant: StageParticipantInfo): SubscribeType

Quando un partecipante remoto partecipa allo stage, l'SDK interroga l'applicazione host sullo stato della sottoscrizione desiderato per quel partecipante. Le opzioni sono NONE, AUDIO_ONLY e AUDIO_VIDEO. Quando si restituisce un valore per questa funzione, l'applicazione host non deve preoccuparsi dello stato di pubblicazione, dello stato della sottoscrizione corrente o dello stato della connessione allo stage. Se viene restituito AUDIO_VIDEO, l'SDK attende che il partecipante remoto effettui la pubblicazione prima della sottoscrizione e aggiorna l'applicazione host emettendo eventi durante tutto il processo.

Di seguito è riportata un'implementazione di esempio:

const strategy = { shouldSubscribeToParticipant: (participant) => { return SubscribeType.AUDIO_VIDEO; } // ... other strategy functions }

Questa è l'implementazione completa di questa funzione per un'applicazione host che vuole sempre che tutti i partecipanti si vedano tra loro, ad esempio un'applicazione di chat video.

Sono possibili anche implementazioni più avanzate. Ad esempio, supponiamo che l'applicazione fornisca un attributo role durante la creazione del token con CreateParticipantToken. L'applicazione può utilizzare la proprietà attributes su StageParticipantInfo per abbonarsi selettivamente ai partecipanti in base agli attributi forniti dal server:

const strategy = { shouldSubscribeToParticipant(participant) { switch (participant.attributes.role) { case 'moderator': return SubscribeType.NONE; case 'guest': return SubscribeType.AUDIO_VIDEO; default: return SubscribeType.NONE; } } // . . . other strategies properties }

Questa può essere usata per creare uno stage in cui i moderatori possano monitorare tutti gli ospiti senza essere visti o ascoltati. L'applicazione host potrebbe utilizzare una logica aziendale aggiuntiva per consentire ai moderatori di vedersi ma rimanendo invisibili agli ospiti.

Configurazione dell'abbonamento ai partecipanti

subscribeConfiguration(participant: StageParticipantInfo): SubscribeConfiguration

Se un partecipante moto viene abbonato (consulta la sezione Abbonamento ai partecipanti), l'SDK interroga l'applicazione host su una configurazione di abbonamento personalizzata per tale partecipante. Questa configurazione è facoltativa e consente all'applicazione host di controllare determinati aspetti del comportamento dell'abbonato. Per informazioni sui valori che è possibile configurare, consulta la sezione SubscribeConfiguration nella documentazione di riferimento dell'SDK.

Di seguito è riportata un'implementazione di esempio:

const strategy = { subscribeConfiguration: (participant) => { return { jitterBuffer: { minDelay: JitterBufferMinDelay.MEDIUM } } // ... other strategy functions }

Questa implementazione aggiorna il ritardo minimo del jitter-buffer per tutti i partecipanti abbonati a un valore predefinito di MEDIUM.

Come per shouldSubscribeToParticipant, sono possibili anche implementazioni più avanzate. Il valore ParticipantInfo dato può essere utilizzato per aggiornare selettivamente la configurazione di abbonamento per partecipanti specifici.

Consigliamo di utilizzare i valori predefiniti. Specifica la configurazione personalizzata solo se desideri modificare un comportamento particolare.

Pubblicazione

shouldPublishParticipant(participant: StageParticipantInfo): boolean

Una volta connesso allo stage, l'SDK interroga l'applicazione host per vedere se un dato partecipante deve eseguire una pubblicazione. Viene richiamata solo per i partecipanti locali che hanno il permesso di pubblicare in base al token fornito.

Di seguito è riportata un'implementazione di esempio:

const strategy = { shouldPublishParticipant: (participant) => { return true; } // . . . other strategies properties }

Si tratta di un'applicazione di chat video standard in cui gli utenti vogliono sempre pubblicare. Possono disattivare e riattivare l'audio e il video per essere nascosti o visti/ascoltati immediatamente. Possono anche usare il comando di pubblicazione/annullamento della pubblicazione, ma è molto più lento. È preferibile disattivare/riattivare l'audio nei casi d'uso in cui è consigliabile modificare spesso la visibilità.

Scelta dei flussi da pubblicare

stageStreamsToPublish(): LocalStageStream[];

Durante la pubblicazione, serve a determinare quali flussi audio e video devono essere pubblicati. Questo argomento verrà trattato dettagliatamente più avanti in Pubblicazione di un flusso multimediale.

Aggiornamento della strategia

La strategia è pensata per essere dinamica: è possibile modificare i valori restituiti da una qualsiasi delle funzioni precedenti in qualsiasi momento. Ad esempio, se l'applicazione host non desidera pubblicare finché l'utente finale non tocca un pulsante, è possibile restituire una variabile da shouldPublishParticipant (del tipo hasUserTappedPublishButton). Quando quella variabile cambia in base a un'interazione da parte dell'utente finale, chiama stage.refreshStrategy() per segnalare all'SDK che dovrebbe eseguire una query sulla strategia per i valori più recenti, applicando solo quanto modificato. Se l'SDK rileva che il valore shouldPublishParticipant è cambiato, avvia il processo di pubblicazione. Se le query dell'SDK e tutte le funzioni restituiscono lo stesso valore di prima, la chiamata refreshStrategy non modifica lo stage.

Se il valore restituito di shouldSubscribeToParticipant cambia da AUDIO_VIDEO a AUDIO_ONLY, il flusso video viene rimosso per tutti i partecipanti con valori restituiti modificati, se in precedenza esisteva un flusso video.

In genere, lo stage utilizza la strategia per applicare in modo più efficiente la differenza tra le strategie precedenti e quelle attuali, senza che l'applicazione host debba preoccuparsi di tutto lo stato necessario per gestirla correttamente. Per questo motivo, considera la chiamata a stage.refreshStrategy() come un'operazione a basso costo, perché non viene eseguita a meno che la strategia non cambi.

Eventi

Un'istanza Stage è un emettitore di eventi. Usando stage.on(), lo stato dello stage viene comunicato all'applicazione host. Gli aggiornamenti all'interfaccia utente dell'applicazione host in genere possono essere supportati interamente dagli eventi. Gli eventi sono i seguenti:

stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participant, state) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participant, state) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED, (participant, streams) => {}) stage.on(StageEvents.STAGE_STREAM_ADAPTION_CHANGED, (participant, stream, isAdapting) => ()) stage.on(StageEvents.STAGE_STREAM_LAYERS_CHANGED, (participant, stream, layers) => ()) stage.on(StageEvents.STAGE_STREAM_LAYER_SELECTED, (participant, stream, layer, reason) => ()) stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {}) stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, stream) => {})

Per la maggior parte di questi metodi, viene fornito il ParticipantInfo corrispondente.

Non è previsto che le informazioni fornite dagli eventi influiscano sui valori restituiti della strategia. Ad esempio, non è previsto che il valore restituito di shouldSubscribeToParticipant cambi quando viene chiamato STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED. Se l'applicazione host desidera effettuare la sottoscrizione a un particolare partecipante, deve restituire il tipo di abbonamento desiderato indipendentemente dallo stato di pubblicazione di quel partecipante. L'SDK è responsabile di garantire che lo stato desiderato della strategia venga applicato al momento giusto in base allo stato dello stage.

Pubblicazione di un flusso multimediale

I dispositivi locali come microfoni e fotocamere vengono recuperati utilizzando gli stessi passaggi descritti sopra in Recupero di un MediaStream da un dispositivo. Nell'esempio utilizziamo MediaStream per creare un elenco di oggetti LocalStageStream utilizzati per la pubblicazione dall'SDK:

try { // Get stream using steps outlined in document above const stream = await getMediaStreamFromDevice(); let streamsToPublish = stream.getTracks().map(track => { new LocalStageStream(track) }); // Create stage with strategy, or update existing strategy const strategy = { stageStreamsToPublish: () => streamsToPublish } }

Pubblicazione di una condivisione dello schermo

Spesso le applicazioni devono pubblicare una condivisione dello schermo in aggiunta alla webcam dell'utente. La pubblicazione di una condivisione dello schermo richiede la creazione di un token aggiuntivo per la fase, in particolare per la pubblicazione dei contenuti multimediali della condivisione dello schermo. Utilizza getDisplayMedia e limita la risoluzione a un massimo di 720p. Dopodiché, i passaggi sono simili a quelli per la pubblicazione di una videocamera sulla fase.

// Invoke the following lines to get the screenshare's tracks const media = await navigator.mediaDevices.getDisplayMedia({ video: { width: { max: 1280, }, height: { max: 720, } } }); const screenshare = { videoStream: new LocalStageStream(media.getVideoTracks()[0]) }; const screenshareStrategy = { stageStreamsToPublish: () => { return [screenshare.videoStream]; }, shouldPublishParticipant: (participant) => { return true; }, shouldSubscribeToParticipant: (participant) => { return SubscribeType.AUDIO_VIDEO; } } const screenshareStage = new Stage(screenshareToken, screenshareStrategy); await screenshareStage.join();

Visualizzazione e rimozione dei partecipanti

Una volta completata la sottoscrizione, riceverai una serie di oggetti StageStream tramite l'evento STAGE_PARTICIPANT_STREAMS_ADDED. L'evento fornisce anche informazioni sui partecipanti per aiutarti a visualizzare i flussi multimediali:

stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { const streamsToDisplay = streams; if (participant.isLocal) { // Ensure to exclude local audio streams, otherwise echo will occur streamsToDisplay = streams.filter(stream => stream.streamType === StreamType.VIDEO) } // Create or find video element already available in your application const videoEl = getParticipantVideoElement(participant.id); // Attach the participants streams videoEl.srcObject = new MediaStream(); streamsToDisplay.forEach(stream => videoEl.srcObject.addTrack(stream.mediaStreamTrack)); })

Quando un partecipante interrompe la pubblicazione o annulla l'iscrizione a un flusso, la funzione STAGE_PARTICIPANT_STREAMS_REMOVED viene chiamata con i flussi che sono stati rimossi. Le applicazioni host devono utilizzarlo come segnale per rimuovere il flusso video del partecipante dal DOM.

STAGE_PARTICIPANT_STREAMS_REMOVED viene richiamato per tutti gli scenari in cui un flusso potrebbe essere rimosso, tra cui:

  • Il partecipante remoto interrompe la pubblicazione.

  • Un dispositivo locale annulla l'iscrizione o modifica l'abbonamento da AUDIO_VIDEO a AUDIO_ONLY.

  • Il partecipante remoto lascia lo stage.

  • Il partecipante locale lascia lo stage.

Poiché STAGE_PARTICIPANT_STREAMS_REMOVED viene richiamato per tutti gli scenari, non è richiesta alcuna logica aziendale personalizzata per la rimozione dei partecipanti dall'interfaccia utente durante le operazioni di abbandono remote o locali.

Disattivazione e riattivazione dell'audio dei flussi multimediali

Gli oggetti LocalStageStream hanno una funzione setMuted che controlla se l'audio del flusso è disattivato. Questa funzione può essere richiamata sul flusso prima o dopo la restituzione dalla funzione della strategia stageStreamsToPublish.

Importante: se una nuova istanza di oggetto LocalStageStream viene restituita da stageStreamsToPublish dopo una chiamata a refreshStrategy, lo stato di silenziamento del nuovo oggetto di flusso viene applicato allo stage. Fai attenzione quando crei nuove istanze LocalStageStream per assicurarti che lo stato di silenziamento previsto venga mantenuto.

Monitoraggio dello stato di silenziamento dei contenuti multimediali dei partecipanti remoti

Quando i partecipanti modificano lo stato di silenziamento del video o dell'audio, l'evento STAGE_STREAM_MUTE_CHANGED viene attivato con un elenco di flussi che sono stati modificati. Usa la proprietà isMuted su StageStream per aggiornare l'interfaccia utente di conseguenza:

stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => { if (stream.streamType === 'video' && stream.isMuted) { // handle UI changes for video track getting muted } })

Inoltre, puoi consultare StageParticipantInfo per informazioni sullo stato dell'eventuale disattivazione dell'audio o del video:

stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => { if (participant.videoStopped || participant.audioMuted) { // handle UI changes for either video or audio } })

Ottenimento delle statistiche WebRTC

Per ottenere le statistiche WebRTC più recenti per un flusso di pubblicazione o un flusso di iscrizione, usa getStats su StageStream. Si tratta di un metodo asincrono con il quale è possibile recuperare le statistiche tramite attesa o concatenando una promessa. Il risultato è un RTCStatsReport, ovvero un dizionario contenente tutte le statistiche standard.

try { const stats = await stream.getStats(); } catch (error) { // Unable to retrieve stats }

Ottimizzazione dei contenuti multimediali

Si consiglia di limitare le chiamate getUserMedia e getDisplayMedia secondo i seguenti vincoli per ottenere prestazioni ottimali:

const CONSTRAINTS = { video: { width: { ideal: 1280 }, // Note: flip width and height values if portrait is desired height: { ideal: 720 }, framerate: { ideal: 30 }, }, };

È possibile limitare ulteriormente i contenuti multimediali tramite opzioni aggiuntive passate al costruttore LocalStageStream:

const localStreamOptions = { minBitrate?: number; maxBitrate?: number; maxFramerate?: number; simulcast: { enabled: boolean } } const localStream = new LocalStageStream(track, localStreamOptions)

Nel codice qui sopra:

  • minBitrate imposta un bitrate minimo che dovrebbe essere utilizzato dal browser. Tuttavia, un flusso video a bassa complessità può spingere il codificatore a scendere al di sotto di questo bitrate.

  • maxBitrate imposta un bitrate massimo che il browser non dovrebbe superare per questo flusso.

  • maxFramerate imposta una frequenza di rate massima che il browser non dovrebbe superare per questo flusso.

  • L'opzione simulcast può essere utilizzata solo sui browser basati su Chromium. Consente l'invio di tre livelli di rendering del flusso.

    • Ciò consente al server di scegliere quale rendering inviare agli altri partecipanti in base alle loro limitazioni di rete.

    • Quando simulcast viene specificato insieme a un valore di maxBitrate e/o maxFramerate, si prevede che il livello di rendering più alto venga configurato tenendo conto di questi valori, a condizione che maxBitrate non scenda al di sotto del valore predefinito interno maxBitrate del secondo livello più alto dell'SDK di 900 kbps.

    • Se viene specificato un valore troppo basso di maxBitrate rispetto al valore predefinito del secondo livello più alto, simulcast sarà disabilitato.

    • simulcast non può essere attivato e disattivato senza ripubblicare il file multimediale tramite una sequenza in cui shouldPublishParticipant restituisce false, richiama refreshStrategy, shouldPublishParticipant restituisce true e richiama di nuovo refreshStrategy.

Ottieni gli attributi dei partecipanti

Se specifichi gli attributi nella richiesta dell'operazione CreateParticipantToken, puoi visualizzare gli attributi nelle proprietà StageParticipantInfo:

stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => { console.log(`Participant ${participant.id} info:`, participant.attributes); })

Supplemental Enhancement Information (SEI)

L'unità NAL Supplemental Enhancement Information (SEI) viene utilizzata per archiviare i metadati allineati al fotogramma insieme al video. È utilizzabile per la pubblicazione e l'abbonamento a flussi video H.264. Non è garantito che i payload SEI arrivino agli abbonati, specialmente in condizioni di rete non ottimali.

Inserimento di payload SEI

I client di pubblicazione possono inserire payload SEI in un flusso di fase in corso di pubblicazione configurando il LocalStageStream del proprio video in modo da abilitare inBandMessaging e, successivamente, richiamando il metodo insertSeiMessage.

I payload devono essere del tipo ArrayBuffer. La dimensione del payload deve essere maggiore di 0 KB e inferiore a 1 KB. Il numero di messaggi SEI inseriti al secondo non deve superare i 10 KB al secondo.

const config = { inBandMessaging: { enabled: true } }; const vidStream = new LocalStageStream(videoTrack, config); const payload = new TextEncoder().encode('hello world').buffer; vidStream.insertSeiMessage(payload);

Ripetizione dei payload SEI

È possibile fornire un repeatCount per ripetere l'inserimento dei payload SEI per i N frame successivi inviati, il che potrebbe essere utile per mitigare la perdita intrinseca che può verificarsi a causa del protocollo di trasporto UDP sottostante utilizzato per inviare video. Il valore deve essere compreso tra 0 e 30. I client di ricezione devono disporre di una logica per deduplicare il messaggio.

vidStream.insertSeiMessage(payload, { repeatCount: 5 }); // Optional config, repeatCount must be between 0 and 30

Leggere i payload SEI

I clienti abbonati possono leggere i payload SEI di un publisher che pubblica video H.264, se presente, configurando l'elemento SubscribeConfiguration degli abbonati per attivare inBandMessaging e ascoltare l'evento StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, come illustrato nell'esempio seguente:

const strategy = { subscribeConfiguration: (participant) => { return { inBandMessaging: { enabled: true } } } // ... other strategy functions } stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, seiMessage) => { console.log(seiMessage.payload, seiMessage.uuid); });

Codifica a livelli con Simulcast

La codifica a livelli con simulcast è una funzionalità di streaming in tempo reale IVS che consente ai publisher di inviare più livelli di qualità video differenti e agli abbonati di modificare dinamicamente o manualmente tali livelli. La funzionalità è descritta più approfonditamente nel documento Ottimizzazioni dello streaming.

Configurazione della codifica a livelli (Publisher)

Per abilitare la codifica a più livelli con simulcast, il publisher deve aggiungere la seguente configurazione a LocalStageStream all’istanziazione:

// Enable Simulcast let cameraStream = new LocalStageStream(cameraDevice, { simulcast: { enabled: true } })

A seconda della risoluzione di input del dispositivo videocamera, verrà codificato e inviato un determinato numero di livelli come definito nella sezione Livelli, qualità e framerate predefiniti di Ottimizzazioni dello streaming.

Configurazione della codifica a livelli (Abbonato)

L’abbonato non deve eseguire alcuna operazione per abilitare la codifica a livelli. Se un publisher invia layer simulcast, per impostazione predefinita il server si adatta dinamicamente tra i livelli per scegliere la qualità ottimale in base al dispositivo e alle condizioni di rete dell'abbonato.

In alternativa, per scegliere layer espliciti inviati dal publisher, sono disponibili diverse opzioni, descritte di seguito.

Opzione 1: preferenza di qualità del livello iniziale

Usando la strategia subscribeConfiguration, è possibile scegliere quale livello iniziale si desidera ricevere come abbonato:

const strategy = { subscribeConfiguration: (participant) => { return { simulcast: { initialLayerPreference: InitialLayerPreference.LOWEST_QUALITY } } } // ... other strategy functions }

Per impostazione predefinita, agli abbonati viene sempre inviato per primo il livello di qualità più bassa; questo livello passa lentamente al livello di qualità più alta. Ciò ottimizza il consumo di larghezza di banda da parte dell'utente finale e offre il tempo ottimale per i video, riducendo i blocchi iniziali del video per gli utenti su reti più deboli.

Queste opzioni sono disponibili per InitialLayerPreference:

  • LOWEST_QUALITY — Il server fornisce prima il livello video con la qualità più bassa. In questo modo, si ottimizza il consumo di larghezza di banda e il tempo di accesso ai contenuti multimediali. La qualità è definita come combinazione di dimensioni, bitrate e framerate del video. Ad esempio, un video 720p ha una qualità inferiore rispetto a un video 1080p.

  • HIGHEST_QUALITY — Il server offre prima il livello video con la qualità più alta. Ciò ottimizza la qualità ma può aumentare il tempo di visualizzazione dei contenuti multimediali. La qualità è definita come combinazione di dimensioni, bitrate e framerate del video. Ad esempio, un video 1080p è di qualità superiore rispetto a un video 720p.

Opzione 2: livello preferito per lo streaming

Una volta avviato un flusso, puoi utilizzare il metodo strategico preferredLayerForStream . Questo metodo strategico espone il partecipante e le informazioni sul flusso.

Il metodo strategico può essere restituito con quanto segue:

  • L'oggetto del livello direttamente in base a ciò che RemoteStageStream.getLayers restituisce

  • La stringa dell'etichetta dell'oggetto del livello, basata su StageStreamLayer.label

  • Non definito o nullo, indicante che non deve essere selezionato alcun livello e che è preferibile l'adattamento dinamico

Ad esempio, la strategia seguente prevede che gli utenti selezionino sempre il livello di video con la qualità più bassa disponibile:

const strategy = { preferredLayerForStream: (participant, stream) => { return stream.getLowestQualityLayer(); } // ... other strategy functions }

Per reimpostare la selezione del livello e tornare all'adattamento dinamico, restituire null o non definito nella strategia. In questo esempio appState è una variabile fittizia che rappresenta il possibile stato dell'applicazione.

const strategy = { preferredLayerForStream: (participant, stream) => { if (appState.isAutoMode) { return null; } else { return appState.layerChoice } } // ... other strategy functions }

Opzione 3: helper per livelli RemoteStageStream

RemoteStageStream dispone di diversi helper che possono essere usati per prendere decisioni sulla selezione dei livelli e visualizzare le selezioni corrispondenti agli utenti finali:

  • Eventi dei livelli: oltre a StageEvents, l’oggetto RemoteStageStream include eventi che comunicano modifiche di adattamento di livelli e simulcast:

    • stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})

    • stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})

    • stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer) => {})

  • Metodi dei livelli: RemoteStageStream include diversi metodi helper che possono essere usati per ottenere informazioni sul flusso e sui livelli presentati. Questi metodi sono disponibili sul flusso remoto fornito nella strategia preferredLayerForStream , nonché sui flussi remoti esposti tramite StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED.

    • stream.getLayers

    • stream.getSelectedLayer

    • stream.getLowestQualityLayer

    • stream.getHighestQualityLayer

Per i dettagli, consulta la classe RemoteStageStream nella Documentazione di riferimento dell'SDK.

Gestione dei problemi di rete

Quando si perde la connessione di rete del dispositivo locale, l'SDK tenta internamente di riconnettersi senza alcuna azione da parte dell'utente. In alcuni casi, l'SDK non funziona ed è necessaria un'azione da parte dell'utente.

In generale, lo stato dello stage può essere gestito tramite l'evento STAGE_CONNECTION_STATE_CHANGED:

stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => { switch (state) { case StageConnectionState.DISCONNECTED: // handle disconnected UI break; case StageConnectionState.CONNECTING: // handle establishing connection UI break; case StageConnectionState.CONNECTED: // SDK is connected to the Stage break; case StageConnectionState.ERRORED: // SDK encountered an error and lost its connection to the stage. Wait for CONNECTED. break; })

In generale, è possibile ignorare uno stato di errore che si verifica dopo essersi aggiunti correttamente in una fase, poiché l'SDK tenterà di ripristinarlo internamente. Se l'SDK riporta uno stato ERRORED e la fase rimane nello stato CONNECTING per un periodo di tempo prolungato (ad esempio, 30 secondi o più), probabilmente è avvenuta la disconnessione dalla rete.

Trasmissione della fase a un canale IVS

Per trasmettere uno stage, creare una sessione IVSBroadcastClient separata e segui le consuete istruzioni per la trasmissione con l'SDK descritte sopra. L'elenco dei StageStream esposti tramite STAGE_PARTICIPANT_STREAMS_ADDED può essere utilizzato per recuperare i flussi multimediali dei partecipanti che possono essere applicati alla composizione del flusso di trasmissione, come segue:

// Setup client with preferred settings const broadcastClient = getIvsBroadcastClient(); stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { streams.forEach(stream => { const inputStream = new MediaStream([stream.mediaStreamTrack]); switch (stream.streamType) { case StreamType.VIDEO: broadcastClient.addVideoInputDevice(inputStream, `video-${participant.id}`, { index: DESIRED_LAYER, width: MAX_WIDTH, height: MAX_HEIGHT }); break; case StreamType.AUDIO: broadcastClient.addAudioInputDevice(inputStream, `audio-${participant.id}`); break; } }) })

Facoltativamente, puoi comporre una fase e trasmetterla a un canale IVS a bassa latenza in modo da raggiungere un pubblico più vasto. Consulta Abilitazione di più host su un flusso Amazon IVS nella Guida per l'utente dello streaming a bassa latenza di IVS.