33define ( function ( require ) {
44 var p5sound = require ( 'master' ) ;
55
6+ // an array of input sources
7+ p5sound . inputSources = [ ] ;
8+
69 /**
710 * <p>Get audio from an input, i.e. your computer's microphone.</p>
811 *
@@ -45,8 +48,7 @@ define(function (require) {
4548
4649 this . stream = null ;
4750 this . mediaStream = null ;
48-
49- this . currentSource = 0 ;
51+ this . currentSource = null ;
5052
5153 /**
5254 * Client must allow browser to access their microphone / audioin source.
@@ -60,18 +62,8 @@ define(function (require) {
6062 this . amplitude = new p5 . Amplitude ( ) ;
6163 this . output . connect ( this . amplitude . input ) ;
6264
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' ) ;
7567 }
7668
7769 // add to soundArray so we can dispose on close
@@ -100,50 +92,39 @@ define(function (require) {
10092 p5 . AudioIn . prototype . start = function ( successCallback , errorCallback ) {
10193 var self = this ;
10294
103- // if stream was already started...
95+ if ( this . stream ) {
96+ this . stop ( ) ;
97+ }
10498
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+ } ;
105107
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 ;
146111 }
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+ } ) ;
147128 } ;
148129
149130 /**
@@ -154,8 +135,14 @@ define(function (require) {
154135 */
155136 p5 . AudioIn . prototype . stop = function ( ) {
156137 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 ;
159146 }
160147 } ;
161148
@@ -216,22 +203,6 @@ define(function (require) {
216203 return this . amplitude . getLevel ( ) ;
217204 } ;
218205
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-
235206 /**
236207 * Set amplitude (volume) of a mic input between 0 and 1.0. <br/>
237208 *
@@ -252,31 +223,20 @@ define(function (require) {
252223 }
253224 } ;
254225
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- } ;
264226 /**
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.
276231 *
277232 * @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
280240 * @example
281241 * <div><code>
282242 * var audiograb;
@@ -285,51 +245,62 @@ define(function (require) {
285245 * //new audioIn
286246 * audioGrab = new p5.AudioIn();
287247 *
288- * audioGrab.getSources(function(sourceList ) {
248+ * audioGrab.getSources(function(deviceList ) {
289249 * //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
292252 * audioGrab.setSource(0);
293253 * });
294254 * }
295255 * </code></div>
296256 */
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 ) ;
305267 }
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+ } ) ;
312278 } ;
279+
313280 /**
314281 * 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 ().
316283 * 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/>
319287 *
320288 * @method setSource
321289 * @param {number } num position of input source in the array
322290 */
323291 p5 . AudioIn . prototype . setSource = function ( num ) {
324- // TO DO - set input by string or # (array position)
325- var self = this ;
326292 if ( p5sound . inputSources . length > 0 && num < p5sound . inputSources . length ) {
327293 // 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 ] ) ;
330296 } else {
331297 console . log ( 'unable to set input source' ) ;
332298 }
299+
300+ // restart stream if currently active
301+ if ( this . stream && this . stream . active ) {
302+ this . start ( ) ;
303+ }
333304 } ;
334305
335306 // private method
@@ -339,14 +310,15 @@ define(function (require) {
339310 p5sound . soundArray . splice ( index , 1 ) ;
340311
341312 this . stop ( ) ;
313+
342314 if ( this . output ) {
343315 this . output . disconnect ( ) ;
344316 }
345317 if ( this . amplitude ) {
346318 this . amplitude . disconnect ( ) ;
347319 }
348- this . amplitude = null ;
349- this . output = null ;
320+ delete this . amplitude ;
321+ delete this . output ;
350322 } ;
351323
352324} ) ;
0 commit comments