UNPKG

extendable-media-recorder

Version:

An extendable drop-in replacement for the native MediaRecorder.

1,025 lines (1,008 loc) 60.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@babel/runtime/helpers/asyncToGenerator'), require('@babel/runtime/regenerator'), require('media-encoder-host'), require('@babel/runtime/helpers/classCallCheck'), require('@babel/runtime/helpers/createClass'), require('@babel/runtime/helpers/typeof'), require('@babel/runtime/helpers/assertThisInitialized'), require('@babel/runtime/helpers/possibleConstructorReturn'), require('@babel/runtime/helpers/getPrototypeOf'), require('@babel/runtime/helpers/inherits'), require('@babel/runtime/helpers/slicedToArray'), require('@babel/runtime/helpers/toConsumableArray'), require('recorder-audio-worklet'), require('standardized-audio-context'), require('multi-buffer-data-view'), require('subscribable-things')) : typeof define === 'function' && define.amd ? define(['exports', '@babel/runtime/helpers/asyncToGenerator', '@babel/runtime/regenerator', 'media-encoder-host', '@babel/runtime/helpers/classCallCheck', '@babel/runtime/helpers/createClass', '@babel/runtime/helpers/typeof', '@babel/runtime/helpers/assertThisInitialized', '@babel/runtime/helpers/possibleConstructorReturn', '@babel/runtime/helpers/getPrototypeOf', '@babel/runtime/helpers/inherits', '@babel/runtime/helpers/slicedToArray', '@babel/runtime/helpers/toConsumableArray', 'recorder-audio-worklet', 'standardized-audio-context', 'multi-buffer-data-view', 'subscribable-things'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.extendableMediaRecorder = {}, global._asyncToGenerator, global._regeneratorRuntime, global.mediaEncoderHost, global._classCallCheck, global._createClass, global._typeof, global._assertThisInitialized, global._possibleConstructorReturn, global._getPrototypeOf, global._inherits, global._slicedToArray, global._toConsumableArray, global.recorderAudioWorklet, global.standardizedAudioContext, global.multiBufferDataView, global.subscribableThings)); })(this, (function (exports, _asyncToGenerator, _regeneratorRuntime, mediaEncoderHost, _classCallCheck, _createClass, _typeof, _assertThisInitialized, _possibleConstructorReturn, _getPrototypeOf, _inherits, _slicedToArray, _toConsumableArray, recorderAudioWorklet, standardizedAudioContext, multiBufferDataView, subscribableThings) { 'use strict'; var createBlobEventFactory = function createBlobEventFactory(nativeBlobEventConstructor) { return function (type, blobEventInit) { if (nativeBlobEventConstructor === null) { throw new Error('A native BlobEvent could not be created.'); } return new nativeBlobEventConstructor(type, blobEventInit); }; }; var createDecodeWebMChunk = function createDecodeWebMChunk(readElementContent, readElementType) { return function (dataView, elementType, channelCount) { var contents = []; var currentElementType = elementType; var offset = 0; while (offset < dataView.byteLength) { if (currentElementType === null) { var lengthAndType = readElementType(dataView, offset); if (lengthAndType === null) { break; } var length = lengthAndType.length, type = lengthAndType.type; currentElementType = type; offset += length; } else { var contentAndLength = readElementContent(dataView, offset, currentElementType, channelCount); if (contentAndLength === null) { break; } var content = contentAndLength.content, _length = contentAndLength.length; currentElementType = null; offset += _length; if (content !== null) { contents.push(content); } } } return { contents: contents, currentElementType: currentElementType, offset: offset }; }; }; var createEventTargetConstructor = function createEventTargetConstructor(createEventTarget, wrapEventListener) { return /*#__PURE__*/function () { function EventTarget() { var nativeEventTarget = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; _classCallCheck(this, EventTarget); this._listeners = new WeakMap(); this._nativeEventTarget = nativeEventTarget === null ? createEventTarget() : nativeEventTarget; } return _createClass(EventTarget, [{ key: "addEventListener", value: function addEventListener(type, listener, options) { if (listener !== null) { var wrappedEventListener = this._listeners.get(listener); if (wrappedEventListener === undefined) { wrappedEventListener = wrapEventListener(this, listener); if (typeof listener === 'function') { this._listeners.set(listener, wrappedEventListener); } } this._nativeEventTarget.addEventListener(type, wrappedEventListener, options); } } }, { key: "dispatchEvent", value: function dispatchEvent(event) { return this._nativeEventTarget.dispatchEvent(event); } }, { key: "removeEventListener", value: function removeEventListener(type, listener, options) { var wrappedEventListener = listener === null ? undefined : this._listeners.get(listener); this._nativeEventTarget.removeEventListener(type, wrappedEventListener === undefined ? null : wrappedEventListener, options); } }]); }(); }; var createEventTargetFactory = function createEventTargetFactory(window) { return function () { if (window === null) { throw new Error('A native EventTarget could not be created.'); } return window.document.createElement('p'); }; }; var createInvalidModificationError = function createInvalidModificationError() { var message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; try { return new DOMException(message, 'InvalidModificationError'); } catch (err) { // @todo Edge is the only browser that does not yet allow to construct a DOMException. err.code = 13; err.message = message; err.name = 'InvalidModificationError'; return err; } }; var createInvalidStateError = function createInvalidStateError() { try { return new DOMException('', 'InvalidStateError'); } catch (err) { // Bug #122: Edge is the only browser that does not yet allow to construct a DOMException. err.code = 11; err.name = 'InvalidStateError'; return err; } }; var createIsSupportedPromise = function createIsSupportedPromise(window) { if (window !== null && // Bug #14: Before v14.1 Safari did not support the BlobEvent. window.BlobEvent !== undefined && window.MediaStream !== undefined && ( /* * Bug #10: An early experimental implemenation in Safari v14 did not provide the isTypeSupported() function. * * Bug #17: Safari up to v14.1.2 throttled the processing on hidden tabs if there was no active audio output. This is not tested * here but should be covered by the following test, too. */ window.MediaRecorder === undefined || window.MediaRecorder.isTypeSupported !== undefined)) { // Bug #11 Safari up to v14.1.2 did not support the MediaRecorder but that isn't tested here. if (window.MediaRecorder === undefined) { return Promise.resolve(true); } var canvasElement = window.document.createElement('canvas'); var context = canvasElement.getContext('2d'); if (context === null || typeof canvasElement.captureStream !== 'function') { return Promise.resolve(false); } var mediaStream = canvasElement.captureStream(); return Promise.all([ /* * Bug #5: Up until v70 Firefox did emit a blob of type video/webm when asked to encode a MediaStream with a video track into an * audio codec. */ new Promise(function (resolve) { var mimeType = 'audio/webm'; try { var mediaRecorder = new window.MediaRecorder(mediaStream, { mimeType: mimeType }); mediaRecorder.addEventListener('dataavailable', function (_ref) { var data = _ref.data; return resolve(data.type === mimeType); }); mediaRecorder.start(); setTimeout(function () { return mediaRecorder.stop(); }, 10); } catch (err) { resolve(err.name === 'NotSupportedError'); } }), /* * Bug #1 & #2: Up until v83 Firefox fired an error event with an UnknownError when adding or removing a track. * * Bug #3 & #4: Up until v112 Chrome dispatched an error event without any error. * * Bug #6: Up until v113 Chrome emitted a blob without any data when asked to encode a MediaStream with a video track as audio. * This is not directly tested here as it can only be tested by recording something for a short time. It got fixed at the same * time as #7 and #8. * * Bug #7 & #8: Up until v113 Chrome dispatched the dataavailable and stop events before it dispatched the error event. */ new Promise(function (resolve) { var mediaRecorder = new window.MediaRecorder(mediaStream); var hasDispatchedDataAvailableEvent = false; var hasDispatchedStopEvent = false; mediaRecorder.addEventListener('dataavailable', function () { return hasDispatchedDataAvailableEvent = true; }); mediaRecorder.addEventListener('error', function (event) { resolve(!hasDispatchedDataAvailableEvent && !hasDispatchedStopEvent && 'error' in event && event.error !== null && _typeof(event.error) === 'object' && 'name' in event.error && event.error.name !== 'UnknownError'); }); mediaRecorder.addEventListener('stop', function () { return hasDispatchedStopEvent = true; }); mediaRecorder.start(); context.fillRect(0, 0, 1, 1); mediaStream.removeTrack(mediaStream.getVideoTracks()[0]); })]).then(function (results) { return results.every(function (result) { return result; }); }); } return Promise.resolve(false); }; function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } var createMediaRecorderConstructor = function createMediaRecorderConstructor(createNativeMediaRecorder, createNotSupportedError, createWebAudioMediaRecorder, createWebmPcmMediaRecorder, encoderRegexes, eventTargetConstructor, nativeMediaRecorderConstructor) { return /*#__PURE__*/function (_eventTargetConstruct) { function MediaRecorder(stream) { var _this; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, MediaRecorder); var mimeType = options.mimeType; if (nativeMediaRecorderConstructor !== null && ( // Bug #10: Safari does not yet implement the isTypeSupported() method. mimeType === undefined || nativeMediaRecorderConstructor.isTypeSupported !== undefined && nativeMediaRecorderConstructor.isTypeSupported(mimeType))) { var internalMediaRecorder = createNativeMediaRecorder(nativeMediaRecorderConstructor, stream, options); _this = _callSuper(this, MediaRecorder, [internalMediaRecorder]); _this._internalMediaRecorder = internalMediaRecorder; } else if (mimeType !== undefined && encoderRegexes.some(function (regex) { return regex.test(mimeType); })) { _this = _callSuper(this, MediaRecorder); // Bug #10: Safari does not yet implement the isTypeSupported() method. if (nativeMediaRecorderConstructor !== null && nativeMediaRecorderConstructor.isTypeSupported !== undefined && nativeMediaRecorderConstructor.isTypeSupported('audio/webm;codecs=pcm')) { _this._internalMediaRecorder = createWebmPcmMediaRecorder(_assertThisInitialized(_this), nativeMediaRecorderConstructor, stream, mimeType); } else { _this._internalMediaRecorder = createWebAudioMediaRecorder(_assertThisInitialized(_this), stream, mimeType); } } else { // This is creating a native MediaRecorder just to provoke it to throw an error. if (nativeMediaRecorderConstructor !== null) { createNativeMediaRecorder(nativeMediaRecorderConstructor, stream, options); } throw createNotSupportedError(); } _this._ondataavailable = null; _this._onerror = null; _this._onpause = null; _this._onresume = null; _this._onstart = null; _this._onstop = null; return _assertThisInitialized(_this); } _inherits(MediaRecorder, _eventTargetConstruct); return _createClass(MediaRecorder, [{ key: "mimeType", get: function get() { return this._internalMediaRecorder.mimeType; } }, { key: "ondataavailable", get: function get() { return this._ondataavailable === null ? this._ondataavailable : this._ondataavailable[0]; }, set: function set(value) { if (this._ondataavailable !== null) { this.removeEventListener('dataavailable', this._ondataavailable[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('dataavailable', boundListener); this._ondataavailable = [value, boundListener]; } else { this._ondataavailable = null; } } }, { key: "onerror", get: function get() { return this._onerror === null ? this._onerror : this._onerror[0]; }, set: function set(value) { if (this._onerror !== null) { this.removeEventListener('error', this._onerror[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('error', boundListener); this._onerror = [value, boundListener]; } else { this._onerror = null; } } }, { key: "onpause", get: function get() { return this._onpause === null ? this._onpause : this._onpause[0]; }, set: function set(value) { if (this._onpause !== null) { this.removeEventListener('pause', this._onpause[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('pause', boundListener); this._onpause = [value, boundListener]; } else { this._onpause = null; } } }, { key: "onresume", get: function get() { return this._onresume === null ? this._onresume : this._onresume[0]; }, set: function set(value) { if (this._onresume !== null) { this.removeEventListener('resume', this._onresume[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('resume', boundListener); this._onresume = [value, boundListener]; } else { this._onresume = null; } } }, { key: "onstart", get: function get() { return this._onstart === null ? this._onstart : this._onstart[0]; }, set: function set(value) { if (this._onstart !== null) { this.removeEventListener('start', this._onstart[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('start', boundListener); this._onstart = [value, boundListener]; } else { this._onstart = null; } } }, { key: "onstop", get: function get() { return this._onstop === null ? this._onstop : this._onstop[0]; }, set: function set(value) { if (this._onstop !== null) { this.removeEventListener('stop', this._onstop[1]); } if (typeof value === 'function') { var boundListener = value.bind(this); this.addEventListener('stop', boundListener); this._onstop = [value, boundListener]; } else { this._onstop = null; } } }, { key: "state", get: function get() { return this._internalMediaRecorder.state; } }, { key: "pause", value: function pause() { return this._internalMediaRecorder.pause(); } }, { key: "resume", value: function resume() { return this._internalMediaRecorder.resume(); } }, { key: "start", value: function start(timeslice) { return this._internalMediaRecorder.start(timeslice); } }, { key: "stop", value: function stop() { return this._internalMediaRecorder.stop(); } }], [{ key: "isTypeSupported", value: function isTypeSupported(mimeType) { return nativeMediaRecorderConstructor !== null && // Bug #10: Safari does not yet implement the isTypeSupported() method. nativeMediaRecorderConstructor.isTypeSupported !== undefined && nativeMediaRecorderConstructor.isTypeSupported(mimeType) || encoderRegexes.some(function (regex) { return regex.test(mimeType); }); } }]); }(eventTargetConstructor); }; var createNativeBlobEventConstructor = function createNativeBlobEventConstructor(window) { if (window !== null && window.BlobEvent !== undefined) { return window.BlobEvent; } return null; }; var createNativeMediaRecorderConstructor = function createNativeMediaRecorderConstructor(window) { if (window === null) { return null; } return window.MediaRecorder === undefined ? null : window.MediaRecorder; }; function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: true } : { done: false, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = true, u = false; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = true, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } var createNativeMediaRecorderFactory = function createNativeMediaRecorderFactory(createNotSupportedError) { return function (nativeMediaRecorderConstructor, stream, mediaRecorderOptions) { var bufferedBlobEventListeners = new Map(); var dataAvailableListeners = new WeakMap(); var errorListeners = new WeakMap(); var flags = []; var nativeMediaRecorder = new nativeMediaRecorderConstructor(stream, mediaRecorderOptions); var stopListeners = new WeakMap(); nativeMediaRecorder.addEventListener('stop', function (_ref) { var isTrusted = _ref.isTrusted; if (isTrusted) { setTimeout(function () { return flags.shift(); }); } }); nativeMediaRecorder.addEventListener = function (addEventListener) { return function (type, listener, options) { var patchedEventListener = listener; if (typeof listener === 'function') { if (type === 'dataavailable') { var bufferedBlobEvents = []; // Bug #20: Firefox dispatches multiple dataavailable events while being inactive. patchedEventListener = function patchedEventListener(event) { var _flags$ = flags[0], _flags$2 = _flags$ === void 0 ? [false, false] : _flags$, _flags$3 = _slicedToArray(_flags$2, 2), isSliced = _flags$3[0], isActive = _flags$3[1]; if (isSliced && !isActive) { bufferedBlobEvents.push(event); } else { listener.call(nativeMediaRecorder, event); } }; bufferedBlobEventListeners.set(listener, bufferedBlobEvents); dataAvailableListeners.set(listener, patchedEventListener); } else if (type === 'error') { // Bug #12 & #13: Firefox fires a regular event with an error property. patchedEventListener = function patchedEventListener(event) { if (event instanceof ErrorEvent) { listener.call(nativeMediaRecorder, event); } else { listener.call(nativeMediaRecorder, new ErrorEvent('error', { error: event.error })); } }; errorListeners.set(listener, patchedEventListener); } else if (type === 'stop') { // Bug #20: Firefox dispatches multiple dataavailable events while being inactive. patchedEventListener = function patchedEventListener(event) { var _iterator = _createForOfIteratorHelper(bufferedBlobEventListeners.entries()), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var _step$value = _slicedToArray(_step.value, 2), dataAvailableListener = _step$value[0], _bufferedBlobEvents = _step$value[1]; if (_bufferedBlobEvents.length > 0) { var _bufferedBlobEvents2 = _slicedToArray(_bufferedBlobEvents, 1), blobEvent = _bufferedBlobEvents2[0]; if (_bufferedBlobEvents.length > 1) { Object.defineProperty(blobEvent, 'data', { value: new Blob(_bufferedBlobEvents.map(function (_ref2) { var data = _ref2.data; return data; }), { type: blobEvent.data.type }) }); } _bufferedBlobEvents.length = 0; dataAvailableListener.call(nativeMediaRecorder, blobEvent); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } listener.call(nativeMediaRecorder, event); }; stopListeners.set(listener, patchedEventListener); } } return addEventListener.call(nativeMediaRecorder, type, patchedEventListener, options); }; }(nativeMediaRecorder.addEventListener); nativeMediaRecorder.removeEventListener = function (removeEventListener) { return function (type, listener, options) { var patchedEventListener = listener; if (typeof listener === 'function') { if (type === 'dataavailable') { bufferedBlobEventListeners["delete"](listener); var dataAvailableListener = dataAvailableListeners.get(listener); if (dataAvailableListener !== undefined) { patchedEventListener = dataAvailableListener; } } else if (type === 'error') { var errorListener = errorListeners.get(listener); if (errorListener !== undefined) { patchedEventListener = errorListener; } } else if (type === 'stop') { var stopListener = stopListeners.get(listener); if (stopListener !== undefined) { patchedEventListener = stopListener; } } } return removeEventListener.call(nativeMediaRecorder, type, patchedEventListener, options); }; }(nativeMediaRecorder.removeEventListener); nativeMediaRecorder.start = function (start) { return function (timeslice) { /* * Bug #6: Safari will emit a blob without any data when asked to encode a MediaStream with a video track into an audio * codec. */ if (mediaRecorderOptions.mimeType !== undefined && mediaRecorderOptions.mimeType.startsWith('audio/') && stream.getVideoTracks().length > 0) { throw createNotSupportedError(); } if (nativeMediaRecorder.state === 'inactive') { flags.push([timeslice !== undefined, true]); } return timeslice === undefined ? start.call(nativeMediaRecorder) : start.call(nativeMediaRecorder, timeslice); }; }(nativeMediaRecorder.start); nativeMediaRecorder.stop = function (stop) { return function () { if (nativeMediaRecorder.state !== 'inactive') { flags[0][1] = false; } stop.call(nativeMediaRecorder); }; }(nativeMediaRecorder.stop); return nativeMediaRecorder; }; }; var createNotSupportedError = function createNotSupportedError() { try { return new DOMException('', 'NotSupportedError'); } catch (err) { // @todo Edge is the only browser that does not yet allow to construct a DOMException. err.code = 9; err.name = 'NotSupportedError'; return err; } }; var createReadElementContent = function createReadElementContent(readVariableSizeInteger) { return function (dataView, offset, type) { var channelCount = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 2; var lengthAndValue = readVariableSizeInteger(dataView, offset); if (lengthAndValue === null) { return lengthAndValue; } var length = lengthAndValue.length, value = lengthAndValue.value; if (type === 'master') { return { content: null, length: length }; } if (offset + length + value > dataView.byteLength) { return null; } if (type === 'binary') { var numberOfSamples = (value / Float32Array.BYTES_PER_ELEMENT - 1) / channelCount; var content = Array.from({ length: channelCount }, function () { return new Float32Array(numberOfSamples); }); for (var i = 0; i < numberOfSamples; i += 1) { var elementOffset = i * channelCount + 1; for (var j = 0; j < channelCount; j += 1) { content[j][i] = dataView.getFloat32(offset + length + (elementOffset + j) * Float32Array.BYTES_PER_ELEMENT, true); } } return { content: content, length: length + value }; } return { content: null, length: length + value }; }; }; var createReadElementType = function createReadElementType(readVariableSizeInteger) { return function (dataView, offset) { var lengthAndValue = readVariableSizeInteger(dataView, offset); if (lengthAndValue === null) { return lengthAndValue; } var length = lengthAndValue.length, value = lengthAndValue.value; if (value === 35) { return { length: length, type: 'binary' }; } if (value === 46 || value === 97 || value === 88713574 || value === 106212971 || value === 139690087 || value === 172351395 || value === 256095861) { return { length: length, type: 'master' }; } return { length: length, type: 'unknown' }; }; }; var createReadVariableSizeInteger = function createReadVariableSizeInteger(readVariableSizeIntegerLength) { return function (dataView, offset) { var length = readVariableSizeIntegerLength(dataView, offset); if (length === null) { return length; } var firstDataByteOffset = offset + Math.floor((length - 1) / 8); if (firstDataByteOffset + length > dataView.byteLength) { return null; } var firstDataByte = dataView.getUint8(firstDataByteOffset); var value = firstDataByte & (1 << 8 - length % 8) - 1; // tslint:disable-line:no-bitwise for (var i = 1; i < length; i += 1) { value = (value << 8) + dataView.getUint8(firstDataByteOffset + i); // tslint:disable-line:no-bitwise } return { length: length, value: value }; }; }; var ERROR_MESSAGE = 'Missing AudioWorklet support. Maybe this is not running in a secure context.'; // @todo This should live in a separate file. var createPromisedAudioNodesEncoderInstanceIdAndPort = /*#__PURE__*/function () { var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(audioBuffer, audioContext, channelCount, mediaStream, mimeType) { var _yield$instantiate, encoderInstanceId, port, audioBufferSourceNode, mediaStreamAudioSourceNode, recorderAudioWorkletNode; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.next = 2; return mediaEncoderHost.instantiate(mimeType, audioContext.sampleRate); case 2: _yield$instantiate = _context.sent; encoderInstanceId = _yield$instantiate.encoderInstanceId; port = _yield$instantiate.port; if (!(standardizedAudioContext.AudioWorkletNode === undefined)) { _context.next = 7; break; } throw new Error(ERROR_MESSAGE); case 7: audioBufferSourceNode = new standardizedAudioContext.AudioBufferSourceNode(audioContext, { buffer: audioBuffer }); mediaStreamAudioSourceNode = new standardizedAudioContext.MediaStreamAudioSourceNode(audioContext, { mediaStream: mediaStream }); recorderAudioWorkletNode = recorderAudioWorklet.createRecorderAudioWorkletNode(standardizedAudioContext.AudioWorkletNode, audioContext, { channelCount: channelCount }); return _context.abrupt("return", { audioBufferSourceNode: audioBufferSourceNode, encoderInstanceId: encoderInstanceId, mediaStreamAudioSourceNode: mediaStreamAudioSourceNode, port: port, recorderAudioWorkletNode: recorderAudioWorkletNode }); case 11: case "end": return _context.stop(); } }, _callee); })); return function createPromisedAudioNodesEncoderInstanceIdAndPort(_x, _x2, _x3, _x4, _x5) { return _ref.apply(this, arguments); }; }(); var createWebAudioMediaRecorderFactory = function createWebAudioMediaRecorderFactory(createBlobEvent, createInvalidModificationError, createInvalidStateError, createNotSupportedError) { return function (eventTarget, mediaStream, mimeType) { var _a; var sampleRate = (_a = mediaStream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().sampleRate; var audioContext = new standardizedAudioContext.MinimalAudioContext({ latencyHint: 'playback', sampleRate: sampleRate }); var length = Math.max(1024, Math.ceil(audioContext.baseLatency * audioContext.sampleRate)); var audioBuffer = new standardizedAudioContext.AudioBuffer({ length: length, sampleRate: audioContext.sampleRate }); var bufferedArrayBuffers = []; var promisedAudioWorkletModule = recorderAudioWorklet.addRecorderAudioWorkletModule(function (url) { if (standardizedAudioContext.addAudioWorkletModule === undefined) { throw new Error(ERROR_MESSAGE); } return standardizedAudioContext.addAudioWorkletModule(audioContext, url); }); var abortRecording = null; var intervalId = null; var promisedAudioNodesAndEncoderInstanceId = null; var promisedPartialRecording = null; var isAudioContextRunning = true; var dispatchDataAvailableEvent = function dispatchDataAvailableEvent(arrayBuffers) { eventTarget.dispatchEvent(createBlobEvent('dataavailable', { data: new Blob(arrayBuffers, { type: mimeType }) })); }; var _requestNextPartialRecording = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(encoderInstanceId, timeslice) { var arrayBuffers; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: _context2.next = 2; return mediaEncoderHost.encode(encoderInstanceId, timeslice); case 2: arrayBuffers = _context2.sent; if (promisedAudioNodesAndEncoderInstanceId === null) { bufferedArrayBuffers.push.apply(bufferedArrayBuffers, _toConsumableArray(arrayBuffers)); } else { dispatchDataAvailableEvent(arrayBuffers); promisedPartialRecording = _requestNextPartialRecording(encoderInstanceId, timeslice); } case 4: case "end": return _context2.stop(); } }, _callee2); })); return function requestNextPartialRecording(_x6, _x7) { return _ref2.apply(this, arguments); }; }(); var _resume = function resume() { isAudioContextRunning = true; return audioContext.resume(); }; var stop = function stop() { if (promisedAudioNodesAndEncoderInstanceId === null) { return; } if (abortRecording !== null) { mediaStream.removeEventListener('addtrack', abortRecording); mediaStream.removeEventListener('removetrack', abortRecording); } if (intervalId !== null) { clearTimeout(intervalId); } promisedAudioNodesAndEncoderInstanceId.then(/*#__PURE__*/function () { var _ref4 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(_ref3) { var encoderInstanceId, mediaStreamAudioSourceNode, recorderAudioWorkletNode, arrayBuffers; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: encoderInstanceId = _ref3.encoderInstanceId, mediaStreamAudioSourceNode = _ref3.mediaStreamAudioSourceNode, recorderAudioWorkletNode = _ref3.recorderAudioWorkletNode; if (promisedPartialRecording !== null) { promisedPartialRecording["catch"](function () { /* @todo Only catch the errors caused by a duplicate call to encode. */ }); promisedPartialRecording = null; } _context3.next = 4; return recorderAudioWorkletNode.stop(); case 4: mediaStreamAudioSourceNode.disconnect(recorderAudioWorkletNode); _context3.next = 7; return mediaEncoderHost.encode(encoderInstanceId, null); case 7: arrayBuffers = _context3.sent; if (!(promisedAudioNodesAndEncoderInstanceId === null)) { _context3.next = 11; break; } _context3.next = 11; return suspend(); case 11: dispatchDataAvailableEvent([].concat(bufferedArrayBuffers, _toConsumableArray(arrayBuffers))); bufferedArrayBuffers.length = 0; eventTarget.dispatchEvent(new Event('stop')); case 14: case "end": return _context3.stop(); } }, _callee3); })); return function (_x8) { return _ref4.apply(this, arguments); }; }()); promisedAudioNodesAndEncoderInstanceId = null; }; var suspend = function suspend() { isAudioContextRunning = false; return audioContext.suspend(); }; suspend(); return { get mimeType() { return mimeType; }, get state() { return promisedAudioNodesAndEncoderInstanceId === null ? 'inactive' : isAudioContextRunning ? 'recording' : 'paused'; }, pause: function pause() { if (promisedAudioNodesAndEncoderInstanceId === null) { throw createInvalidStateError(); } if (isAudioContextRunning) { suspend(); eventTarget.dispatchEvent(new Event('pause')); } }, resume: function resume() { if (promisedAudioNodesAndEncoderInstanceId === null) { throw createInvalidStateError(); } if (!isAudioContextRunning) { _resume(); eventTarget.dispatchEvent(new Event('resume')); } }, start: function start(timeslice) { var _a; if (promisedAudioNodesAndEncoderInstanceId !== null) { throw createInvalidStateError(); } if (mediaStream.getVideoTracks().length > 0) { throw createNotSupportedError(); } eventTarget.dispatchEvent(new Event('start')); var audioTracks = mediaStream.getAudioTracks(); var channelCount = audioTracks.length === 0 ? 2 : (_a = audioTracks[0].getSettings().channelCount) !== null && _a !== void 0 ? _a : 2; promisedAudioNodesAndEncoderInstanceId = Promise.all([_resume(), promisedAudioWorkletModule.then(function () { return createPromisedAudioNodesEncoderInstanceIdAndPort(audioBuffer, audioContext, channelCount, mediaStream, mimeType); })]).then(/*#__PURE__*/function () { var _ref6 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(_ref5) { var _ref7, _ref7$, audioBufferSourceNode, encoderInstanceId, mediaStreamAudioSourceNode, port, recorderAudioWorkletNode; return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) switch (_context4.prev = _context4.next) { case 0: _ref7 = _slicedToArray(_ref5, 2), _ref7$ = _ref7[1], audioBufferSourceNode = _ref7$.audioBufferSourceNode, encoderInstanceId = _ref7$.encoderInstanceId, mediaStreamAudioSourceNode = _ref7$.mediaStreamAudioSourceNode, port = _ref7$.port, recorderAudioWorkletNode = _ref7$.recorderAudioWorkletNode; mediaStreamAudioSourceNode.connect(recorderAudioWorkletNode); _context4.next = 4; return new Promise(function (resolve) { audioBufferSourceNode.onended = resolve; audioBufferSourceNode.connect(recorderAudioWorkletNode); audioBufferSourceNode.start(audioContext.currentTime + length / audioContext.sampleRate); }); case 4: audioBufferSourceNode.disconnect(recorderAudioWorkletNode); _context4.next = 7; return recorderAudioWorkletNode.record(port); case 7: if (timeslice !== undefined) { promisedPartialRecording = _requestNextPartialRecording(encoderInstanceId, timeslice); } return _context4.abrupt("return", { encoderInstanceId: encoderInstanceId, mediaStreamAudioSourceNode: mediaStreamAudioSourceNode, recorderAudioWorkletNode: recorderAudioWorkletNode }); case 9: case "end": return _context4.stop(); } }, _callee4); })); return function (_x9) { return _ref6.apply(this, arguments); }; }()); var tracks = mediaStream.getTracks(); abortRecording = function abortRecording() { stop(); eventTarget.dispatchEvent(new ErrorEvent('error', { error: createInvalidModificationError() })); }; mediaStream.addEventListener('addtrack', abortRecording); mediaStream.addEventListener('removetrack', abortRecording); intervalId = setInterval(function () { var currentTracks = mediaStream.getTracks(); if ((currentTracks.length !== tracks.length || currentTracks.some(function (track, index) { return track !== tracks[index]; })) && abortRecording !== null) { abortRecording(); } }, 1000); }, stop: stop }; }; }; var createWebmPcmMediaRecorderFactory = function createWebmPcmMediaRecorderFactory(createBlobEvent, decodeWebMChunk, readVariableSizeInteger) { return function (eventTarget, nativeMediaRecorderConstructor, mediaStream, mimeType) { var bufferedArrayBuffers = []; var nativeMediaRecorder = new nativeMediaRecorderConstructor(mediaStream, { mimeType: 'audio/webm;codecs=pcm' }); var promisedPartialRecording = null; var stopRecording = function stopRecording() {}; // tslint:disable-line:no-empty var dispatchDataAvailableEvent = function dispatchDataAvailableEvent(arrayBuffers) { eventTarget.dispatchEvent(createBlobEvent('dataavailable', { data: new Blob(arrayBuffers, { type: mimeType }) })); }; var _requestNextPartialRecording = /*#__PURE__*/function () { var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(encoderInstanceId, timeslice) { var arrayBuffers; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.next = 2; return mediaEncoderHost.encode(encoderInstanceId, timeslice); case 2: arrayBuffers = _context.sent; if (nativeMediaRecorder.state === 'inactive') { bufferedArrayBuffers.push.apply(bufferedArrayBuffers, _toConsumableArray(arrayBuffers)); } else { dispatchDataAvailableEvent(arrayBuffers); promisedPartialRecording = _requestNextPartialRecording(encoderInstanceId, timeslice); } case 4: case "end": return _context.stop(); } }, _callee); })); return function requestNextPartialRecording(_x, _x2) { return _ref.apply(this, arguments); }; }(); var stop = function stop() { if (nativeMediaRecorder.state === 'inactive') { return; } if (promisedPartialRecording !== null) { promisedPartialRecording["catch"](function () { /* @todo Only catch the errors caused by a duplicate call to encode. */ }); promisedPartialRecording = null; } stopRecording(); stopRecording = function stopRecording() {}; // tslint:disable-line:no-empty nativeMediaRecorder.stop(); }; nativeMediaRecorder.addEventListener('error', function (event) { stop(); eventTarget.dispatchEvent(new ErrorEvent('error', { error: event.error })); }); nativeMediaRecorder.addEventListener('pause', function () { return eventTarget.dispatchEvent(new Event('pause')); }); nativeMediaRecorder.addEventListener('resume', function () { return eventTarget.dispatchEvent(new Event('resume')); }); nativeMediaRecorder.addEventListener('start', function () { return eventTarget.dispatchEvent(new Event('start')); }); return { get mimeType() { return mimeType; }, get state() { return nativeMediaRecorder.state; }, pause: function pause() { return nativeMediaRecorder.pause(); }, resume: function resume() { return nativeMediaRecorder.resume(); }, start: function start(timeslice) { var _mediaStream$getAudio = mediaStream.getAudioTracks(), _mediaStream$getAudio2 = _slicedToArray(_mediaStream$getAudio, 1), audioTrack = _mediaStream$getAudio2[0]; if (audioTrack !== undefined && nativeMediaRecorder.state === 'inactive') { // Bug #19: Chrome does not expose the correct channelCount property right away. var _audioTrack$getSettin = audioTrack.getSettings(), channelCount = _audioTrack$getSettin.channelCount, sampleRate = _audioTrack$getSettin.sampleRate; if (channelCount === undefined) { throw new Error('The channelCount is not defined.'); } if (sampleRate === undefined) { throw new Error('The sampleRate is not defined.'); } var isRecording = false; var isStopped = false; // Bug #9: Chrome sometimes fires more than one dataavailable event while being inactive. var pendingInvocations = 0; var promisedDataViewElementTypeEncoderInstanceIdAndPort = mediaEncoderHost.instantiate(mimeType, sampleRate); stopRecording = function stopRecording() { isStopped = true; }; var removeEventListener = subscribableThings.on(nativeMediaRecorder, 'dataavailable')(function (_ref2) { var data = _ref2.data; pendingInvocations += 1; var promisedArrayBuffer = data.arrayBuffer(); prom