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

37 篇文章 0 订阅
24 篇文章 0 订阅

http://www.cnblogs.com/holybozo/archive/2010/06/26/1765943.html

 

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
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已经可以做到了~~~
有些朋友问我要源码,虽然都贴出来了,不过想象几个外部类包的调用和配置还是比较无聊的。 [点此下载]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值