1
1
import recordWorker from './record-worker'
2
2
const URL = window . URL || window . webkitURL
3
- let recorderInstance = null
4
- function Recorder ( ) {
5
- this . config = null
6
- this . recording = false
7
- this . callback = null
8
- this . worker = null
3
+
4
+ const globalProxy = {
5
+ headInstanceReady : false ,
6
+ proxyInstanceCount : 0 ,
7
+ defaultConfig : {
8
+ sampleRate : 48000 , // 采样率(48000),注意:设定的值必须为 48000 的约数
9
+ bufferSize : 4096 , // 缓存大小,用来缓存声音
10
+ sampleBits : 16 , // 采样比特率,8 或 16
11
+ twoChannel : false // 双声道
12
+ } ,
13
+ stream : null ,
14
+ recorderProxy : null ,
15
+ proxyInstance : null
16
+ }
17
+ function throwError ( message ) {
18
+ if ( message . toString ( ) . includes ( 'NotFoundError' ) ) {
19
+ alert ( '未找到可用的录音设备!' )
20
+ return
21
+ }
22
+ console . error ( message )
23
+ }
24
+ class Recorder {
25
+ constructor ( config = { } ) {
26
+ this . config = Object . assign ( { } , globalProxy . defaultConfig , config )
27
+ this . recording = false
28
+ this . callback = null
29
+ this . worker = null
30
+ this . ready = false ,
31
+ this . createTime = new Date ( ) . getTime ( )
32
+ }
9
33
}
10
34
Recorder . prototype = {
11
- ready : function ( ) {
12
- this . proxyInstanceCount ++
13
- document . dispatchEvent ( new Event ( 'recorder-init' ) )
14
- } ,
15
- start : function ( ) {
35
+ start ( ) {
16
36
if ( this . recording ) return
37
+ globalProxy . recorderProxy . onaudioprocess = this . holdBuffer . bind ( this )
17
38
this . recording = true
18
39
} ,
19
- stop : function ( success ) {
40
+
41
+ stop ( success ) {
20
42
if ( ! this . recording ) return
21
43
this . callback = success
22
44
this . recording = false
45
+ globalProxy . recorderProxy . onaudioprocess = null
23
46
} ,
24
- clear : function ( ) {
47
+
48
+ clear ( ) {
25
49
if ( this . recording ) {
26
- this . throwError ( '请先停止录音!' )
50
+ throwError ( '请先停止录音!' )
27
51
return
28
52
}
29
53
this . worker . postMessage ( {
30
54
command : 'clear'
31
55
} )
32
56
} ,
33
- destroy : function ( ) {
34
- this . proxyInstanceCount --
57
+
58
+ destroy ( ) {
59
+ globalProxy . proxyInstanceCount --
35
60
this . config = null
36
61
this . worker && this . worker . terminate ( )
37
62
this . worker = null
38
- if ( this . proxyInstanceCount < 1 ) {
39
- this . recorderProxy = null
40
- if ( this . proxyInstance && this . proxyInstance . state !== 'closed' ) {
41
- this . proxyInstance . suspend ( )
42
- this . proxyInstance . close ( )
43
- this . proxyInstance = null
63
+ this . ready = false
64
+ if ( globalProxy . proxyInstanceCount < 1 ) {
65
+ globalProxy . headInstanceReady = false
66
+ globalProxy . recorderProxy = null
67
+ if ( globalProxy . proxyInstance && globalProxy . proxyInstance . state !== 'closed' ) {
68
+ globalProxy . proxyInstance . suspend ( )
69
+ globalProxy . proxyInstance . close ( )
70
+ globalProxy . proxyInstance = null
44
71
}
45
- this . stream && this . stream . getTracks ( ) . forEach ( track => track . stop ( ) )
46
- this . stream = null
47
- window . isAudioAvailable = this . isAudioAvailable = false
72
+ globalProxy . stream && globalProxy . stream . getTracks ( ) . forEach ( track => track . stop ( ) )
73
+ globalProxy . stream = null
48
74
}
49
- recorderInstance = null
50
75
} ,
51
- handleStream : function ( stream ) {
52
- this . stream = stream
76
+
77
+ handleStream ( stream ) {
78
+ globalProxy . stream = stream
53
79
const channelNumber = this . config . twoChannel ? 2 : 1
54
80
// 创建一个音频环境对象
55
81
const ACProxy = window . AudioContext || window . webkitAudioContext
56
82
if ( ! ACProxy ) {
57
- this . throwError ( '浏览器不支持录音功能!' )
83
+ throwError ( '浏览器不支持录音功能!' )
58
84
return
59
85
}
60
- this . proxyInstance = new ACProxy ( )
86
+ globalProxy . proxyInstance = new ACProxy ( )
61
87
62
- if ( this . proxyInstance . createScriptProcessor ) {
63
- this . recorderProxy = this . proxyInstance . createScriptProcessor ( this . config . bufferSize , channelNumber , channelNumber )
64
- } else if ( recorder . proxyInstance . createJavaScriptNode ) {
65
- this . recorderProxy = this . proxyInstance . createJavaScriptNode ( this . config . bufferSize , channelNumber , channelNumber )
88
+ if ( globalProxy . proxyInstance . createScriptProcessor ) {
89
+ globalProxy . recorderProxy = globalProxy . proxyInstance . createScriptProcessor ( this . config . bufferSize , channelNumber , channelNumber )
90
+ } else if ( globalProxy . proxyInstance . createJavaScriptNode ) {
91
+ globalProxy . recorderProxy = globalProxy . proxyInstance . createJavaScriptNode ( this . config . bufferSize , channelNumber , channelNumber )
66
92
} else {
67
- this . throwError ( '浏览器不支持录音功能!' )
93
+ throwError ( '浏览器不支持录音功能!' )
68
94
}
69
95
70
96
// 将声音输入这个对像
71
- const audioInputSource = this . proxyInstance . createMediaStreamSource ( this . stream )
97
+ const audioInputSource = globalProxy . proxyInstance . createMediaStreamSource ( globalProxy . stream )
72
98
73
- audioInputSource . connect ( this . recorderProxy )
74
- this . recorderProxy . connect ( audioInputSource . context . destination )
99
+ audioInputSource . connect ( globalProxy . recorderProxy )
100
+ globalProxy . recorderProxy . connect ( audioInputSource . context . destination )
75
101
76
- this . ready ( )
102
+ this . ready = true
77
103
78
- this . recorderProxy . onaudioprocess = this . holdBuffer . bind ( this )
79
-
80
- window . isAudioAvailable = this . isAudioAvailable = true
104
+ globalProxy . headInstanceReady = true
81
105
} ,
82
- init : function ( config = { } ) {
83
- this . config = Object . assign ( { } , this . defaultConfig , config )
106
+
107
+ init ( ) {
108
+ if ( globalProxy . proxyInstanceCount && ! globalProxy . headInstanceReady ) {
109
+ const waitHeadInstance = this
110
+ requestAnimationFrame ( function ( ) {
111
+ waitHeadInstance . init ( )
112
+ } )
113
+ // console.info('wait head instance')
114
+ return
115
+ }
116
+ globalProxy . proxyInstanceCount ++
84
117
85
118
// 加载并启动 record worker
86
119
let workerString = recordWorker . toString ( )
@@ -91,7 +124,7 @@ Recorder.prototype = {
91
124
const workerURL = URL . createObjectURL ( workerBlob )
92
125
this . worker = new Worker ( workerURL )
93
126
URL . revokeObjectURL ( workerURL )
94
-
127
+
95
128
const instance = this
96
129
this . worker . onmessage = function ( e ) {
97
130
instance . callback && instance . callback ( e . data )
@@ -102,8 +135,8 @@ Recorder.prototype = {
102
135
config : this . config
103
136
} )
104
137
105
- if ( this . recorderProxy ) {
106
- this . ready ( )
138
+ if ( globalProxy . recorderProxy ) {
139
+ this . ready = true
107
140
} else {
108
141
if ( ! navigator . mediaDevices ) {
109
142
navigator . mediaDevices = { }
@@ -120,59 +153,42 @@ Recorder.prototype = {
120
153
} )
121
154
}
122
155
}
123
- navigator . mediaDevices . getUserMedia ( { audio : true , video : false } ) . then ( this . handleStream . bind ( this ) ) . catch ( this . throwError )
124
- }
125
- } ,
126
- defaultConfig : {
127
- sampleRate : 48000 , // 采样率(48000),注意:设定的值必须为 48000 的约数
128
- bufferSize : 4096 , // 缓存大小,用来缓存声音
129
- sampleBits : 16 , // 采样比特率,8 或 16
130
- twoChannel : false // 双声道
131
- } ,
132
- proxyInstanceCount : 0 ,
133
- stream : null ,
134
- recorderProxy : null ,
135
- proxyInstance : null ,
136
- holdBuffer : function ( e ) {
137
- if ( this . recording ) {
138
- const data = e . inputBuffer
139
- const buffer = ! this . config . twoChannel ? [
140
- data . getChannelData ( 0 )
141
- ] : [
142
- data . getChannelData ( 0 ) ,
143
- data . getChannelData ( 1 )
144
- ]
145
- this . worker . postMessage ( {
146
- command : 'record' ,
147
- buffer
148
- } )
156
+ navigator . mediaDevices . getUserMedia ( { audio : true , video : false } ) . then ( this . handleStream . bind ( this ) ) . catch ( throwError )
149
157
}
150
158
} ,
151
- exportWAV : function ( success , type ) {
159
+
160
+ exportWAV ( success , type ) {
152
161
this . callback = success
153
162
type = type || this . config . type || 'audio/wav'
154
163
this . worker . postMessage ( {
155
164
command : 'exportWAV' ,
156
165
type
157
166
} )
158
167
} ,
159
- getSource : function ( ) {
168
+
169
+ getSource ( ) {
160
170
return new Promise ( ( resolve ) => {
161
171
this . exportWAV ( function ( data ) {
162
172
resolve ( data )
163
173
} , 'audio/wav' )
164
174
} )
165
175
} ,
166
- throwError : ( this . config && this . config . error ) || function ( message ) {
167
- if ( message . toString ( ) . includes ( 'NotFoundError' ) ) {
168
- alert ( '未找到可用的录音设备!' )
169
- return
176
+
177
+ holdBuffer ( e ) {
178
+ if ( this . recording ) {
179
+ const data = e . inputBuffer
180
+ const buffer = ! this . config . twoChannel ? [
181
+ data . getChannelData ( 0 )
182
+ ] : [
183
+ data . getChannelData ( 0 ) ,
184
+ data . getChannelData ( 1 )
185
+ ]
186
+ this . worker . postMessage ( {
187
+ command : 'record' ,
188
+ buffer
189
+ } )
170
190
}
171
- console . error ( message )
172
- } ,
173
- isAudioAvailable : false
191
+ }
174
192
}
175
193
176
- recorderInstance = new Recorder ( )
177
-
178
- export default recorderInstance
194
+ export default Recorder
0 commit comments