UNPKG

flocking

Version:

Creative audio synthesis for the Web

211 lines (176 loc) 7.27 kB
/* * Flocking Web Audio Input Manager * https://github.com/continuing-creativity/flocking * * Copyright 2013-2014, Colin Clark * Dual licensed under the MIT and GPL Version 2 licenses. */ /*global require, MediaStreamTrack, jQuery*/ /*jshint white: false, newcap: true, regexp: true, browser: true, forin: false, nomen: true, bitwise: false, maxerr: 100, indent: 4, plusplus: false, curly: true, eqeqeq: true, freeze: true, latedef: true, noarg: true, nonew: true, quotmark: double, undef: true, unused: true, strict: true, asi: false, boss: false, evil: false, expr: false, funcscope: false*/ var fluid = fluid || require("infusion"), flock = fluid.registerNamespace("flock"); (function () { "use strict"; // TODO: Remove this when Chrome implements navigator.getMediaDevices(). fluid.registerNamespace("flock.webAudio.chrome"); flock.webAudio.chrome.getSources = function (callback) { return MediaStreamTrack.getSources(function (infoSpecs) { var normalized = fluid.transform(infoSpecs, function (infoSpec) { infoSpec.deviceId = infoSpec.id; return infoSpec; }); callback(normalized); }); }; flock.webAudio.mediaStreamFailure = function (onError) { var msg = "This browser does not support getUserMedia() or the Media Streams API."; if (!onError) { fluid.log(fluid.logLevel.IMPORTANT, msg); } else { onError(new Error(msg)); } }; var webAudioShims = { AudioContext: window.AudioContext || window.webkitAudioContext, getUserMedia: function (constraints, onAccess, onError) { if (navigator.mediaDevices) { var p = navigator.mediaDevices.getUserMedia(constraints); p.then(onAccess).catch(onError); } else if (navigator.getUserMedia) { navigator.getUserMedia(constraints, onAccess, onError); } else { flock.webAudio.mediaStreamFailure(onError); } }, getMediaDevicesImpl: navigator.getMediaDevices ? navigator.getMediaDevices : typeof window.MediaStreamTrack !== "undefined" ? flock.webAudio.chrome.getSources : flock.webAudio.mediaStreamFailure, getMediaDevice: function () { flock.shim.getMediaDevicesImpl.apply(navigator, arguments); } }; jQuery.extend(flock.shim, webAudioShims); /** * Manages audio input devices using the Web Audio API. */ // Add a means for disconnecting audio input nodes. fluid.defaults("flock.webAudio.inputDeviceManager", { gradeNames: ["fluid.component"], invokers: { /** * Opens the specified audio device. * If no device is specified, the default device is opened. * * @param {Object} deviceSpec a device spec containing, optionally, an 'id' or 'label' parameter */ openAudioDevice: { funcName: "flock.webAudio.inputDeviceManager.openAudioDevice", args: [ "{arguments}.0", "{that}.openAudioDeviceWithId", "{that}.openFirstAudioDeviceWithLabel", "{that}.openAudioDeviceWithConstraints" ] }, /** * Opens an audio device with the specified WebRTC constraints. * If no constraints are specified, the default audio device is opened. * * @param {Object} constraints a WebRTC-compatible constraints object */ openAudioDeviceWithConstraints: { funcName: "flock.webAudio.inputDeviceManager.openAudioDeviceWithConstraints", args: [ "{audioSystem}.context", "{enviro}", "{nativeNodeManager}.createMediaStreamInput", "{arguments}.0" ] }, /** * Opens an audio device with the specified WebRTC device id. * * @param {string} id a device identifier */ openAudioDeviceWithId: { funcName: "flock.webAudio.inputDeviceManager.openAudioDeviceWithId", args: ["{arguments}.0", "{that}.openAudioDeviceWithConstraints"] }, /** * Opens the first audio device found with the specified label. * The label must be an exact, case-insensitive match. * * @param {string} label a device label */ openFirstAudioDeviceWithLabel: { funcName: "flock.webAudio.inputDeviceManager.openFirstAudioDeviceWithLabel", args: ["{arguments}.0", "{that}.openAudioDeviceWithId"] } } }); flock.webAudio.inputDeviceManager.openAudioDevice = function (sourceSpec, idOpener, labelOpener, specOpener) { if (sourceSpec) { if (sourceSpec.id) { return idOpener(sourceSpec.id); } else if (sourceSpec.label) { return labelOpener(sourceSpec.label); } } return specOpener(); }; flock.webAudio.inputDeviceManager.openAudioDeviceWithId = function (id, deviceOpener) { var options = { audio: { optional: [ { sourceId: id } ] } }; deviceOpener(options); }; flock.webAudio.inputDeviceManager.openFirstAudioDeviceWithLabel = function (label, deviceOpener) { if (!label) { return; } // TODO: Can't access device labels until the user agrees // to allow access to the current device. flock.shim.getMediaDevices(function (deviceInfoSpecs) { var matches = deviceInfoSpecs.filter(function (device) { if (device.label.toLowerCase() === label.toLowerCase()) { return true; } }); if (matches.length > 0) { deviceOpener(matches[0].deviceId); } else { fluid.log(fluid.logLevel.IMPORTANT, "An audio device named '" + label + "' could not be found."); } }); }; flock.webAudio.inputDeviceManager.openAudioDeviceWithConstraints = function (context, enviro, openMediaStream, options) { options = options || { audio: true }; // Acquire an input bus ahead of time so we can synchronously // notify the client where its output will be. var busNum = enviro.busManager.acquireNextBus("input"); function error (err) { fluid.log(fluid.logLevel.IMPORTANT, "An error occurred while trying to access the user's microphone. " + err); } function success (mediaStream) { openMediaStream(mediaStream, busNum); } flock.shim.getUserMedia(options, success, error); return busNum; }; }());