https://d226lax1qjow5r.cloudfront.net/blog/blogposts/how-to-use-mediastreams-with-vonage-video-api/add-video-elements.png

Comment utiliser mediaStreams avec l'API Video de Vonage

Publié le April 24, 2024

Temps de lecture : 4 minutes

L'API Video de Vonage permet aux développeurs d'ajouter facilement la vidéo à leurs Applications. Si vous n'avez pas de besoins très spécifiques pour votre application de vidéoconférence ou si vous n'avez pas besoin d'un contrôle de bas niveau sur les éléments vidéo, vous pouvez utiliser l'interface utilisateur par défaut fournie par l'API Video de Vonage, ce qui réduit la complexité pour votre équipe de développement. Cependant, si vous avez l'habitude de travailler avec mediaStreams et de gérer vos éléments vidéo ou parce que cela correspond mieux aux principes de conception de votre application vidéo, nous vous couvrons.

Conditions préalables

  1. Un compte Video API de Vonage. Cliquez sur S'inscrire pour en créer un si vous n'en avez pas déjà un.

  2. Ce billet de blog suppose que vous êtes familier avec l'API Video de Vonage, c'est pourquoi nous nous concentrerons uniquement sur les besoins spécifiques pour publier et s'abonner à vos éléments vidéo.

Éléments vidéo personnalisés

Pour faciliter l'utilisation de l'API Video de Vonage par les développeurs, le Client SDK crée par défaut un élément vidéo que vous pouvez attacher au DOM. Cependant, vous pouvez fournir votre propre élément HTML Video si vous souhaitez un contrôle plus poussé. Pour ce billet de blog, nous ferons référence à cette application React comme exemple de la façon d'accéder au mediaStream et de l'utiliser comme srcObject pour votre élément vidéo personnalisé. N'hésitez pas à la cloner et à l'essayer.

Éditeur

Tout d'abord, dans les propriétés de notre éditeur, nous devons désactiver l'interface utilisateur par défaut, comme nous le mentionnons dans la documentation destinée aux développeurs. nous le mentionnons dans la documentation destinée aux développeurs. La fonction de publication est définie dans le crochet de l'éditeur

//hooks/publisher.jsx 
async function publish(name, extraData) {
    try {
      if (!mSession.session) throw new Error('You are not connected to session');
      const options = {
        insertMode: 'append',
        name: name,
        resolution: '1280x720',
        publishAudio: user.defaultSettings.publishAudio,
        publishVideo: user.defaultSettings.publishVideo,
        audioSource: user.defaultSettings.audioSource,
        videoSource: user.defaultSettings.videoSource,
        insertDefaultUI: false,
        audioFallback: {
          publisher: true,
        },
      };
      const finalOptions = Object.assign({}, options, extraData);
      setPublisherOptions(finalOptions);
      console.log(finalOptions);
      const newPublisher = OT.initPublisher(null, finalOptions);

      publishAttempt(newPublisher, 1);
      publisher.current = newPublisher;
   
    } catch (err) {
      console.log(err.stack);
    }
  }

La logique de publication dans la session est définie dans la fonction publishAttempt. Mais pour plus de simplicité, nous allons coder en dur une seule tentative. Notez que nous ne passons pas d'élément cible à la fonction publish puisque nous voulons accéder au mediaStream sous-jacent et l'utiliser avec notre élément vidéo.

async function publishAttempt(publisher, attempt = 1, noRetry = true) {
    console.log(`Attempting to publish in ${attempt} try`);

    publisher.on('destroyed', handleDestroyed);
    publisher.on('streamDestroyed', handleStreamDestroyed);
  publisher.on('videoElementCreated', handleVideoElementCreated);

    const { retry, error } = await new Promise((resolve, reject) => {
      mSession.session.publish(publisher, (err) => {
        if (err && noRetry) {
          resolve({ retry: undefined, error: err });
        }
        if (err && attempt < 3) {
          resolve({ retry: true, error: err });
        }
        if (err && attempt >= 3) {
          resolve({ retry: false, error: err });
        } else {
          resolve({ retry: false, error: undefined });
        }
      });
    });

    if (retry) {
      // Wait for 2 seconds before attempting to publish again
      await delay(2000 * attempt);
      await publishAttempt(publisher.current, attempt + 1);
    } else if (error) {
      if (noRetry) return;
      alert("Publish error");
      mSession.disconnect();
      setIsPublishing(false);
      publisher.current = null;
    } else {
      setIsPublishing(true);
      publisher.current = publisher;
    }
  }

Nous devons maintenant écouter l'événement videoElementCreated événement qui est envoyé à l'éditeur dans ce cas. Au lieu d'utiliser directement l'élément Video envoyé par l'événement videoElementCreated directement, nous allons accéder à son mediaStream pour l'envoyer à notre propre élément vidéo. Vérifiez l'implémentation du composant CustomPublisher.

//Components/CustomPublisher
import React, { useEffect, useMemo, useState, useRef } from 'react';
function CustomPublisher({ mediaStream }) {
  const videoRef = useRef(null);
  useEffect(() => {
    if (mediaStream) {
      videoRef.current.srcObject = mediaStream;
    }
  }, [mediaStream]);
  return <video width="100%" ref={videoRef} autoPlay playsInline muted></video>;
}

export default CustomPublisher;

Nous ajoutons l'attribut autoplay qui permettra de lire automatiquement les nouveaux flux attribués à l'élément. L'attribut playsinline permet à la vidéo d'être lue en ligne au lieu d'être lue uniquement en plein écran. Nous ajoutons également l'attribut muted pour éviter l'écho car l'API Video de Vonage jouera l'audio à travers l'élément vidéo créé mais non rendu sur le DOM.

Tout ce que nous faisons avec notre élément Video, c'est remplir le srcObject avec le mediaStream fourni par l'événement videoElementCreated événement. Le code suivant montre comment obtenir le mediaStream à partir de l'écouteur d'événement.

//hooks/publisher.jsx

publisher.on('videoElementCreated', handleVideoElementCreated);
//hooks/publisher 

function handleVideoElementCreated({ element }) {
    const stream = element.srcObject;
    setPubStream(stream);
  }

Puis dans notre page Chambrenous pouvons simplement rendre notre composant CustomPublisher avec le mediaStream comme propriété. Notez que mPublisher est juste l'importation du crochet publisher() et pubStream est l'élément d'état qui contient notre mediaStream

//Pages/Room.index.js
  {mPublisher.pubStream && <CustomPublisher mediaStream={mPublisher.pubStream}></CustomPublisher>}

Abonné

L'approche que nous allons adopter pour le rendu des abonnés est similaire, mais avec une mise en garde. Au moment de la rédaction de ce billet de blog, pour les clients utilisant des versions de JS > 2.24.7, si vous travaillez avec des mediaStreams du côté de l'abonné, vous devez suivre les étapes décrites dans cet article d'assistance.

Tout d'abord, nous devons désactiver l'interface utilisateur par défaut, comme nous l'avons fait pour l'éditeur. Ensuite, dans ce cas, nous allons définir un élément d'état. Nous allons stocker l'élément vidéo créé par Video afin de pouvoir accéder au mediaStream sous-jacent. Vous verrez ce que nous faisons avec l'élément vidéo dans un instant. Cette logique est définie dans le contexte de session

 async function subscribe(stream, session, options = {}) {
    console.log('request to subscribe');
    if (session) {
      console.log(session);
      const finalOptions = Object.assign({}, options, {
        insertMode: 'append',
        width: '100%',
        height: '100%',
        insertDefaultUI: false,
      });
      const subscriber = session.current.subscribe(stream, null, finalOptions);
     subscriber.on('videoElementCreated', function (event) {
        const element = event.element;
        element.setAttribute('id', event.target.streamId);
        setSubscriberElements((prevStreams) => [...prevStreams, { element, subscriber     }]);
      });
      addSubscribers({ subscriber });
    }
  }

Dans le CustomSubscriber composantnous fournirons notre élément vidéo et attacherons un écouteur d'événements à l'élément vidéo créé par Vonage afin de pouvoir mettre à jour notre mediaStream lorsqu'il change, comme expliqué dans l'article.

import React, { useEffect, useRef } from 'react';

function CustomSubscriber({ element }) {
  const videoRef = useRef(null);
  const mediaStream = element.srcObject;
  useEffect(() => {
    if (mediaStream && videoRef.current) {
      videoRef.current.srcObject = mediaStream;
      videoRef.current.setAttribute('id', element.id);
      const handleStreamChange = () => {
        if (mediaStream !== element.srcObject) {
          videoRef.current.srcObject = element.srcObject;
        }
      };

      element.addEventListener('play', handleStreamChange);

      return () => {
        element.removeEventListener('play', handleStreamChange);
      };
    }
  }, [element, mediaStream]);

  return <video width="100%" ref={videoRef} autoPlay playsInline muted></video>;
}

export default CustomSubscriber;

Comme dans le cas du Publisher, nous récupérons le mediaStream de l'élément Video et l'attachons à notre élément Video. La différence est que nous devons maintenant ajouter un écouteur d'événements pour comprendre quand le mediaStream change et mettre à jour notre élément Video avec le nouveau mediaStream s'il change.

À ce stade, nous pouvons rendre les abonnés dans notre page d'accueil.

{mSession.subscriberElements.length > 0 &&
            mSession.subscriberElements.map((element, index) => <CustomSubscriber key={index} element={element}></CustomSubscriber>)}

Notez que vous pouvez également transmettre l'objet abonné au composant CustomSubscriber pour mettre à jour votre interface utilisateur en fonction de l'état. Par exemple, vous pouvez afficher une icône de superposition micro on/off en fonction de la propriété subscriber.stream.hasAudio en fonction de la propriété Cela vous permettra de ne pas avoir à manipuler le DOM en insérant/supprimant des éléments HTML au-dessus de l'élément Video créé par l'API Video de Vonage. Au lieu de cela, vous rendrez différents états basés sur les différentes propriétés de l'abonné en fonction de votre logique d'application.

Important à noter

Notez que si vous suivez cette approche et décidez d'utiliser vos éléments vidéo plutôt que les éléments vidéo créés par le SDK, vous ne pourrez pas utiliser certaines fonctionnalités liées à l'élément vidéo du SDK. Vous ne bénéficierez pas des éléments suivants initiales de l'éditeur et backgroundImageUri car la logique de ces fonctionnalités est construite au-dessus de l'élément vidéo créé par Vonage.

Conclusion

En conclusion, Vonage offre une grande flexibilité lors du développement d'applications de vidéoconférence. Par défaut, Vonage crée un élément vidéo que vous pouvez attacher au DOM. Cependant, nous prenons également en charge les cas d'utilisation où vous devez fournir votre élément vidéo en accédant aux mediaStreams des éléments vidéo que l'API Video de Vonage crée pour vous.

Pour obtenir les dernières nouvelles, connectez-vous avec nous sur notre communauté de développeurs Communauté des développeurs Slacksur X, anciennement connu sous le nom de Twitteret lors d'événements.

Partager:

https://a.storyblok.com/f/270183/384x384/6007824739/javier-molina-sanz.png
Javier Molina Sanz

Javier studied Industrial Engineering back in Madrid where he's from. He is now one of our Solution Engineers, so if you get into trouble using our APIs he may be the one that gives you a hand. Out of work he loves playing football and travelling as much as he can.