3
3
define ( function ( require ) {
4
4
var p5sound = require ( 'master' ) ;
5
5
6
+ // an array of input sources
7
+ p5sound . inputSources = [ ] ;
8
+
6
9
/**
7
10
* <p>Get audio from an input, i.e. your computer's microphone.</p>
8
11
*
@@ -45,8 +48,7 @@ define(function (require) {
45
48
46
49
this . stream = null ;
47
50
this . mediaStream = null ;
48
-
49
- this . currentSource = 0 ;
51
+ this . currentSource = null ;
50
52
51
53
/**
52
54
* Client must allow browser to access their microphone / audioin source.
@@ -60,18 +62,8 @@ define(function (require) {
60
62
this . amplitude = new p5 . Amplitude ( ) ;
61
63
this . output . connect ( this . amplitude . input ) ;
62
64
63
- // Some browsers let developer determine their input sources
64
- if ( typeof window . MediaStreamTrack === 'undefined' ) {
65
- if ( errorCallback ) {
66
- errorCallback ( ) ;
67
- } else {
68
- window . alert ( 'This browser does not support AudioIn' ) ;
69
- }
70
- } else if ( typeof window . MediaDevices . enumerateDevices === 'function' ) {
71
- // Chrome supports getSources to list inputs. Dev picks default
72
- window . MediaDevices . enumerateDevices ( this . _gotSources ) ;
73
- } else {
74
- // Firefox has no getSources() but lets user choose their input
65
+ if ( ! window . MediaStreamTrack || ! window . navigator . mediaDevices || ! window . navigator . mediaDevices . getUserMedia ) {
66
+ errorCallback ? errorCallback ( ) : window . alert ( 'This browser does not support MediaStreamTrack and mediaDevices' ) ;
75
67
}
76
68
77
69
// add to soundArray so we can dispose on close
@@ -100,50 +92,39 @@ define(function (require) {
100
92
p5 . AudioIn . prototype . start = function ( successCallback , errorCallback ) {
101
93
var self = this ;
102
94
103
- // if stream was already started...
95
+ if ( this . stream ) {
96
+ this . stop ( ) ;
97
+ }
104
98
99
+ // set the audio source
100
+ var audioSource = p5sound . inputSources [ self . currentSource ] ;
101
+ var constraints = {
102
+ audio : {
103
+ sampleRate : p5sound . audiocontext . sampleRate ,
104
+ echoCancellation : false
105
+ }
106
+ } ;
105
107
106
- // if _gotSources() i.e. developers determine which source to use
107
- if ( p5sound . inputSources [ self . currentSource ] ) {
108
- // set the audio source
109
- var audioSource = p5sound . inputSources [ self . currentSource ] . id ;
110
- var constraints = {
111
- audio : {
112
- optional : [ { sourceId : audioSource } ]
113
- } } ;
114
- window . navigator . getUserMedia ( constraints ,
115
- this . _onStream = function ( stream ) {
116
- self . stream = stream ;
117
- self . enabled = true ;
118
- // Wrap a MediaStreamSourceNode around the live input
119
- self . mediaStream = p5sound . audiocontext . createMediaStreamSource ( stream ) ;
120
- self . mediaStream . connect ( self . output ) ;
121
- if ( successCallback ) successCallback ( ) ;
122
- // only send to the Amplitude reader, so we can see it but not hear it.
123
- self . amplitude . setInput ( self . output ) ;
124
- } , this . _onStreamError = function ( e ) {
125
- if ( errorCallback ) errorCallback ( e ) ;
126
- else console . error ( e ) ;
127
- } ) ;
128
- } else {
129
- // if Firefox where users select their source via browser
130
- // if (typeof MediaStreamTrack.getSources === 'undefined') {
131
- // Only get the audio stream.
132
- window . navigator . getUserMedia ( { 'audio' :true } ,
133
- this . _onStream = function ( stream ) {
134
- self . stream = stream ;
135
- self . enabled = true ;
136
- // Wrap a MediaStreamSourceNode around the live input
137
- self . mediaStream = p5sound . audiocontext . createMediaStreamSource ( stream ) ;
138
- self . mediaStream . connect ( self . output ) ;
139
- // only send to the Amplitude reader, so we can see it but not hear it.
140
- self . amplitude . setInput ( self . output ) ;
141
- if ( successCallback ) successCallback ( ) ;
142
- } , this . _onStreamError = function ( e ) {
143
- if ( errorCallback ) errorCallback ( e ) ;
144
- else console . error ( e ) ;
145
- } ) ;
108
+ // if developers determine which source to use
109
+ if ( p5sound . inputSources [ this . currentSource ] ) {
110
+ constraints . audio . deviceId = audioSource . deviceId ;
146
111
}
112
+
113
+ window . navigator . mediaDevices . getUserMedia ( constraints )
114
+ . then ( function ( stream ) {
115
+ self . stream = stream ;
116
+ self . enabled = true ;
117
+ // Wrap a MediaStreamSourceNode around the live input
118
+ self . mediaStream = p5sound . audiocontext . createMediaStreamSource ( stream ) ;
119
+ self . mediaStream . connect ( self . output ) ;
120
+ // only send to the Amplitude reader, so we can see it but not hear it.
121
+ self . amplitude . setInput ( self . output ) ;
122
+ if ( successCallback ) successCallback ( ) ;
123
+ } )
124
+ . catch ( function ( err ) {
125
+ if ( errorCallback ) errorCallback ( err ) ;
126
+ else console . error ( err ) ;
127
+ } ) ;
147
128
} ;
148
129
149
130
/**
@@ -154,8 +135,14 @@ define(function (require) {
154
135
*/
155
136
p5 . AudioIn . prototype . stop = function ( ) {
156
137
if ( this . stream ) {
157
- // assume only one track
158
- this . stream . getTracks ( ) [ 0 ] . stop ( ) ;
138
+ this . stream . getTracks ( ) . forEach ( function ( track ) {
139
+ track . stop ( ) ;
140
+ } ) ;
141
+
142
+ this . mediaStream . disconnect ( ) ;
143
+
144
+ delete this . mediaStream ;
145
+ delete this . stream ;
159
146
}
160
147
} ;
161
148
@@ -216,22 +203,6 @@ define(function (require) {
216
203
return this . amplitude . getLevel ( ) ;
217
204
} ;
218
205
219
- /**
220
- * Add input sources to the list of available sources.
221
- *
222
- * @private
223
- */
224
- p5 . AudioIn . prototype . _gotSources = function ( sourceInfos ) {
225
- for ( var i = 0 ; i < sourceInfos . length ; i ++ ) {
226
- var sourceInfo = sourceInfos [ i ] ;
227
- if ( sourceInfo . kind === 'audio' ) {
228
- // add the inputs to inputSources
229
- //p5sound.inputSources.push(sourceInfo);
230
- return sourceInfo ;
231
- }
232
- }
233
- } ;
234
-
235
206
/**
236
207
* Set amplitude (volume) of a mic input between 0 and 1.0. <br/>
237
208
*
@@ -252,31 +223,20 @@ define(function (require) {
252
223
}
253
224
} ;
254
225
255
- p5 . AudioIn . prototype . listSources = function ( ) {
256
- console . log ( 'listSources is deprecated - please use AudioIn.getSources' ) ;
257
- console . log ( 'input sources: ' ) ;
258
- if ( p5sound . inputSources . length > 0 ) {
259
- return p5sound . inputSources ;
260
- } else {
261
- return 'This browser does not support MediaStreamTrack.getSources()' ;
262
- }
263
- } ;
264
226
/**
265
- * Chrome only. Returns a list of available input sources
266
- * and allows the user to set the media source. Firefox allows
267
- * the user to choose from input sources in the permissions dialogue
268
- * instead of enumerating available sources and selecting one.
269
- * Note: in order to have descriptive media names your page must be
270
- * served over a secure (HTTPS) connection and the page should
271
- * request user media before enumerating devices. Otherwise device
272
- * ID will be a long device ID number and does not specify device
273
- * type. For example see
274
- * https://simpl.info/getusermedia/sources/index.html vs.
275
- * http://simpl.info/getusermedia/sources/index.html
227
+ * Returns a list of available input sources. This is a wrapper
228
+ * for <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href=
229
+ * "https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices"
230
+ * > and it returns a Promise.
276
231
*
277
232
* @method getSources
278
- * @param {Function } callback a callback to handle the sources
279
- * when they have been enumerated
233
+ * @param {Function } [successCallback] This callback function handles the sources when they
234
+ * have been enumerated. The callback function
235
+ * receives the deviceList array as its only argument
236
+ * @param {Function } [errorCallback] This optional callback receives the error
237
+ * message as its argument.
238
+ * @returns {Promise } Returns a Promise that can be used in place of the callbacks, similar
239
+ * to the enumerateDevices() method
280
240
* @example
281
241
* <div><code>
282
242
* var audiograb;
@@ -285,51 +245,62 @@ define(function (require) {
285
245
* //new audioIn
286
246
* audioGrab = new p5.AudioIn();
287
247
*
288
- * audioGrab.getSources(function(sourceList ) {
248
+ * audioGrab.getSources(function(deviceList ) {
289
249
* //print out the array of available sources
290
- * console.log(sourceList );
291
- * //set the source to the first item in the inputSources array
250
+ * console.log(deviceList );
251
+ * //set the source to the first item in the deviceList array
292
252
* audioGrab.setSource(0);
293
253
* });
294
254
* }
295
255
* </code></div>
296
256
*/
297
- p5 . AudioIn . prototype . getSources = function ( callback ) {
298
- if ( typeof window . MediaStreamTrack . getSources === 'function' ) {
299
- window . MediaStreamTrack . getSources ( function ( data ) {
300
- for ( var i = 0 , max = data . length ; i < max ; i ++ ) {
301
- var sourceInfo = data [ i ] ;
302
- if ( sourceInfo . kind === 'audio' ) {
303
- // add the inputs to inputSources
304
- p5sound . inputSources . push ( sourceInfo ) ;
257
+ p5 . AudioIn . prototype . getSources = function ( onSuccess , onError ) {
258
+ return new Promise ( function ( resolve , reject ) {
259
+ window . navigator . mediaDevices . enumerateDevices ( )
260
+ . then ( function ( devices ) {
261
+ p5sound . inputSources = devices . filter ( function ( device ) {
262
+ return device . kind === 'audioinput' ;
263
+ } ) ;
264
+ resolve ( p5sound . inputSources ) ;
265
+ if ( onSuccess ) {
266
+ onSuccess ( p5sound . inputSources ) ;
305
267
}
306
- }
307
- callback ( p5sound . inputSources ) ;
308
- } ) ;
309
- } else {
310
- console . log ( 'This browser does not support MediaStreamTrack.getSources()' ) ;
311
- }
268
+ } )
269
+ . catch ( function ( error ) {
270
+ reject ( error ) ;
271
+ if ( onError ) {
272
+ onError ( error ) ;
273
+ } else {
274
+ console . error ( 'This browser does not support MediaStreamTrack.getSources()' ) ;
275
+ }
276
+ } ) ;
277
+ } ) ;
312
278
} ;
279
+
313
280
/**
314
281
* Set the input source. Accepts a number representing a
315
- * position in the array returned by listSources ().
282
+ * position in the array returned by getSources ().
316
283
* This is only available in browsers that support
317
- * MediaStreamTrack.getSources(). Instead, some browsers
318
- * give users the option to set their own media source.<br/>
284
+ * <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href=
285
+ * "https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices"
286
+ * >navigator.mediaDevices.enumerateDevices()</a>.<br/>
319
287
*
320
288
* @method setSource
321
289
* @param {number } num position of input source in the array
322
290
*/
323
291
p5 . AudioIn . prototype . setSource = function ( num ) {
324
- // TO DO - set input by string or # (array position)
325
- var self = this ;
326
292
if ( p5sound . inputSources . length > 0 && num < p5sound . inputSources . length ) {
327
293
// set the current source
328
- self . currentSource = num ;
329
- console . log ( 'set source to ' + p5sound . inputSources [ self . currentSource ] . id ) ;
294
+ this . currentSource = num ;
295
+ console . log ( 'set source to ' , p5sound . inputSources [ this . currentSource ] ) ;
330
296
} else {
331
297
console . log ( 'unable to set input source' ) ;
332
298
}
299
+
300
+ // restart stream if currently active
301
+ if ( this . stream && this . stream . active ) {
302
+ this . start ( ) ;
303
+ }
333
304
} ;
334
305
335
306
// private method
@@ -339,14 +310,15 @@ define(function (require) {
339
310
p5sound . soundArray . splice ( index , 1 ) ;
340
311
341
312
this . stop ( ) ;
313
+
342
314
if ( this . output ) {
343
315
this . output . disconnect ( ) ;
344
316
}
345
317
if ( this . amplitude ) {
346
318
this . amplitude . disconnect ( ) ;
347
319
}
348
- this . amplitude = null ;
349
- this . output = null ;
320
+ delete this . amplitude ;
321
+ delete this . output ;
350
322
} ;
351
323
352
324
} ) ;
0 commit comments