https://d226lax1qjow5r.cloudfront.net/blog/blogposts/experience-spatial-audio-with-vonage-video/spatial-audio_video-api-1.png

Vonage Video APIで空間音声を体験しよう

最終更新日 November 16, 2021

所要時間:1 分

はじめに

モバイル、デスクトップ、その他のデバイスでオーディオを消費する方法は変化しており、パンデミックは間違いなく消費モデルに影響を与えている。オーディオにまつわる流行語の1つに "空間オーディオ "があります。この記事では、Webブラウザ上でVonage Video APIとResonance SDKを使って空間オーディオ体験を構築する方法を紹介します。

空間オーディオ体験はいかがですか?ヘッドセットを使用してビデオをご覧ください。

オーディオの歴史

Spatial audio/3D audioについて話す前に、オーディオチャンネルとその違いについて話しましょう。

モノ

モノラル(1つの意味)オーディオとは、右のイヤホンで再生される音声と左のイヤホンで再生される音声が同じであるシングル・チャンネル・オーディオのことです。すべての音は両方のイヤホンに均等に分散されます。

ステレオ

ステレオ・オーディオは2チャンネル・オーディオで、右のイヤホンと左のイヤホンで異なる音を聞くことができます。右ではギターの音が、左では足音が聞こえます。

サラウンド・サウンド

オーディオがどのようにミックスされ再生されるかについては、独自の研究が行われてきた。モノラルおよび/またはステレオ音声は、オーディオセットアップのスピーカーとサブウーファーの数(5.1、7.1など、5つのスピーカーと1つのサブウーファー、または7つのスピーカーと1つのサブウーファーに等しい)に合わせてミックスされ、サラウンドサウンド感を作り出すためにすべてのスピーカーとサブウーファーで再生されます。

バイノーラル

これはステレオの改良版で、録音には2本の無指向性マイクが必要です。この音声を再生すると、あたかも自分がその場所にいるように聞こえる。

空間オーディオ

スペーシャルオーディオでは、オーディオを3D空間のどこにでも配置することができます。つまり、音源を左右だけでなく、上、下、前、後でも聞き分けることができるのです。空間オーディオは、音声が左右の耳に到達する時間を遅らせたり、高い周波数と低い周波数を使い分けることで、人間の脳をだます。VR空間の成長が、空間オーディオの人気に拍車をかけている。

スペーシャル・オーディオにこだわるべきか?

ビデオ会議の疲労- ビデオ会議の音声は、すべて同じスピーカーから同じ距離で聞こえるため、不自然なリスニング体験となります。このような合成された音場は、音が位置的、指向的、球状である現実のリスニング体験とは異なります。空間オーディオは、オーディオを3D空間に配置することで、現実のリスニング体験を再現することができます。

AR・VR空間空間オーディオは、AR/VR空間での没入感を演出します。AR/VR空間では、ビジュアルやアクションと同様にオーディオが重要な役割を果たします。

ソーシャルアプリの構築- In-App Videoライブストリーミングアプリは、会話をより魅力的でインタラクティブなものにするために空間オーディオを導入している。

Vonage Video APIとResonance SDKを使用した空間オーディオ体験

Vonage Video SDKとResonance SDKを使用した空間オーディオ体験の構築について、カスタマー・ソリューション・エンジニアのRajkiran Talusaniが「HOW TO」ガイドを作成しました。以下の手順に従ってください。

必要条件

特別なハードウェアは必要ですか?

いいえ、ステレオヘッドセット/イヤホン、またはオーディオをレンダリングするための互換性のあるデバイスが必要なだけです。この特別な例に特別なマイクは必要ありません。

初期設定

レゾナンス・オーディオは、x,y,z座標で特定される3D空間の特定の位置にリスナーを配置することができます。そして、任意の数のオーディオソースを異なる位置に置くことができ、レゾナンス・オーディオは、物理的な空間にいるように聞こえるようにオーディオストリームをミックスします。

Spatial Audio - Virtual Room ExampleSpatial Audio - Virtual Room Example

最初のステップは、AudioContextとGainノードを作成し、レゾナンスのオーディオ・ボリュームをコントロールすることです。

audioContext = new AudioContext();
  resonanceGain = audioContext.createGain();

次に、3Dの部屋とその壁の素材を定義します。

let roomDimensions = {
  width: roomWidth,
  height: roomHeight,
  depth: roomDepth,
  };
  
  let roomMaterials = {
  left: 'uniform',
  right: 'uniform',
  up: 'uniform',
  down: 'uniform',
  front: 'uniform',
  back: 'uniform'
  };

利用可能なすべての壁材タイプについては、レゾナンス・オーディオのドキュメントを参照してください。

次に、Resonance Audioのインスタンスを作成し、resonanceGainを通してaudioContextに接続します。また、リスナーの初期位置を部屋の中心(0,0,0)に設定します。

resonanceAudioScene = new ResonanceAudio(audioContext,{
  ambisonicOrder: 1
  });
  
  resonanceAudioScene.output.connect(resonanceGain);
  resonanceGain.connect(audioContext.destination);
  resonanceAudioScene.setRoomProperties(roomDimensions, roomMaterials);
  resonanceAudioScene.setListenerPosition(0, 0, 0);

加入者をレゾナンス・オーディオにつなぐ

次に、セッションに加入者が追加されるたびに、加入者の出力をレゾナンス・オーディオに接続する。

function connectVideoToResonanceAudio(subscriber,x=1,y=0,z=1) {
  if(!isSupported)
  return;
  let subscriberId = subscriber.id;
  subscriber.setAudioVolume(0);
  
  console.log("Adding streamId="+subscriber.stream.id+" to the
  map");
  // find the video element 
  var videoElem = subscriber.element.querySelector('video');
  if(videoElem == undefined){
  console.log("Video Element null in connectVideoToResonanceAudio. Something terribly wrong");
  return;
  }
  
  let audioElementSource =
  audioContext.createMediaStreamSource(videoElem.srcObject);
  let source = resonanceAudioScene.createSource();
  audioElementSource.connect(source.input);
  source.setPosition(x, y, z);
  resonanceSources\[subscriberId] = source;
  }

加入者のオーディオを直接聞きたいわけではないので、加入者のボリュームを0に設定していることに注意してください。その代わりに、加入者のオーディオをResonanceを通してルーティングします。

まず、サブスクライバの video要素を見つけ、videoElem.srcObject を使ってサブスクライバのオーディオストリームを取得し、MediStream を返す。次に、"Resonance audio source "を作成し、サブスクライバのオーディオストリームをこのソースに接続します。サブスクライバ・ソースの初期位置は、デフォルト値に設定できます。この位置は、後でレイアウトが確定したり、サイズが変更されたときに変更します。

ソース・ポジションを加入者に割り当てる

レイアウトに新しいサブスクライバを追加した場合、またはレイアウトのサイズが変更された場合は、レイアウト上のサブスクライバの相対位置に基づいてソース・ポジションを再割り当てする必要があります。

参加者はそれぞれ自分のレイアウトを持つことができる。

このスニペットでは、リスナーを球体の中心に配置し、次に加入者を半球の縁(およそ)に配置している。

  function adjustAudioSourcePositions(streams, numSpeakersVisible, layoutDiv){\
  // find the center point of the video layout in pixels 
  let layoutRect = document.getElementById(layoutDiv).getBoundingClientRect();
  let layoutCenterX = layoutRect.left + (layoutRect.width/2);
  let layoutCenterZ = layoutRect.top + (layoutRect.height/2);
  // convert pixels to room dimensions in meters
  let scaleX = roomWidth/layoutRect.width;
  let scaleZ = roomHeight/layoutRect.height;
  for(i=0;i<numSpeakersVisible && i <streams.length;i++){
  /* for each subscriber, get the bounding box and find the center relative to
  the center of layoutContainer */
  let subscriberRect =
  document.getElementById(streams\[i].subscriber.id).getBoundingClientRect();
  let subscriberCenterX = subscriberRect.left + (subscriberRect.width/2);
  let subscriberCenterZ = subscriberRect.top + (subscriberRect.height/2);
  
  let relativeX = (subscriberCenterX - layoutCenterX)*scaleX;
  let relativeZ = (subscriberCenterZ - layoutCenterZ)*scaleZ;
  /* lets keep people closer to the center of screen further away on Y axis, so
  it should be like people sitting in half spherical shape */
  let Y = 2 * (1 - (Math.abs(relativeX)/(roomWidth/2)));
  setSourcePosition(streams\[i].subscriber.id,relativeX,Y,relativeZ);
  }
  }

スペーシャルとモノラルの切り替え

同様に、モノモードを有効にするには、すべての加入者のボリュームを50に設定し、resonanceGainのゲイン値を0に設定する。

  function changeMode(mode){
  if(!isSupported)
  return;
  if(mode == MODE_SPATIAL){
  console.log("mode is spatial now");
  resonanceGain.gain.value=1;
  setSubscribersVolume(0);
  }
  else if(mode == MODE_NONE){
  console.log("mode is mono now");
  resonanceGain.gain.value=0;
  setSubscribersVolume(50);
  }
  }
  
  
  function setSubscribersVolume(vol){
  if(!isSupported)
  return;
  for (var streamId in subscriberMap) {
  subscriberMap\[streamId].setAudioVolume(vol);
  }
  }

ブラウザの互換性

すべてのブラウザに互換性があるはずですが、テスト中にいくつかの問題が発生しました。Firefoxは期待通りに動作しますが、デスクトップのChromeでは、音声がWebAudio経由でルーティングされる際にエコーキャンセレーションが有効にならないことがわかりました (Chromeのバグ).これは、参加者の誰かがヘッドセットを装着していない場合、全員に悪いオーディオ体験をもたらす可能性があることを意味します。この問題を回避するには、処理された音声をループバックピア接続でルーティングし、オーディオエレメントに接続します。

以下に修正する:

function fixChrome687574(loopbackDestination, audioContext,
  resonanceGainNode,audioEl){
  const outboundPeerConnection = new RTCPeerConnection();
  const inboundPeerConnection = new RTCPeerConnection();
  const onError = e => {
    console.error("RTCPeerConnection loopback initialization error", e);
  };
  outboundPeerConnection.addEventListener("icecandidate", e => {
  inboundPeerConnection.addIceCandidate(e.candidate).catch(onError);
  });
  inboundPeerConnection.addEventListener("icecandidate", e => {
  outboundPeerConnection.addIceCandidate(e.candidate).catch(onError);
  });
  inboundPeerConnection.addEventListener("track", e => {
  audioEl.srcObject = e.streams[0];
  });
  resonanceGainNode.connect(loopbackDestination);
  loopbackDestination.stream.getTracks().forEach(track => {
  outboundPeerConnection.addTrack(track, loopbackDestination.stream);
  });
  outboundPeerConnection.createOffer().then(offer => {
  outboundPeerConnection.setLocalDescription(offer).catch(onError);
  
  inboundPeerConnection
  .setRemoteDescription(offer)
  .then(() => {
  inboundPeerConnection
  .createAnswer()
  .then(answer => {
  answer.sdp = answer.sdp.replace('useinbandfec=1', 'useinbandfec=1', 'stereo=1');
  inboundPeerConnection.setLocalDescription(answer).catch(onError);
  outboundPeerConnection.setRemoteDescription(answer).catch(onError);
  })
  .catch(onError);
  })
  .catch(onError);
  });
  }

サファリ(14.1.2)にもオーディオの問題があるが、15.xは問題なく動作しているようだ。

今後の改善

3D空間に音源を配置しても、音源は点音源です。将来の改良として、指向性音源にして、各加入者がリスナーの方向だけに音を出すようにすることもできます。

結論

本日、Vonage Video APIとResonance SDKを使用して、加入者をバーチャル・ルームのさまざまな場所に配置することで、空間オーディオ体験を構築しました。空間オーディオを有効にすることで、バーチャル・ミーティングをより楽しむことができます。ソースコード 完全なソースコードをご覧ください。

シェア:

https://a.storyblok.com/f/270183/400x400/e204f1b8c6/binoy-chemmagate.png
Binoy Chemmagateヴォネージ・マネージャー

ビノイ・チェンマゲイトは、ICT業界で10年以上の経験を持つVonage AIサービスのプロダクトリードで、ジェネレーティブAI APIとローコード会話AIプラットフォームを専門としている。ロンドンを拠点に、空いた時間には未来のプロダクト・マネージャーの指導を楽しんでいる。