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

Vonage Video API で mediaStreams を使用する方法

最終更新日 April 24, 2024

所要時間:1 分

Vonage Video API は、開発者がアプリケーションに Video を簡単に追加できるようにします。ビデオ会議アプリケーションにそれほど特殊なニーズがない場合や、ビデオ要素に対する低レベルのコントロールが必要な場合は、Vonage Video API が提供するデフォルトの UI を使用することができ、開発チームの複雑さを軽減することができます。しかし メディアストリームの操作に慣れていて、Video 要素を処理したい場合、または Video アプリケーションの構築方法の設計原則に適している場合は、Vonage Video API をご利用ください。

前提条件

  1. Video API アカウント。クリック サインアップをクリックして作成してください。

  2. このブログ記事では、Vonage Video API に精通していることを前提に、Video 要素の公開と購読に必要な特定のニーズのみに焦点を当てます。

カスタム・ビデオ・エレメント

開発者がVonage Video APIを簡単に使用できるように、Client SDKはデフォルトでvideo要素を作成し、DOMにアタッチすることができます。しかし、さらにコントロールしたい場合は、独自の HTML Video 要素を提供することもできます。このブログ記事では このReactアプリケーションを参照して、mediaStream にアクセスし、それを独自の Video 要素の srcObject として使用する方法を説明します。自由にクローンして試してみてください。

出版社

まず最初に、パブリッシャーのプロパティでデフォルトの UI を無効にする必要があります。 開発者向けドキュメントにあるように.パブリッシュ関数は パブリッシャーフック

//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);
    }
  }

セッションに発行するロジックは、publishAttempt関数で定義します。しかし、簡単にするために、1 回の再試行をハードコードすることにします。基盤となる mediaStream にアクセスして Video 要素で使用したいので、publish 関数にターゲット要素を渡していないことに注意してください。

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;
    }
  }

次に videoElementCreated イベントをリッスンする必要があります。ここで、イベントでディスパッチされた Video 要素を直接使用するのではなく videoElementCreatedイベントでディスパッチされた Video 要素を直接使用するのではなく、mediaStream にアクセスして独自の Video 要素に送ります。の実装を確認してください。 コンポーネントの実装を確認してください。.

//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;

私たちは autoplay属性を追加しており、これにより、要素に割り当てられた新しいストリームが自動的に再生されるようになる。この playsinline属性により、Video をフルスクリーンではなくインラインで再生できるようになります。また、Vonage Video API は、作成された Video 要素を通して音声を再生しますが、DOM 上ではレンダリングされないため、エコーを避けるために muted 属性を追加します。

Video 要素で行っているのは、srcObject にイベントによって提供された mediaStream を入力することだけです。 videoElementCreatedイベントによって提供される mediaStream を srcObject に入力することです。次のコードは、イベント リスナーから mediaStream を取得する方法を示しています。

//hooks/publisher.jsx

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

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

次に ルームページページで CustomPublisherコンポーネントをレンダリングします。をレンダリングするだけです。ただし mPublisherフックのインポートであり publisher()フックのインポートであり pubStreamを含む状態の一部であることに注意してください。

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

購読者

サブスクライバーをレンダリングするために取るべきアプローチも同様ですが、1つ注意点があります。このブログ記事を書いている時点で、JSのバージョン> 2.24.7を使用している顧客は、購読者側でmediaStreamsを操作している場合、以下のサポート記事で説明されている手順に従ってください。 サポート記事.

まず、パブリッシャーの時と同じように、デフォルトのUIを無効にする必要がある。次に、この場合、1 つの状態を設定します。Vonage が作成した Video 要素を保存して、基盤となる MediaStream にアクセスできるようにします。Video 要素で何を行うかは、後ほど説明します。このロジックは セッション・コンテキスト

 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 });
    }
  }

コンポーネント CustomSubscriberコンポーネントでで、Video 要素を提供し、Vonage が作成した Video 要素にイベントリスナーをアタッチします。

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;

パブリッシャーの場合と同様に、video 要素から mediaStream を取得し、それを video 要素にアタッチします。違いは、mediaStream がいつ変更されたかを理解し、変更された場合は video 要素を新しい mediaStream で更新するために、イベント リスナーを追加する必要があることです。

この時点で、ルームページに購読者をレンダリングすることができます。

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

コンポーネントにサブスクライバ・オブジェクトを渡すこともできます。 CustomSubscriberコンポーネントに渡すこともできます。例えば、マイクのオン/オフのオーバーレイアイコンを subscriber.stream.hasAudioプロパティに応じて、マイクのオン/オフのオーバーレイアイコンを表示できます。これにより、Vonage Video API によって作成された Video 要素の上に HTML 要素を挿入/削除して DOM を操作する必要がなくなります。代わりに、アプリケーションのロジックに基づいて、異なる加入者プロパティに基づいて異なる状態をレンダリングします。

重要な注意事項

この方法に従って、SDKが作成したVideoエレメントではなく、自分で作成したVideoエレメントを使用することにした場合、SDKのVideoエレメントに関連付けられたいくつかの機能を使用できなくなることに注意してください。また、次の機能も使用できません。 パブリッシャ イニシャルと backgroundImageUriの恩恵を受けることはできません。これらの機能のロジックは、Videoage が作成した video 要素の上に構築されているからです。

結論

結論として、Vonageはビデオ会議アプリケーションを開発する際に多くの柔軟性を提供します。デフォルトでは、Vonage は DOM にアタッチできる Video 要素を作成します。しかし、Vonage Video API が作成する Video 要素の mediaStreams にアクセスすることで、Video 要素を提供する必要がある場合もサポートしています。

最新ニュースを入手するには、開発者コミュニティ コミュニティSlackにて X(旧Twitterで、そしてイベントで。

シェア:

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.