WebRTC
イベント
該当するコンテンツが見つかりませんでした
マガジン
該当するコンテンツが見つかりませんでした
技術ブログ
はじめに 前回の記事 では、Webアプリで映像を扱う際の産業用途におけるリアルタイムコミュニケーション実現のための検討ポイントと、intdashとintdash-RTC SDKという選択肢を紹介しました。 要点をおさらいすると: SFU選定時はベンダー固有の実装に依存する点も考慮が必要 センサーデータとの統合や録画・解析は追加の設計が必要になる可能性 intdashは、産業用途に適したもう一つの選択肢 前編では概要しか触れなかったため、実際の使用感について興味をお持ちいただいた方もいらっしゃると思います。 本記事では、intdash-RTC SDKの具体的な実装方法をサンプルコード付きで解説します。環境が準備できていれば、約30分で動作するビデオチャットが完成しますので、ぜひお試しください。 ライブラリの概要 intdashは映像・音声・センサーデータを統合して伝送できるプラットフォームです。intdash-RTC SDKは、intdashで扱うデータのうち映像・音声をWebアプリから簡単に扱えるようにするライブラリです。 本ライブラリは3つのインターフェースで構成されています。 ┌─────────────────────────────────────────────┐ │ MediaConnection │ 統合管理 ├─────────────────────┬───────────────────────┤ │ MediaSender │ MediaReceiver │ 送受信 └─────────────────────┴───────────────────────┘ | ^ v | ┌─────────────────────────────────────────────┐ │ intdash (iSCP) │ 伝送 └─────────────────────────────────────────────┘ MediaConnection: 送受信を統合管理。 start() / stop() で接続制御 MediaSender: ローカルメディアをintdashに送信 MediaReceiver: intdashからメディアを受信し、video要素に直接接続 本ライブラリは、TypeScript 向けのintdash通信ライブラリ iscp-ts のラッパーとしても利用できますし、今回のようなアプリケーションでは接続設定を直接指定するシンプルな使い方も可能です。 実装ステップ 以下では、基本的なビデオチャットを実装するサンプルコードを5つのステップに分けて紹介します。全量は記事末尾の「Appendix: サンプルコード全文」に再掲しています。 1. ライブラリのimportとMediaConnectionの作成 // 1. ライブラリのimport import { createMediaConnection } from "@aptpod/intdash-rtc" ; // 2. MediaConnectionの作成(intdashへの接続も内部で行います) const { mediaConnection } = await createMediaConnection( { address : "your-intdash.example.jp" , // intdash接続アドレス projectUuid : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" , // intdashプロジェクトのUUID nodeId : "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" , // 送信元(自分側)のノードUUID enableTLS : true , apiToken : "your_token_here" , // intdash Web Consoleから作成したAPIトークン(OAuth2サインインを使う場合はapiTokenを省略) } , { sender : { // 音声に関する設定 audio : { codec : "PCM" , // PCM, OPUS, AACをサポート } , // 映像に関する設定 video : { codec : "H264" , // H264, VP9をサポート } , } , receiver : { sourceNodeIds : [ "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz" ] , // 通信相手のノードUUID } , } , ); @aptpod/intdash-rtc が今回のintdash-RTC SDKです。これをimportするだけで、intdashを介したビデオチャットが実装できます( @aptpod/iscp-ts は peer dependency として併せてインストールが必要です)。 createMediaConnection 関数で、intdashへの接続とMediaConnectionの作成をまとめて行います。第1引数で接続情報(アドレス・プロジェクトUUID・ノードUUID・APIトークン)を、第2引数で送受信オプションを指定します。これらの値は intdash Web Console から取得できます。APIトークンは長期間有効な固定トークンですが、より安全なワンタイムトークンやOAuth2による認証も利用可能です。送受信オプションは階層化された構造になっており、 sender.audio で音声設定、 sender.video で映像設定、 receiver で受信対象ノードを指定します。コーデックは型安全な文字列リテラル型で指定でき、設定ミスを防ぎます。 2. ローカルメディアの取得と表示 // 3. ローカルメディアストリームの取得と設定 const localStream = await navigator .mediaDevices. getUserMedia ( { video : true , audio : true , } ); await mediaConnection.sender.setLocalMediaStream(localStream); // ローカル映像をvideo要素に表示 const localVideoEl = document . getElementById ( "local-video" ) as HTMLVideoElement ; localVideoEl.srcObject = new MediaStream (localStream.getVideoTracks()); localVideoEl.muted = true ; await localVideoEl.play(); getUserMedia でカメラとマイクからストリームを取得し、 setLocalMediaStream で設定します。取得したストリームはそのままローカルのvideo要素にも表示できます。 3. 受信メディアのvideo要素への接続 // 4. 受信メディアストリームの処理 const remoteVideoEl = document . getElementById ( "remote-video" , ) as HTMLVideoElement ; mediaConnection.receiver.on( "statechange" , ( state ) => { if (state === "running" ) { // 受信が開始されたら、video要素に直接接続 mediaConnection.receiver.attach(remoteVideoEl); } else if (state === "stopped" || state === "failed" ) { // 受信が停止したら、video要素から切断 mediaConnection.receiver.detach(remoteVideoEl); } } ); 受信側の状態変化は statechange イベントで監視します。 running になったら attach() でvideo要素に直接接続できます。内部の変換処理(デコード等)はintdash-RTC SDKが処理するため、意識する必要がありません。 4. 接続開始 // 5. 接続開始(running状態まで待機) await mediaConnection.start( { waitUntil : "running" } ); console . log ( "接続が確立しました" ); start({ waitUntil: 'running' }) で接続を開始し、 running 状態になるまで待機します。これにより、接続が完全に確立してから次の処理に進めます。 5. UI操作と停止処理 // 6. UI操作(映像・音声の有効/無効切り替え) document . getElementById ( "toggle-video" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setVideoEnabled( !mediaConnection.sender.videoEnabled, ); console .log( `映像: ${ enabled ? "有効" : "無効" } ` ); } ); document . getElementById ( "toggle-audio" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setAudioEnabled( !mediaConnection.sender.audioEnabled, ); console .log( `音声: ${ enabled ? "有効" : "無効" } ` ); } ); // 7. 停止処理(クリーンアップ) document . getElementById ( "stop" )?. addEventListener ( "click" , async () => { await mediaConnection. stop (); await mediaConnection.iscpConn. close (); localStream.getTracks(). forEach (( track ) => track. stop ()); console .log( "接続を終了しました" ); } ); setVideoEnabled / setAudioEnabled で映像・音声を個別に制御できます。終了時は stop() でメディア処理を停止し、 iscpConn.close() でintdash接続もクローズします。内部のワークレットやバッファも自動的にクリーンアップされます。 実際の動作の確認 このように、WebRTCと遜色ない簡潔さで、intdashを使った映像・音声通信を実装できます。 実際にサンプルアプリを動作させた様子が以下の動画です。 youtu.be 画面の左側がサンプルアプリ「Easy Video Chat」、右側がintdashに付属する簡易可視化ツール「Edge Finder」です。 サンプルアプリ「Easy Video Chat」には「あなた」(左)と「相手」(右)の2つの映像表示があります。今回のデモでは送信元と受信元のノードを同一に設定しているため、左右に同じ映像が表示されています。左の「あなた」は getUserMedia で取得したローカル映像をそのまま表示したもの、右の「相手」はそのローカルメディアをintdashへ送信したあと再度受信してデコード・表示したものです。 実際に二者間で通話する場合は、相手側でも同様にintdashへの接続と受信元ノードの指定を行うことで、双方向での映像・音声通話が成立します。 同時にEdge Finder側では、送信されたH.264映像フレームとPCM音声データが、それぞれ時系列のデータポイントとしてintdashに記録されていく様子が確認できます。 さらなる拡張性 データの可視化とダッシュボードのカスタマイズ 動画で紹介した「Edge Finder」はintdashに標準で付属しており、送受信されているデータをすぐに確認できる簡易ツールです。 より高度な可視化やダッシュボードのカスタマイズが必要な場合は、弊社の可視化アプリケーション「VM2M Data Visualizer」をご利用いただけます。ノーコードで時系列データのダッシュボードを構築でき、映像とセンサーデータを時刻同期させた再生や、多彩なウィジェットを組み合わせた解析画面の作成に対応しています。 VM2M Data Visualizer: 複数の映像と時系列データを時刻同期して再生するタイムラインビュー VM2M Data Visualizer: ゲージ・グラフ・レーダーチャートなど多彩なウィジェットを組み合わせたカスタムダッシュボード Appendix: サンプルコード全文 ここまでステップごとに分割して紹介してきたサンプルコードの全量を、以下に再掲します。 // 1. ライブラリのimport import { createMediaConnection } from "@aptpod/intdash-rtc" ; // 2. MediaConnectionの作成(intdashへの接続も内部で行います) const { mediaConnection } = await createMediaConnection( { address : "your-intdash.example.jp" , // intdash接続アドレス projectUuid : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" , // intdashプロジェクトのUUID nodeId : "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" , // 送信元(自分側)のノードUUID enableTLS : true , apiToken : "your_token_here" , // intdash Web Consoleから作成したAPIトークン(OAuth2サインインを使う場合はapiTokenを省略) } , { sender : { // 音声に関する設定 audio : { codec : "PCM" , // PCM, OPUS, AACをサポート } , // 映像に関する設定 video : { codec : "H264" , // H264, VP9をサポート } , } , receiver : { sourceNodeIds : [ "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz" ] , // 通信相手のノードUUID } , } , ); // 3. ローカルメディアストリームの取得と設定 const localStream = await navigator .mediaDevices. getUserMedia ( { video : true , audio : true , } ); await mediaConnection.sender.setLocalMediaStream(localStream); // ローカル映像をvideo要素に表示 const localVideoEl = document . getElementById ( "local-video" ) as HTMLVideoElement ; localVideoEl.srcObject = new MediaStream (localStream.getVideoTracks()); localVideoEl.muted = true ; await localVideoEl.play(); // 4. 受信メディアストリームの処理 const remoteVideoEl = document . getElementById ( "remote-video" , ) as HTMLVideoElement ; mediaConnection.receiver.on( "statechange" , ( state ) => { if (state === "running" ) { // 受信が開始されたら、video要素に直接接続 mediaConnection.receiver.attach(remoteVideoEl); } else if (state === "stopped" || state === "failed" ) { // 受信が停止したら、video要素から切断 mediaConnection.receiver.detach(remoteVideoEl); } } ); // 5. 接続開始(running状態まで待機) await mediaConnection.start( { waitUntil : "running" } ); console . log ( "接続が確立しました" ); // 6. UI操作(映像・音声の有効/無効切り替え) document . getElementById ( "toggle-video" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setVideoEnabled( !mediaConnection.sender.videoEnabled, ); console .log( `映像: ${ enabled ? "有効" : "無効" } ` ); } ); document . getElementById ( "toggle-audio" )?. addEventListener ( "click" , async () => { const enabled = await mediaConnection.sender.setAudioEnabled( !mediaConnection.sender.audioEnabled, ); console .log( `音声: ${ enabled ? "有効" : "無効" } ` ); } ); // 7. 停止処理(クリーンアップ) document . getElementById ( "stop" )?. addEventListener ( "click" , async () => { await mediaConnection. stop (); await mediaConnection.iscpConn. close (); localStream.getTracks(). forEach (( track ) => track. stop ()); console .log( "接続を終了しました" ); } ); おわりに 本記事では、intdash-RTC SDKを使ったビデオチャットの実装方法を見てきました。 ポイントのまとめ: WebRTCと同等の簡潔さで、intdash経由のビデオチャットを実装可能 最初はビデオチャットから始めて、将来はセンサーデータを含むマルチモーダルシステムへ拡張できるのがintdashの強みです。同じプラットフォーム、同じSDKで対応できるため、技術選定で後悔するリスクを減らせます。 「試してみたい」「もう少し詳しく知りたい」という方は、ぜひお気軽に お問い合わせ ください。本ライブラリは現在お問い合わせベースでの個別提供となっています。
はじめに WebRTCという標準的な選択肢 産業用途での検討ポイント SFUの選定と移行コスト センサーデータとの統合 録画・解析システムの構築 intdashという選択肢 Webアプリからintdashを使う ― intdash-RTC SDK ユースケース おわりに はじめに Webアプリケーションでリアルタイムな映像通信を実装したい。ビデオ通話、遠隔支援、リアルタイム監視...。こうしたニーズは年々高まっています。 リアルタイムな映像通信を実装するとき、まず候補に挙がるのがWebRTCです。ブラウザ標準で使え、低遅延な双方向通信が可能で、実績も豊富。多くの開発者が最初に検討する選択肢でしょう。 ただ、産業用途で本格的に活用するには、追加の検討が必要になることもあります。本記事では、産業用途での検討ポイントを整理しつつ、intdashという選択肢を紹介します。 WebRTCという標準的な選択肢 WebRTC(Web Real-Time Communication)は、ブラウザ間で低遅延な双方向通信を実現するための技術です。P2Pによるダイレクトな通信が可能で、ビデオ会議、ライブカスタマーサポート、オンライン診療など、さまざまなユースケースで広く採用されています。 WebRTCの強み: ブラウザ標準: 主要ブラウザでネイティブサポート、追加プラグイン不要 低遅延な双方向通信: P2Pによる直接接続で、遅延を最小限に抑えた通信を実現 豊富な実績: ビデオ会議ツールやオンライン診療など、多くのサービスで採用 SFUベンダーの充実: Twilio、Agora、時雨堂等、多くの選択肢 「標準規格だからベンダーロックインされない」という声もよく聞きます。確かにWebRTC自体はRFCで標準化されたプロトコルです。 産業用途での検討ポイント WebRTCは汎用的で優れた技術ですが、産業用途で本格的に活用するには、追加の検討や工夫が必要になることがあります。 SFUの選定と移行コスト WebRTCの接続方式:P2P vs SFU WebRTCの「標準」が規定するのは、主にブラウザ間のP2P通信です。 P2Pは1対1の通信に向いていますが、参加者が増えると各端末の送受信負荷が急増するため、多人数での通信にはSFU(Selective Forwarding Unit)が必要になります。しかし、SFUは各ベンダーが独自に実装しており、ルーム管理、認証、録画といった機能もベンダーごとにAPIが異なります。 また、利用規模の拡大や新たな機能要件により、SFUベンダーの乗り換えが必要になることもあります。その場合、ベンダー固有のAPIに依存した部分は作り直しになるため、選定時には将来的な移行コストも考慮に入れておくと良いでしょう。 センサーデータとの統合 産業用途では、映像だけでなくセンサーデータも一緒に扱いたいケースがあります。たとえば、車両の走行映像とCANデータ・GPS、建設現場の監視映像とセンサー情報、製造ラインの映像と設備データ、といった組み合わせです。 WebRTCでこれを実現する場合、DataChannelを活用する方法があります。ただし、DataChannelはデータの送受信のみを提供するため、センサーデータの格納フォーマットや映像との時刻同期の仕組みは、自前で定義・実装する必要があります。 録画・解析システムの構築 「送信した映像を後から見返したい」「解析に使いたい」という要件も多いです。 WebRTCでは、録画や解析の機能は標準で提供されていません。SFUベンダーが録画機能を提供している場合もありますが、解析・可視化まで含めたシステムを構築する場合は、追加の開発が必要になることがあります。 intdashという選択肢 弊社が開発するintdashは、こうした産業用途のニーズを想定して設計された伝送プラットフォームです。 intdashの強み: マルチモーダル対応: 映像、音声、センサーデータを統合して伝送可能 大容量・低遅延: モバイル回線経由でも高頻度データを伝送可能 時刻同期が標準装備: すべてのデータに共通の基準時刻でタイムスタンプ 保存・解析・可視化まで一気通貫: サーバーに保存し、Data Visualizerでノーコード可視化・再生が可能 Webアプリからintdashを使う ― intdash-RTC SDK intdashでWebアプリから映像・音声のリアルタイム通信を行う場合は、intdash-RTC SDKを使用できます。 intdash-RTC SDKは、intdashを用いたリアルタイムコミュニケーションを実装するためのSDKです。 intdashの通信クライアントをラップして利用することで、リアルタイムコミュニケーションの実装をWebRTCのようなシンプルなインターフェイスで実現できます。 intdash-RTC SDKは、3つのインターフェイスで構成されています: MediaConnection: 接続の開始・停止 MediaSender: 映像・音声を送信 MediaReceiver: 映像・音声を受信 さらに、センサーデータの統合や録画・可視化といったintdashの機能も併せて活用できます。 実装の流れは以下のとおりです。シンプルなビデオチャットであれば、数十行のコードで実装できます: // 1. intdashに接続 const iscpConn = await iscp.Conn.connect( { address , connector , tokenSource , nodeId } ) // 2. メディア接続を設定 const mediaConnection = createMediaConnection(iscpConn, { video : { codec : 'H264' , ... } , audio : { codec : 'PCM' , ... } , receive : { sourceNodeIds : [ 相手のノードID ] } } ) // 3. ローカルメディアを送信 const stream = await navigator .mediaDevices. getUserMedia ( { video : true , audio : true } ) await mediaConnection.sender.setLocalMediaStream(stream) // 4. リモート映像を表示 mediaConnection.receiver.on( 'statechange' , state => { if (state === 'running' ) mediaConnection.receiver.attach(videoElement) } ) // 5. 接続開始 await mediaConnection.start() 具体的な実装方法は後編で解説します。 ユースケース intdash-RTC SDKは、以下のようなユースケースで活用できます。 ビデオ通話・遠隔支援: 作業者同士のリアルタイムコミュニケーション、技術支援 遠隔監視: 現場の映像をリアルタイムで確認、必要に応じてセンサーデータも統合 データ収集: 映像とセンサーデータを時刻同期して収集・解析 おわりに Webアプリでリアルタイムな映像通信を実現するとき、WebRTCは有力な選択肢です。ビデオ会議やライブ配信など、多くのユースケースで実績があります。一方で、産業用途においてセンサーデータとの統合や録画・解析が求められる場合は、追加のシステム構築が必要になることがあります。 intdashは、そうしたニーズに対応した、WebRTCとは異なるアプローチの映像伝送プラットフォームです。Webアプリから利用する場合は、intdash-RTC SDKを使うことで、シンプルなインターフェイスでintdashの機能を活用できます。 次回の記事では、intdash-RTC SDKを使った具体的な実装方法をサンプルコード付きで解説します。「実際どれくらい簡単なの?」という疑問にお答えしますので、ぜひご覧ください。 本ライブラリは現在お問い合わせベースでの個別提供となっています。ご興味のある方は、お気軽に お問い合わせ ください。
WebRTCをテーマにした連載の最終回として、運用フェーズで重要となるパフォーマンス品質の測定と監視手法を解説します。WebRTCが提供する getStats() APIを用いた統計的分析と、Chromeのデバッグ機能 webrtc-internals によるリアルタイム監視の2つの方法を紹介。特に画面共有アプリケーションで重要となるフレームレート、解像度、CPU負荷などの観点や、確認すべき具体的なStats項目、 clumsy を用いたネットワーク劣化テストの実践的な確認方法にも触れます。
動画
該当するコンテンツが見つかりませんでした
書籍
該当するコンテンツが見つかりませんでした






