通过flash+js 实现web中录音 FlashWavRecorder

最近在做一个小网站,其中有一个语音识别的功能,我暂时打算用Google Speech API来实现,但是在这之前还有一个小问题那就是录音。要在网页中录音应该大多数是通过Flash或者java applet实现的,因为考虑到flash比较普及,我觉得采用flash。因为我本身不会flash actionscript那些,想在网上找个现成,功夫不负有心人终于让我找到了这个FlashWavRecorder。其github地址为:https://github.com/cykod/FlashWavRecorder

这个项目你一个有两文件夹flash和html,flash文件夹中是文件,html文件夹中是一个示例,试了一下果然能录音。
但是上传却出了问题,卡在save_progress了。

找了一会儿原因,发现是接受上传文件的upload.php有个小问题,他的<? 后面没有php导致直接把所有代码当文本返回了。改完之后如下:

<?php
$save_folder = dirname(__FILE__) . "/audio";
if(! file_exists($save_folder)) {
  if(! mkdir($save_folder)) {

首先下面的配置对我来说并不需要,我把它直接删了,但是问题就出现了。

 

发生这个问题的原因是index.html 中有一段js脚本

$(function() {
  var gain = $('#gain')[0];
  var silenceLevel = $('#silenceLevel')[0];
  for(var i=0; i<=100; i++) {
    gain.options[gain.options.length] = new Option(100-i);
    silenceLevel.options[silenceLevel.options.length] = new Option(i);
  }

  var appWidth = 24;
  var appHeight = 24;
  var flashvars = {'event_handler': 'microphone_recorder_events', 'upload_image': 'images/upload.png'};
  var params = {};
  var attributes = {'id': "recorderApp", 'name':  "recorderApp"};
  swfobject.embedSWF("recorder.swf", "flashcontent", appWidth, appHeight, "11.0.0", "", flashvars, params, attributes);
});

因为我把配置的表单删掉了,所以$(‘#gain’)[0]和$(‘#silenceLevel’)[0]都是undefined的,对它们进行操作报错脚本终止导致flash没有成功加载,把那下面这5行删掉即可。

  var gain = $('#gain')[0];
  var silenceLevel = $('#silenceLevel')[0];
  for(var i=0; i<=100; i++) {
    gain.options[gain.options.length] = new Option(100-i);
    silenceLevel.options[silenceLevel.options.length] = new Option(i);
  }

总的来说这个东西就是js调用flash的js接口,flash里再调用js与页面交互。

位于recorder.js文件的microphone_recorder_events函数就是处理flash返回状态的函数。
通过修改这个函数可以修改flash不同状态事页面的显示。

因为这个flash每次刷新页面后都要点一下录音按键后允许flash使用麦克风才行,我想省掉要先点录音按键这一步,页面刷新有自动弹出麦克风请求窗口。其实只要还microphone_recorder_events中case “ready” 这个分支的最后加一行Recorder.record(‘audio’, ‘audio.wav’);即可,因为点击那个红色的录音键实际上也是执行了这句脚本。

 case "ready":
    var width = parseInt(arguments[1]);
    var height = parseInt(arguments[2]);
    Recorder.uploadFormId = "#uploadForm";
    Recorder.uploadFieldName = "upload_file[filename]";
    Recorder.connect("recorderApp", 0);
    Recorder.recorderOriginalWidth = width;
    Recorder.recorderOriginalHeight = height;
    $('#play_button').css({'margin-left': width + 8});
    $('#save_button').css({'width': width, 'height': height});
    Recorder.record('audio', 'audio.wav'); //在示例中改成$("#record_button").click();也行
  break;

最后我想实现停止录音后直接上传该怎么修改呢?

这个上传按键并不是一个html元素,而是在flash中的,这意味着我不得不去修改flash了。

flash文件夹下有4个as文件,因为只是要改一小点我就直接看RecorderJSInterface.as这个文件了,果然和文件名一样这个文件定义了js调用的入口,还有通过ExternalInterface.call(methodName: String, [parameter1: Object]) : Object 方法调用页面中的js。

话不多说,我在这个文件中找到两个关键的方法record(name:String, filename:String=null):Boolean 和 save():Boolean 一个是录音是调用的,第二个是保存(就是上传服务器)时调用的。这样在record中停止录音的语句后调用sava方法即可,修改后如下:

    public function record(name:String, filename:String=null):Boolean {
      if(! this.isMicrophoneAvailable()) {
        return false;
      }

      if(this.recorder.recording) {
        this.recorder.stop();
        ExternalInterface.call(this.eventHandler, RecorderJSInterface.RECORDING_STOPPED, this.recorder.currentSoundName, this.recorder.duration());
        this.save();   //加入这句
      } else {
        this.recorder.record(name, filename);
        ExternalInterface.call(this.eventHandler, RecorderJSInterface.RECORDING, this.recorder.currentSoundName);
      }

      return this.recorder.recording;
    }

接下来就是编译它了,先去下载sdk,下载地址为http://www.adobe.com/devnet/flex/flex-sdk-download-all.html

下载完成后把其中的bin目录加入环境变量PATH,打开命令行到刚刚的flash目录执行下面语句。

mxmlc Recorder.as -output recorder.swf

把生成的recorder.swf覆盖html中的,刷新页面,虽然停止录音后进行了保存但是出现了异常

 

但是再点击上传按钮却能成功上传,我检查代码,发现是执行URLLoader.load(request:URLRequest):void时发生了异常,推测是出于安全问题,只能通过用户交互来调用。那我们就来再改一下吧。

先把recorder.as里的ready方法和save()方法改一下,改成下面这样:

   public function ready():void {
      addChild(saveButton);

      recorderInterface.saveButton = saveButton;

      saveButton.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);

      recorderInterface.ready(saveButton.width, saveButton.height);
    }

    public function save():void {
      recorderInterface.record("audio", "audio.wav");
    }

再把RecorderJSInterface.as里show()和hide()方法的函数体变成空的,如下:

    public function show():void {

    }
    public function hide():void {

    }

再编译一下搞定,直接点上传键就录音加上传一条龙了。

posted @ 2013-07-25 14:07  Horizon↗  阅读(8997)  评论(7编辑  收藏  举报