WEBで録音を実現する「WAMI recorder」が便利すぎてワラタ

マイクのイラストWEBサイトに録音機能を追加したくてリサーチ開始。Flashで簡単に出来そうだと軽い気持ちで。しかしFlashでマイクを認識するまではいいが、録音データをクライアントに溜められないのでストリーミングサーバーを用意する必要があった。

ストリーミングサーバーは高価なFlashMediaServerかフリーのRed5。Red5を使う場合、開発はサーバー側がJavaでクライアント側はAS3。「ただ録音するだけなのに・・・」という感じ。(´・ω・`)

しかしFlashプラグイン10.1からクライアントに録音データを溜められるようになりストリーミングが必要なくなった事を知る。さらに手軽に録音できる「WAMI recorder」ライブラリを発見→録音機能あっという間に実装完了!そんなわけで「WAMI recorder」を紹介したいと思います。

 

出来上がりサンプル

デザインまで入れた状態のサンプルです。Flashの動作を許可すれば実際に録音できます。WAMIはJavascriptとSWFで動いています。デザインはbootstrapとJustGageを使いました。bootstrapのデザインについては解説する必要はないと思うので、説明はWAMIとJustGageのみに削ぎ落したソースを使います。

 

下準備

まずはWAMIとJustGageから必要なファイルをダウンロード。

WAMIには標準のGUI(gui.js)がついていますが、GUIは0から組むので必要なファイルは Wami.swf と recorder.js の2つです。

justGageで必要なファイルは justgage.1.0.1.min.js と raphael.2.1.0.min.js の2つ。

こちらで作成するのは index.html と wami.js と save.php の3ファイル、合計7ファイルを用意します。save.php は WAMI公式サイトのサンプルままです。WAMIはFLASHなのでファイルを直接ブラウザで表示しても動作しません。ローカルでもHTTPアクセスで。

 

HTML

まずHTMLですが、最低限の操作ボタンとWAMIとJustGageの為のdivを作っておきます。#wamiにはWami.setupでswfが入ってきます。

swfobject.js は WAMI に、raphael.js は JustGage に必要です。

index.html
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="recorder" style="width: 340px; text-align: center;">
    <button id="record" onclick="clickRecord()">録音</button>
    <button id="stop" onclick="clickStop()">停止</button>
    <button id="play" onclick="clickPlay()">再生</button>
    <div id="wami"></div>
    <div id="meter" style="width: 340px; height: 200px;"></div> <!--justgageはサイズ指定必須-->
</div>
<script src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script src="recorder.js"></script>
<script src="raphael.2.1.0.min.js"></script>
<script src="justgage.1.0.1.min.js"></script>
<script src="wami.js"></script>
</body>
</html>

 

JavaScript

各設定をグローバル変数で定義し、Wami.setupでWamiの初期化。操作ボタンのクリックに応じてWAMIの関数を実行しています。

ポイントは

  • recordStart 内の setTimeout で最大録音時間を設定する
  • setInterval で JustGage を動かす(戻り値は0-100)
  • キャッシュが再生されるのを回避する

という感じです。動作には変数hostを定義する必要があります。

wami.js
var mode;
var timeLimit=10; // 録音制限 秒
var host = 'save.phpがあるURL'; // http://localhost/wami/ 等
var recording = 'temp.wav'; // ファイル名
var recordInterval, playInterval;
var gage = new JustGage({
    id: 'meter', 
    value: 0,
    min: 0, // wamiのlevel戻り値は0-100
    max: 100,
    showMinMax: false,
    title: 'Ready'
}); 

Wami.setup({id:'wami'});

function clickRecord(){
    mode = 'record';
    var recordingUrl = host+'save.php?name='+recording;
    Wami.startRecording(recordingUrl,Wami.nameCallback(recordStart),Wami.nameCallback(recordFinish),Wami.nameCallback(wamiError));
}

function stopRecording(){
    Wami.stopRecording();
    recordFinish();
}

function recordStart(){
    setTimeout('stopRecording()',timeLimit * 1000);  // 録音時間制限
    recordInterval = setInterval(function(){
        var level = Wami.getRecordingLevel();
        updateMeter(level);
    },100);
}

function recordFinish(){
    clearInterval(recordInterval);
    updateMeter(0);
}

function clickPlay(){
    mode = 'play';
    var playUrl = host+recording+'?_='+(new Date)/1; // キャッシュ回避
    Wami.startPlaying(playUrl,Wami.nameCallback(playStart),Wami.nameCallback(playFinish),Wami.nameCallback(wamiError));
}

function stopPlaying(){
    Wami.stopPlaying();
    playFinish();
}

function playStart(){
    playInterval = setInterval(function(){
        var level = Wami.getPlayingLevel();
        updateMeter(level);
    },100);
}

function playFinish(){
    clearInterval(playInterval);
    updateMeter(0);
}

function clickStop(){
    if ( mode == 'record' ){
        stopRecording();
    } else if ( mode == 'play' ){
        stopPlaying();
    }
}

function wamiError( e ){
    alert(e);
}

function updateMeter( level ){
    gage.refresh(level);
}

 

PHP

POST送信される音声データをファイル化するPHPです。公式サイトのものですが必要最低限ですので、運用する場合は容量制限などが必要です。

save.php
<?php
    parse_str($_SERVER['QUERY_STRING'], $params);
    $name = isset($params['name']) ? $params['name'] : 'output.wav';
    $content = file_get_contents('php://input');
    $fh = fopen($name, 'w') or die("can't open file");
    fwrite($fh, $content);
?>

出力されるファイル形式はwav。フォーマットは

  • サンプリングレート 22.05kHz
  • 量子化ビット 16ビット
  • モノラル

です。現行バージョンのWAMIはフォーマットの変更が出来ないようです。

wavファイルのサイズ計算は、22050*16 を バイト化 / 8 で 44100 Byte/sec ですので、容量制限を行う場合は、

if ( $sec * 44100 < strlen($content) ){ exit; } [/code]

上のソースを file_get_contents の後に追加すれば、指定秒数を超えたデータは保存されません。

 

課題

WAMIはクライアントサイドで大きなファイルを扱う都合上、待ちが発生してモッサリ動作です。これはRed5などのストリーミングで解決するしかありません。

サーバー容量の問題もあります。サーバー側で定期的にmp3等の圧縮音源にエンコすれば解決しそうですが、再生は他のプレイヤーを使う必要がでてきます。でも、これだけ手軽に録音機能を構築できるWAMIは凄いです。(・∀・)

 

プログラミングで悩んだ時は

93%の回答率が売りのエンジニアのための無料Q&Aサイト「teratail」。長く悩んでも答えが出ない時の為に、登録しておけば助かるかもしれません。