More than 1 year has passed since last update.

ちょっとお遊びで、WebRTCの音声通話で、音声の途中で都合の悪い言葉を隠すのに「ピー」という音を入れることができるようになる方法を試してみます(笑)。

Chrome for Androidでは残念ながら動作しないようです。
(参考: http://caniuse.com/#search=web%20audio )

まずはマイクの音声をキャプチャ

お約束のnavigator.getUserMedia()です。

音声キャプチャを開始
var mic;
navigator.getUserMedia =
  navigator.getUserMedia ||
  navigator.webkitGetUserMedia ||
  navigator.mozGetUserMedia;
navigator.getUserMedia(
  { audio: true },
  function(s) { mic = s; },
  function(e) { console.log(e); }
);

「ピー」を作る

「ピー」という音を、今回はWeb Audio APIを使って作ってみます。正弦波のオシレータを使えば、十分それっぽい雰囲気が出るのではと思います。

「ピー」の音をオシレータで再現
var context = window.AudioContext || window.webkitAudioContext;
var ctx = new context();
var osc = context.createOscillator();
osc.frequency.value = 880 * Math.pow(2,2/12); // シの音階(ラの音階より全音上)

マイクと「ピー」をミキシング

まず、WebRTC Advent Calendar 9日目のgetUserMedia使ってJSで動くチューナー作った。の記事と同様に、マイクの入力ノードをcreateMediaStreamSource()で取り出します。

その後、マイクと「ピー」のそれぞれの音量をコントロールするゲインノードを作って接続し、それらをcreateMediaStreamDestination()で生成した出力ノードに接続してミキシング、という順序になります。

マイクと「ピー」をミキシング
var micNode = context.createMediaStreamSource(mic);
var micGain, oscGain;
if(context.createGain) {
  micGain = context.createGain();
  oscGain = context.createGain();
}
else {
  // 多分不要だと思われますが、念のため古いWeb Audio APIへの対処
  micGain = context.createGainNode();
  oscGain = context.createGainNode();
}
micNode.connect(micGain);
osc.connect(oscGain);
// まずはマイクを鳴らして「ピー」をミュート
micGain.gain.value = 1;
oscGain.gain.value = 0;
// ミキシング
var output = context.createMediaStreamDestination();
micGain.connect(output);
oscGain.connect(output);
if(osc.start)
  osc.start(0);
else
  // 多分不要だと思われますが、念のため古いWeb Audio APIへの対処
  osc.noteOn(0);

いよいよWebRTC

さて、いよいよWebRTCの初期化です。ここでは詳細は省かせていただいて、要点に絞って説明します。

RTCPeerConnectionの初期化やoffer/answerのやりとり等は通常の手順と同様で、RTCPeerConnection.addStream()で渡すストリームだけ変えればよい、ということになります。

ひとまず、通常と同じようにRTCPeerConnectionインスタンスを生成し、必要な初期化を行います。
そして、addStream()で、先ほど生成したミキシングの出力ノードのストリームをここに渡せばよい、ということになります。output自体ではなく、output.streamを渡す点に注意が必要です。

RTCPeerConnection初期化
var PC =
  window.RTCPeerConnection ||
  window.webkitRTCPeerConnection ||
  window.mozRTCPeerConnection;
var peer = new PC({ iceServers: [ { ... } ] });
peer.onicecandidate = function(ice) { ... };

// ミキシングの出力ノードのストリームをRTCPeerConnectionに追加
peer.addStream(output.stream);

あとは、引き続きoffer/answerを経てセッションを確立させれば、いつもどおりWebRTCで通話ができるようになるわけですが、ここでもう少々細工をして、好きなタイミングでマイクの音声の代わりに「ピー」が相手に聞こえるようにしてみます。ここでは「P」キーを押している間はマイクがミュートされて「ピー」が相手に聞こえる、というようにしています。

「ピー」の切替
function startCensor(evt) {
  if(evt.keyCode == 'P'.charCodeAt(0)) {
    micGain.gain.value = 0;
    oscGain.gain.value = 1;
  }
}

function stopCensor(evt) {
  if(evt.keyCode == 'P'.charCodeAt(0)) {
    micGain.gain.value = 1;
    oscGain.gain.value = 0;
  }
}

document.addEventListener('keydown', startCensor, false);
document.addEventListener('keyup', stopCensor, false);

...というわけで、WebRTC音声チャットで「ピー」、という非常にくだらない使い道を例として(笑)、WebRTCにWeb Audio APIを組み合わせる方法、でした。

この他にも、Web Audio APIをWebRTCに組み合わせて、例えば、音楽ファイルがあれば保留音を相手に聞こえるようにする、等の使い方ができます。色々とお試しあれ。