WebRTC

WebRTCを利用するためには, navigatorオブジェクトのgetUserMediaメソッドを呼び出す必要があります.

第1引数にはデバイスを指定するためのオブジェクト (連想配列), 第2引数にはデバイスへのアクセスが成功した場合に実行されるコールバック関数, 第3引数にはデバイスへのアクセスが失敗した場合 (ユーザーがデバイスへのアクセスを拒否した場合など) に実行されるコールバック関数を指定します.

サンプルコード 01


// Access microphone and camera
var medias = {audio : true, video : true};

/**
 * @param {MediaStream|LocalMediaStream} stream
 */
var successCallback = function(stream) {
    // do something ....
};

/**
 * @param {NavigatorUserMediaError|MediaStreamError} error
 */
var errorCallback = function(error) {
    // do something ....
};

navigator.getUserMedia(medias, successCallback, errorCallback);

ただし, 現状ではベンダープレフィックスが必要となるので, サンプルコード 02のように修正します.

サンプルコード 02


navigator.getUserMedia = navigator.getUserMedia       ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;

// Access microphone and camera
var medias = {audio : true, video : true};

/**
 * @param {MediaStream|LocalMediaStream} stream
 */
var successCallback = function(stream) {
    // do something ....
};

/**
 * @param {NavigatorUserMediaError|MediaStreamError} error
 */
var errorCallback = function(error) {
    // do something ....
};

navigator.getUserMedia(medias, successCallback, errorCallback);

第1引数のオブジェクト (連想配列) は, マイクにアクセスするのであればaudioプロパティの値をtrueに指定し, カメラにアクセスするのであればvideoプロパティの値をtrueに指定します.

第2引数のコールバック関数には, MediaStreamインスタンス (FirefoxはLocalMediaStreaインスタンス) が渡されます

第3引数のコールバック関数には, NavigatorUserMediaErrorインスタンス (FirefoxはMediaStreamErrorインスタンス) が渡されます.

MediaStreamインスタンスがデバイスからの入力となる重要なオブジェクトです. MediaStreamインスタンスをWeb Audio APIの入力としてあつかう方法は次のセクションで解説します.

とりあえず, デバイス (マイクとカメラ) からの入力を, HTMLVideoElementで再生するには, サンプルコード 03のようにします.

サンプルコード 03


<!-- HTML -->
<video autoplay></video>


navigator.getUserMedia = navigator.getUserMedia       ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;

window.URL = window.URL || window.webkitURL;

var video = document.querySelector('video');

// Access microphone and camera
var medias = {audio : true, video : true};

/**
 * @param {MediaStream|LocalMediaStream} stream
 */
var successCallback = function(stream) {
    video.src = window.URL.createObjectURL(stream);
};

/**
 * @param {NavigatorUserMediaError|MediaStreamError} error
 */
var errorCallback = function(error) {
    console.error(error);
};

navigator.getUserMedia(medias, successCallback, errorCallback);

重要なポイントは以下の3つです.

  • videoタグにautoplay属性を指定する (これがないと, 最初のフレームしか再生されない)
  • createObjectURLメソッドの引数にMediaStreamインスタンスを渡す
  • 生成したObject URLをHTMLVideoElementのsrc属性に指定する

ちなみに, getUserMediaメソッドを実行すると, ブラウザがデバイスへアクセスする許可を求めるダイアログを表示します. アクセスしても問題がなければ, 「許可」を選択するようにしてください.

デバイスへアクセスする許可を求めるダイアログ

図4 - 2 - a. デバイスへアクセスする許可を求めるダイアログ

それでは, デモ 01で実際に試してみてください.

デモ 01

MediaStreamAudioSourceNode

さて, このセクションがいよいよ本題となります. WebRTCによって取得したデバイスからの入力をどうすれば, Web Audio APIの入力ノードとしてあつかえるかです.

MediaStreamAudioSourceNodeクラスは, WebRTCによって取得したデバイスからの入力, すなわち, MediaStreamインスタンスをWeb Audio APIの入力ノードとしてあつかうことを可能にします.

そして, MediaStreamAudioSourceNodeインスタンスを生成するためには, AudioContextインスタンスの createMediaStreamSourceメソッドを利用します. このメソッドの第1引数にMediaStreamインスタンスを指定します.

サンプルコード 04


window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Create the instance of AudioContext
var context = new AudioContext();

navigator.getUserMedia = navigator.getUserMedia       ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;

// Access microphone
var medias = {audio : true, video : false};

/**
 * @param {MediaStream|LocalMediaStream} stream
 */
var successCallback = function(stream) {
    // Create the instance of MediaStreamAudioSourceNode
    var source = context.createMediaStreamSource(stream);
};

/**
 * @param {NavigatorUserMediaError|MediaStreamError} error
 */
var errorCallback = function(error) {
    console.error(error);
};

navigator.getUserMedia(medias, successCallback, errorCallback);

そして, MediaStreamAudioSourceNodeは, 他のサウンドの入力点となるノード, すなわち, OscillatorNodeやAudioBufferSourceNodeと同様に, AudioDestinationNodeに接続することによって, デバイスから入力されたサウンドを出力することができます.

サンプルコード 05


window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Create the instance of AudioContext
var context = new AudioContext();

navigator.getUserMedia = navigator.getUserMedia       ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;

// Access microphone
var medias = {audio : true, video : false};

/**
 * @param {MediaStream|LocalMediaStream} stream
 */
var successCallback = function(stream) {
    // Create the instance of MediaStreamAudioSourceNode
    var source = context.createMediaStreamSource(stream);

    // MediaStreamAudioSourceNode (Input) -> AudioDestinationNode (Output)
    source.connect(context.destination);
};

/**
 * @param {NavigatorUserMediaError|MediaStreamError} error
 */
var errorCallback = function(error) {
    console.error(error);
};

navigator.getUserMedia(medias, successCallback, errorCallback);

ノード接続

図4 - 2 - b. ノード接続

もちろん, 他のノードを接続することも可能なので, OscillatorNodeやAudioBufferSourceNodeを入力ノードとする場合と同様に, エフェクトをかけたり, ビジュアライゼーションしたりといったことができます.

サンプルコード 06は, デバイスから入力されたサウンドにディレイエフェクトをかけるコードです.

サンプルコード 06


window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Create the instance of AudioContext
var context = new AudioContext();

// for legacy browsers
context.createDelay = context.createDelay || context.createDelayNode;

// for legacy browsers
context.createGain = context.createGain || context.createGainNode;

navigator.getUserMedia = navigator.getUserMedia       ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;

// Access microphone
var medias = {audio : true, video : false};

/**
 * @param {MediaStream|LocalMediaStream} stream
 */
var successCallback = function(stream) {
    // Create the instance of MediaStreamAudioSourceNode
    var source = context.createMediaStreamSource(stream);

    // Create the instance of DelayNode
    var delay = context.createDelay(1);

    // Create the instance of GainNode
    var dry      = context.createGain();  // for gain of original sound
    var wet      = context.createGain();  // for gain of effect (Delay) sound
    var feedback = context.createGain();  // for feedback

    // Set parameters
    delay.delayTime.value = 0.5;  // 0.5 sec
    dry.gain.value        = 0.7;
    wet.gain.value        = 0.3;
    feedback.gain.value   = 0.5;

    // Connect nodes for original sound
    // MediaStreamAudioSourceNode (Input) -> GainNode (Dry) -> AudioDestinationNode (Output)
    source.connect(dry);
    dry.connect(context.destination);

    // Connect nodes for effect (Delay) sound
    // MediaStreamAudioSourceNode (Input) -> DelayNode (Delay) -> GainNode (Wet) -> AudioDestinationNode (Output)
    source.connect(delay);
    delay.connect(wet);
    wet.connect(context.destination);

    // Connect nodes for Feedback
    // (MediaStreamAudioSourceNode (Input) ->) DelayNode (Delay) -> GainNode (Feedback) -> DelayNode (Delay) -> ...
    delay.connect(feedback);
    feedback.connect(delay);
};

/**
 * @param {NavigatorUserMediaError|MediaStreamError} error
 */
var errorCallback = function(error) {
    console.error(error);
};

navigator.getUserMedia(medias, successCallback, errorCallback);

デモ 02においては, MediaStreamAudioSourceNodeにAnayserNodeを接続することによって, デバイスから入力されたサウンドを視覚化しています.

デモ 02