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;
|
this._format = newFormat;
|
||||||
logger.log(`Recording format switched to ${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) {
|
switch (action.type) {
|
||||||
case CONFERENCE_JOINED: {
|
case CONFERENCE_JOINED: {
|
||||||
// the Conference object is ready
|
|
||||||
const { conference } = getState()['features/base/conference'];
|
const { conference } = getState()['features/base/conference'];
|
||||||
|
|
||||||
recordingController.registerEvents(conference);
|
recordingController.registerEvents(conference);
|
||||||
|
@ -48,5 +47,8 @@ MiddlewareRegistry.register(({ getState, dispatch }) => next => action => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo: detect change in features/base/settings micDeviceID
|
||||||
|
// @todo: SET_AUDIO_MUTED, when audio is muted
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,9 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
*/
|
*/
|
||||||
export class OggAdapter extends RecordingAdapter {
|
export class OggAdapter extends RecordingAdapter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of MediaRecorder.
|
||||||
|
*/
|
||||||
_mediaRecorder = null;
|
_mediaRecorder = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,29 +24,17 @@ export class OggAdapter extends RecordingAdapter {
|
||||||
|
|
||||||
if (this._mediaRecorder === null) {
|
if (this._mediaRecorder === null) {
|
||||||
p = new Promise((resolve, error) => {
|
p = new Promise((resolve, error) => {
|
||||||
navigator.getUserMedia(
|
this._getAudioStream(0)
|
||||||
|
.then(stream => {
|
||||||
// constraints, only audio needed
|
|
||||||
{
|
|
||||||
audioBitsPerSecond: 44100, // 44 kbps
|
|
||||||
audio: true,
|
|
||||||
mimeType: 'application/ogg'
|
|
||||||
},
|
|
||||||
|
|
||||||
// success callback
|
|
||||||
stream => {
|
|
||||||
this._mediaRecorder = new MediaRecorder(stream);
|
this._mediaRecorder = new MediaRecorder(stream);
|
||||||
this._mediaRecorder.ondataavailable
|
this._mediaRecorder.ondataavailable
|
||||||
= e => this._saveMediaData(e.data);
|
= e => this._saveMediaData(e.data);
|
||||||
resolve();
|
resolve();
|
||||||
},
|
})
|
||||||
|
.catch(err => {
|
||||||
// Error callback
|
|
||||||
err => {
|
|
||||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||||
error();
|
error();
|
||||||
}
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
p = new Promise(resolve => {
|
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 {
|
export class RecordingAdapter {
|
||||||
|
|
||||||
|
@ -38,4 +40,31 @@ export class RecordingAdapter {
|
||||||
download() {
|
download() {
|
||||||
throw new Error('Not implemented');
|
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,17 +40,8 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
const p = new Promise((resolve, reject) => {
|
const p = new Promise((resolve, reject) => {
|
||||||
navigator.getUserMedia(
|
this._getAudioStream(0)
|
||||||
|
.then(stream => {
|
||||||
// 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._audioContext = new AudioContext();
|
||||||
this._audioSource
|
this._audioSource
|
||||||
= this._audioContext.createMediaStreamSource(stream);
|
= this._audioContext.createMediaStreamSource(stream);
|
||||||
|
@ -66,14 +57,11 @@ export class WavAdapter extends RecordingAdapter {
|
||||||
};
|
};
|
||||||
this._isInitialized = true;
|
this._isInitialized = true;
|
||||||
resolve();
|
resolve();
|
||||||
},
|
})
|
||||||
|
.catch(err => {
|
||||||
// Error callback
|
|
||||||
err => {
|
|
||||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||||
reject();
|
reject();
|
||||||
}
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
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 {
|
export class FlacAdapter extends RecordingAdapter {
|
||||||
|
|
||||||
|
@ -83,17 +83,8 @@ export class FlacAdapter extends RecordingAdapter {
|
||||||
});
|
});
|
||||||
|
|
||||||
const callbackInitAudioContext = (resolve, reject) => {
|
const callbackInitAudioContext = (resolve, reject) => {
|
||||||
navigator.getUserMedia(
|
this._getAudioStream(0)
|
||||||
|
.then(stream => {
|
||||||
// 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._audioContext = new AudioContext();
|
||||||
this._audioSource
|
this._audioSource
|
||||||
= this._audioContext.createMediaStreamSource(stream);
|
= this._audioContext.createMediaStreamSource(stream);
|
||||||
|
@ -110,14 +101,11 @@ export class FlacAdapter extends RecordingAdapter {
|
||||||
};
|
};
|
||||||
logger.debug('AudioContext is set up.');
|
logger.debug('AudioContext is set up.');
|
||||||
resolve();
|
resolve();
|
||||||
},
|
})
|
||||||
|
.catch(err => {
|
||||||
// Error callback
|
|
||||||
err => {
|
|
||||||
logger.error(`Error calling getUserMedia(): ${err}`);
|
logger.error(`Error calling getUserMedia(): ${err}`);
|
||||||
reject();
|
reject();
|
||||||
}
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: because Promise constructor immediately executes the executor
|
// FIXME: because Promise constructor immediately executes the executor
|
||||||
|
|
|
@ -26,39 +26,33 @@ importScripts('/libs/libflac3-1.3.2.min.js');
|
||||||
declare var Flac: Object;
|
declare var Flac: Object;
|
||||||
|
|
||||||
const FLAC_ERRORS = {
|
const FLAC_ERRORS = {
|
||||||
// The encoder is in the normal OK state and
|
// The encoder is in the normal OK state and samples can be processed.
|
||||||
// samples can be processed.
|
|
||||||
0: 'FLAC__STREAM_ENCODER_OK',
|
0: 'FLAC__STREAM_ENCODER_OK',
|
||||||
|
|
||||||
// The encoder is in the
|
// The encoder is in the uninitialized state one of the
|
||||||
// uninitialized state one of the FLAC__stream_encoder_init_*() functions
|
// FLAC__stream_encoder_init_*() functions must be called before samples can
|
||||||
// must be called before samples can be processed.
|
// be processed.
|
||||||
1: 'FLAC__STREAM_ENCODER_UNINITIALIZED',
|
1: 'FLAC__STREAM_ENCODER_UNINITIALIZED',
|
||||||
|
|
||||||
// An error occurred in the underlying Ogg layer.
|
// An error occurred in the underlying Ogg layer.
|
||||||
2: 'FLAC__STREAM_ENCODER_OGG_ERROR',
|
2: 'FLAC__STREAM_ENCODER_OGG_ERROR',
|
||||||
|
|
||||||
// An error occurred in the
|
// An error occurred in the underlying verify stream decoder; check
|
||||||
// underlying verify stream decoder; check
|
|
||||||
// FLAC__stream_encoder_get_verify_decoder_state().
|
// FLAC__stream_encoder_get_verify_decoder_state().
|
||||||
3: 'FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR',
|
3: 'FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR',
|
||||||
|
|
||||||
// The verify decoder detected a mismatch between the
|
// The verify decoder detected a mismatch between the original audio signal
|
||||||
// original audio signal and the decoded audio signal.
|
// and the decoded audio signal.
|
||||||
|
|
||||||
4: 'FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA',
|
4: 'FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA',
|
||||||
|
|
||||||
// One of the callbacks returned
|
// One of the callbacks returned a fatal error.
|
||||||
// a fatal error.
|
|
||||||
5: 'FLAC__STREAM_ENCODER_CLIENT_ERROR',
|
5: 'FLAC__STREAM_ENCODER_CLIENT_ERROR',
|
||||||
|
|
||||||
// An I/O error occurred while
|
// An I/O error occurred while opening/reading/writing a file. Check errno.
|
||||||
// opening/reading/writing a file. Check errno.
|
|
||||||
|
|
||||||
6: 'FLAC__STREAM_ENCODER_IO_ERROR',
|
6: 'FLAC__STREAM_ENCODER_IO_ERROR',
|
||||||
|
|
||||||
// An error occurred while writing
|
// An error occurred while writing the stream; usually, the write_callback
|
||||||
// the stream; usually, the write_callback returned an error.
|
// returned an error.
|
||||||
7: 'FLAC__STREAM_ENCODER_FRAMING_ERROR',
|
7: 'FLAC__STREAM_ENCODER_FRAMING_ERROR',
|
||||||
|
|
||||||
// Memory allocation failed.
|
// Memory allocation failed.
|
||||||
|
|
|
@ -9,11 +9,7 @@ import {
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
import { recordingController } from './controller';
|
import { recordingController } from './controller';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
|
||||||
|
|
||||||
ReducerRegistry.register('features/local-recording', (state = {}, action) => {
|
ReducerRegistry.register('features/local-recording', (state = {}, action) => {
|
||||||
logger.debug(`Redux state (features/local-recording):\n ${
|
|
||||||
JSON.stringify(state)}`);
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case LOCAL_RECORDING_ENGAGED: {
|
case LOCAL_RECORDING_ENGAGED: {
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in New Issue