refactor: use createLocalTracks instead of gUM; fix some docs;
This commit is contained in:
parent
3241c7a929
commit
e125861b29
|
@ -258,7 +258,7 @@ class RecordingController {
|
|||
this._format = newFormat;
|
||||
logger.log(`Recording format switched to ${newFormat}`);
|
||||
|
||||
// will be used next time
|
||||
// the new format will be used in the next recording session
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,6 @@ MiddlewareRegistry.register(({ getState, dispatch }) => next => action => {
|
|||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOINED: {
|
||||
// the Conference object is ready
|
||||
const { conference } = getState()['features/base/conference'];
|
||||
|
||||
recordingController.registerEvents(conference);
|
||||
|
@ -48,5 +47,8 @@ MiddlewareRegistry.register(({ getState, dispatch }) => next => action => {
|
|||
break;
|
||||
}
|
||||
|
||||
// @todo: detect change in features/base/settings micDeviceID
|
||||
// @todo: SET_AUDIO_MUTED, when audio is muted
|
||||
|
||||
return result;
|
||||
});
|
||||
|
|
|
@ -9,6 +9,9 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
|
|||
*/
|
||||
export class OggAdapter extends RecordingAdapter {
|
||||
|
||||
/**
|
||||
* Instance of MediaRecorder.
|
||||
*/
|
||||
_mediaRecorder = null;
|
||||
|
||||
/**
|
||||
|
@ -21,29 +24,17 @@ export class OggAdapter extends RecordingAdapter {
|
|||
|
||||
if (this._mediaRecorder === null) {
|
||||
p = new Promise((resolve, error) => {
|
||||
navigator.getUserMedia(
|
||||
|
||||
// constraints, only audio needed
|
||||
{
|
||||
audioBitsPerSecond: 44100, // 44 kbps
|
||||
audio: true,
|
||||
mimeType: 'application/ogg'
|
||||
},
|
||||
|
||||
// success callback
|
||||
stream => {
|
||||
this._mediaRecorder = new MediaRecorder(stream);
|
||||
this._mediaRecorder.ondataavailable
|
||||
= e => this._saveMediaData(e.data);
|
||||
resolve();
|
||||
},
|
||||
|
||||
// Error callback
|
||||
err => {
|
||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||
error();
|
||||
}
|
||||
);
|
||||
this._getAudioStream(0)
|
||||
.then(stream => {
|
||||
this._mediaRecorder = new MediaRecorder(stream);
|
||||
this._mediaRecorder.ondataavailable
|
||||
= e => this._saveMediaData(e.data);
|
||||
resolve();
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||
error();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
p = new Promise(resolve => {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import JitsiMeetJS from '../../base/lib-jitsi-meet';
|
||||
|
||||
/**
|
||||
* Common interface for recording mechanisms
|
||||
* Base class for recording backends.
|
||||
*/
|
||||
export class RecordingAdapter {
|
||||
|
||||
|
@ -38,4 +40,31 @@ export class RecordingAdapter {
|
|||
download() {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting an audio MediaStream. Use this instead of
|
||||
* calling browser APIs directly.
|
||||
*
|
||||
* @protected
|
||||
* @param {number} micDeviceId - The ID of the current audio device.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_getAudioStream(micDeviceId) {
|
||||
return JitsiMeetJS.createLocalTracks({
|
||||
devices: [ 'audio' ],
|
||||
micDeviceId
|
||||
}).then(result => {
|
||||
if (result.length !== 1) {
|
||||
throw new Error('Unexpected number of streams '
|
||||
+ 'from createLocalTracks.');
|
||||
}
|
||||
const mediaStream = result[0].stream;
|
||||
|
||||
if (mediaStream === undefined) {
|
||||
throw new Error('Failed to get MediaStream.');
|
||||
}
|
||||
|
||||
return mediaStream;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,40 +40,28 @@ export class WavAdapter extends RecordingAdapter {
|
|||
}
|
||||
|
||||
const p = new Promise((resolve, reject) => {
|
||||
navigator.getUserMedia(
|
||||
this._getAudioStream(0)
|
||||
.then(stream => {
|
||||
this._audioContext = new AudioContext();
|
||||
this._audioSource
|
||||
= this._audioContext.createMediaStreamSource(stream);
|
||||
this._audioProcessingNode
|
||||
= this._audioContext.createScriptProcessor(4096, 1, 1);
|
||||
this._audioProcessingNode.onaudioprocess = e => {
|
||||
const channelLeft = e.inputBuffer.getChannelData(0);
|
||||
|
||||
// constraints - only audio needed for this app
|
||||
{
|
||||
audioBitsPerSecond: WAV_SAMPLE_RATE * WAV_BITS_PER_SAMPLE,
|
||||
audio: true,
|
||||
mimeType: 'application/ogg' // useless?
|
||||
},
|
||||
|
||||
// Success callback
|
||||
stream => {
|
||||
this._audioContext = new AudioContext();
|
||||
this._audioSource
|
||||
= this._audioContext.createMediaStreamSource(stream);
|
||||
this._audioProcessingNode
|
||||
= this._audioContext.createScriptProcessor(4096, 1, 1);
|
||||
this._audioProcessingNode.onaudioprocess = e => {
|
||||
const channelLeft = e.inputBuffer.getChannelData(0);
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/
|
||||
// Web/API/AudioBuffer/getChannelData
|
||||
// the returned value is an Float32Array
|
||||
this._saveWavPCM(channelLeft);
|
||||
};
|
||||
this._isInitialized = true;
|
||||
resolve();
|
||||
},
|
||||
|
||||
// Error callback
|
||||
err => {
|
||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||
reject();
|
||||
}
|
||||
);
|
||||
// https://developer.mozilla.org/en-US/docs/
|
||||
// Web/API/AudioBuffer/getChannelData
|
||||
// the returned value is an Float32Array
|
||||
this._saveWavPCM(channelLeft);
|
||||
};
|
||||
this._isInitialized = true;
|
||||
resolve();
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||
reject();
|
||||
});
|
||||
});
|
||||
|
||||
return p;
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Recording adapter that uses libflac in the background
|
||||
* Recording adapter that uses libflac.js in the background.
|
||||
*/
|
||||
export class FlacAdapter extends RecordingAdapter {
|
||||
|
||||
|
@ -43,7 +43,7 @@ export class FlacAdapter extends RecordingAdapter {
|
|||
// try load the minified version first
|
||||
this._encoder = new Worker('/libs/flacEncodeWorker.min.js');
|
||||
} catch (exception1) {
|
||||
// if failed, try un minified version
|
||||
// if failed, try unminified version
|
||||
try {
|
||||
this._encoder = new Worker('/libs/flacEncodeWorker.js');
|
||||
} catch (exception2) {
|
||||
|
@ -83,41 +83,29 @@ export class FlacAdapter extends RecordingAdapter {
|
|||
});
|
||||
|
||||
const callbackInitAudioContext = (resolve, reject) => {
|
||||
navigator.getUserMedia(
|
||||
this._getAudioStream(0)
|
||||
.then(stream => {
|
||||
this._audioContext = new AudioContext();
|
||||
this._audioSource
|
||||
= this._audioContext.createMediaStreamSource(stream);
|
||||
this._audioProcessingNode
|
||||
= this._audioContext.createScriptProcessor(4096, 1, 1);
|
||||
this._audioProcessingNode.onaudioprocess = e => {
|
||||
// delegate to the WebWorker to do the encoding
|
||||
const channelLeft = e.inputBuffer.getChannelData(0);
|
||||
|
||||
// constraints - only audio needed for this app
|
||||
{
|
||||
audioBitsPerSecond: 44100, // 44 kbps
|
||||
audio: true,
|
||||
mimeType: 'application/ogg' // useless?
|
||||
},
|
||||
|
||||
// Success callback
|
||||
stream => {
|
||||
this._audioContext = new AudioContext();
|
||||
this._audioSource
|
||||
= this._audioContext.createMediaStreamSource(stream);
|
||||
this._audioProcessingNode
|
||||
= this._audioContext.createScriptProcessor(4096, 1, 1);
|
||||
this._audioProcessingNode.onaudioprocess = e => {
|
||||
// delegate to the WebWorker to do the encoding
|
||||
const channelLeft = e.inputBuffer.getChannelData(0);
|
||||
|
||||
this._encoder.postMessage({
|
||||
command: MAIN_THREAD_NEW_DATA_ARRIVED,
|
||||
buf: channelLeft
|
||||
});
|
||||
};
|
||||
logger.debug('AudioContext is set up.');
|
||||
resolve();
|
||||
},
|
||||
|
||||
// Error callback
|
||||
err => {
|
||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||
reject();
|
||||
}
|
||||
);
|
||||
this._encoder.postMessage({
|
||||
command: MAIN_THREAD_NEW_DATA_ARRIVED,
|
||||
buf: channelLeft
|
||||
});
|
||||
};
|
||||
logger.debug('AudioContext is set up.');
|
||||
resolve();
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||
reject();
|
||||
});
|
||||
};
|
||||
|
||||
// FIXME: because Promise constructor immediately executes the executor
|
||||
|
|
|
@ -26,39 +26,33 @@ importScripts('/libs/libflac3-1.3.2.min.js');
|
|||
declare var Flac: Object;
|
||||
|
||||
const FLAC_ERRORS = {
|
||||
// The encoder is in the normal OK state and
|
||||
// samples can be processed.
|
||||
// The encoder is in the normal OK state and samples can be processed.
|
||||
0: 'FLAC__STREAM_ENCODER_OK',
|
||||
|
||||
// The encoder is in the
|
||||
// uninitialized state one of the FLAC__stream_encoder_init_*() functions
|
||||
// must be called before samples can be processed.
|
||||
// The encoder is in the uninitialized state one of the
|
||||
// FLAC__stream_encoder_init_*() functions must be called before samples can
|
||||
// be processed.
|
||||
1: 'FLAC__STREAM_ENCODER_UNINITIALIZED',
|
||||
|
||||
// An error occurred in the underlying Ogg layer.
|
||||
2: 'FLAC__STREAM_ENCODER_OGG_ERROR',
|
||||
|
||||
// An error occurred in the
|
||||
// underlying verify stream decoder; check
|
||||
// An error occurred in the underlying verify stream decoder; check
|
||||
// FLAC__stream_encoder_get_verify_decoder_state().
|
||||
3: 'FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR',
|
||||
|
||||
// The verify decoder detected a mismatch between the
|
||||
// original audio signal and the decoded audio signal.
|
||||
|
||||
// The verify decoder detected a mismatch between the original audio signal
|
||||
// and the decoded audio signal.
|
||||
4: 'FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA',
|
||||
|
||||
// One of the callbacks returned
|
||||
// a fatal error.
|
||||
// One of the callbacks returned a fatal error.
|
||||
5: 'FLAC__STREAM_ENCODER_CLIENT_ERROR',
|
||||
|
||||
// An I/O error occurred while
|
||||
// opening/reading/writing a file. Check errno.
|
||||
|
||||
// An I/O error occurred while opening/reading/writing a file. Check errno.
|
||||
6: 'FLAC__STREAM_ENCODER_IO_ERROR',
|
||||
|
||||
// An error occurred while writing
|
||||
// the stream; usually, the write_callback returned an error.
|
||||
// An error occurred while writing the stream; usually, the write_callback
|
||||
// returned an error.
|
||||
7: 'FLAC__STREAM_ENCODER_FRAMING_ERROR',
|
||||
|
||||
// Memory allocation failed.
|
||||
|
|
|
@ -9,11 +9,7 @@ import {
|
|||
} from './actionTypes';
|
||||
import { recordingController } from './controller';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
ReducerRegistry.register('features/local-recording', (state = {}, action) => {
|
||||
logger.debug(`Redux state (features/local-recording):\n ${
|
||||
JSON.stringify(state)}`);
|
||||
switch (action.type) {
|
||||
case LOCAL_RECORDING_ENGAGED: {
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue