Flash Player 10.1 终实现本地线上录制MP3

Flash Player 10.1 可以获取麦克风数据了,所以可以实现本地录音。(不知道啥时候Adobe能开发本路录像,估计怕FMS卖不掉?)

但光凭FP10.1,只能实现即录即放,没法保存。如果要保存,又是另外一个课题了——音频编码。

adobe这篇文章里提供了一个WAVWriter,可以把ByteArray转成WAV文件。执行起来是同步的,效率上还不错,因为wav本身就是无损格式,也正因为如此,保存成wav文件太大,总归不太好。理想的是MP3...

Thibault Imbert利用AIR2的新特性,可以运行一个本地程序,这样调用鼎鼎大名的Lame来转MP3就OK了。

借用AIR还不够让人兴奋,因为这和在线项目无缘。那么利用Alchemy打包Lame呢?这个想法近似疯狂,但却衍生出一个靠谱的方法

Shine MP3 Encoder on Alchemy

是用Alchemy打包了一个叫8hz-MP3的轻量级MP3编码器,这样一来就能够脱离AIR实现WAV转MP3了。

作者提供了swc,加上之前adobe提供的WAVWriter,组合起来写了一个保存录音的demo

package 
{
	import com.adobe.audio.format.WAVWriter;
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.ProgressEvent;
	import flash.events.SampleDataEvent;
	import flash.media.Microphone;
	import flash.media.Sound;
	import flash.text.TextField;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;
	import fr.kikko.lab.ShineMP3Encoder;
	
	/**
	 * ...
	 * @author hbb
	 */
	public class Main extends Sprite 
	{
		private var _mic:Microphone;
		private var _voice:ByteArray;
		private var _mp3Encoder:ShineMP3Encoder;
		
		private var _state:String;
		private var _timer:int;
		
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
		}
		
		private function onAddedToStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			init();
		}
		
		private function init():void
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.stageFocusRect = false;
			
			if (!setupMicrophone()) return;
			
			stage.addEventListener(KeyboardEvent.KEY_UP, commandHandler);
			
			_state = 'pre-recording';
			
			log('press <key>: <r>ecord');
		}
		
		private function setupMicrophone():Boolean
		{
			_mic = Microphone.getMicrophone();
			if (!_mic) { log('no michrophone!'); return false; }
			
			_mic.rate = 44;
			_mic.setSilenceLevel(0, 1000);
			_mic.setLoopBack(true);
			_mic.setUseEchoSuppression(true);
			return true;
		}
		
		private function commandHandler(e:KeyboardEvent):void 
		{
			switch(String.fromCharCode(e.charCode))
			{
				case 'r':
					startRecording();
					break;
					
				case 'e':
					stopAndEncodeRecording();
					break;
					
				case 's':
					saveMP3();
					break;
			}
		}
		
		private function saveMP3():void
		{
			if (_state != 'encoded') return;
			
			_mp3Encoder.saveAs();
			_state = 'pre-recording';
		}
		
		private function startRecording():void
		{
			if (_state != 'pre-recording' && _state != 'encoded') return;
			
			log('press <key>: stop and <e>ncode recording');
			
			_state = 'pre-encoding';
			_voice = new ByteArray();
			_mic.addEventListener(SampleDataEvent.SAMPLE_DATA, onRecord);
		}
		
		private function stopAndEncodeRecording():void
		{
			if (_state != 'pre-encoding') return;
			
			_state = 'encoding';
			_mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, onRecord);
			
			_voice.position = 0;
			
			log('encode start...synchronous convert to a WAV first');
			
			convertToMP3();
		}
		
		private function convertToMP3():void 
		{
			var wavWrite:WAVWriter = new WAVWriter();
			wavWrite.numOfChannels = 1;
			wavWrite.sampleBitRate = 16;
			wavWrite.samplingRate = 44100;
			
			var wav:ByteArray = new ByteArray();
			
			_timer = getTimer();
			wavWrite.processSamples(wav, _voice, 44100, 1);
			log('convert to a WAV used: ' + (getTimer() - _timer) + 'ms');
			
			wav.position = 0;
			log('WAV size:' + wav.bytesAvailable + ' bytes');
			log('Asynchronous convert to MP3 now');
			
			_timer = getTimer();
			_mp3Encoder = new ShineMP3Encoder( wav );
			_mp3Encoder.addEventListener(Event.COMPLETE, onEncoded);
			_mp3Encoder.addEventListener(ProgressEvent.PROGRESS, onEncoding);
			_mp3Encoder.addEventListener(ErrorEvent.ERROR, onEncodeError);
			_mp3Encoder.start();
		}
		
		private function onEncoded(e:Event):void 
		{
			_state = 'encoded';
			log('encode MP3 complete used: ' + (getTimer() - _timer) + 'ms');
			_mp3Encoder.mp3Data.position = 0;
			log('MP3 size:' + _mp3Encoder.mp3Data.bytesAvailable + ' bytes');
			log('press <key>: <s>ave to MP3 or <r>ecord again');
		}
		
		private function onEncoding(e:ProgressEvent):void 
		{
			log('encoding MP3... ' + Number(e.bytesLoaded / e.bytesTotal * 100).toFixed(2) + '%', true);
		}
		
		private function onEncodeError(e:ErrorEvent):void 
		{
			log('encode MP3 error ' + e.text);
		}
		
		private function onRecord(e:SampleDataEvent):void 
		{
			_voice.writeBytes( e.data );
			
			var str:String = '';
			for (var i:int = _mic.activityLevel; i--;)
			{
				str += '*';
			}
			log('recoding ' + str, true);
		}
		
		private function log(msg:String, updateInPlace:Boolean = false):void
		{
			var txt:TextField = getChildByName('logTxt') as TextField;
			if (txt)
			{
				if (updateInPlace)
				{
					if (txt.text.substr( -1, 1) == '\r')
					{
						txt.text = txt.text.substr( 0, txt.text.lastIndexOf('\r', txt.text.length - 2) );
					}
					txt.appendText('\n' + msg + '\n');
				}
				else
				{
					txt.appendText((txt.text.substr(-1,1) == '\r' ? '' : '\n') + msg);
				}
				txt.scrollV = txt.maxScrollV;
			}
			else
			{
				txt = new TextField();
				txt.name = 'logTxt';
				txt.multiline = true;
				txt.border = true;
				txt.borderColor = 0x666666;
				txt.width = stage.stageWidth - 20;
				txt.height = stage.stageHeight - 20;
				txt.x = txt.y = 10;
				txt.text = msg;
				addChild(txt);
			}
		}
	}
	
}
用下来,性能上没问题,转WAV虽然是同步的,但不实现压缩,效率上可以接受。录2分钟、12M大小的WAV,比转个800x600的JPG要快多了。转MP3是异步的,效率上没问题,只是目前没法更好的进行压缩设置。
如此,本地线上录音并保存MP3的功能,Flash已经可以做到了~~~
有些朋友问我要源码,虽然都贴出来了,不过想象几个外部类包的调用和配置还是比较无聊的。 [点此下载]

转载于:https://www.cnblogs.com/holybozo/archive/2010/06/26/1765943.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值