mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: fix LocalRecorder
parent
18f3f76b22
commit
4ca3839821
|
@ -4,6 +4,7 @@
|
||||||
"freeice": "2.2.2",
|
"freeice": "2.2.2",
|
||||||
"hark": "1.2.3",
|
"hark": "1.2.3",
|
||||||
"jsnlog": "2.30.0",
|
"jsnlog": "2.30.0",
|
||||||
|
"mime-types": "2.1.34",
|
||||||
"platform": "1.3.6",
|
"platform": "1.3.6",
|
||||||
"semver": "7.3.5",
|
"semver": "7.3.5",
|
||||||
"uuid": "8.3.2",
|
"uuid": "8.3.2",
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "17.0.8",
|
"@types/node": "17.0.8",
|
||||||
"@types/platform": "1.3.4",
|
"@types/platform": "1.3.4",
|
||||||
|
"@types/mime-types": "2.1.1",
|
||||||
"browserify": "17.0.0",
|
"browserify": "17.0.0",
|
||||||
"grunt": "1.4.1",
|
"grunt": "1.4.1",
|
||||||
"grunt-cli": "1.4.3",
|
"grunt-cli": "1.4.3",
|
||||||
|
|
|
@ -19,12 +19,8 @@ import { Stream } from './Stream';
|
||||||
import { LocalRecorderState } from '../OpenViduInternal/Enums/LocalRecorderState';
|
import { LocalRecorderState } from '../OpenViduInternal/Enums/LocalRecorderState';
|
||||||
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
|
import { OpenViduLogger } from '../OpenViduInternal/Logger/OpenViduLogger';
|
||||||
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
|
import { PlatformUtils } from '../OpenViduInternal/Utils/Platform';
|
||||||
|
import * as mime from 'mime-types';
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @hidden
|
|
||||||
*/
|
|
||||||
declare var MediaRecorder: any;
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
*/
|
*/
|
||||||
|
@ -38,17 +34,13 @@ let platform: PlatformUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Easy recording of [[Stream]] objects straightaway from the browser. Initialized with [[OpenVidu.initLocalRecorder]] method
|
* Easy recording of [[Stream]] objects straightaway from the browser. Initialized with [[OpenVidu.initLocalRecorder]] method
|
||||||
*
|
|
||||||
* > WARNINGS:
|
|
||||||
* - Performing browser local recording of **remote streams** may cause some troubles. A long waiting time may be required after calling _LocalRecorder.stop()_ in this case
|
|
||||||
* - Only Chrome and Firefox support local stream recording
|
|
||||||
*/
|
*/
|
||||||
export class LocalRecorder {
|
export class LocalRecorder {
|
||||||
|
|
||||||
state: LocalRecorderState;
|
state: LocalRecorderState;
|
||||||
|
|
||||||
private connectionId: string;
|
private connectionId: string;
|
||||||
private mediaRecorder: any;
|
private mediaRecorder: MediaRecorder;
|
||||||
private chunks: any[] = [];
|
private chunks: any[] = [];
|
||||||
private blob?: Blob;
|
private blob?: Blob;
|
||||||
private id: string;
|
private id: string;
|
||||||
|
@ -69,46 +61,54 @@ export class LocalRecorder {
|
||||||
/**
|
/**
|
||||||
* Starts the recording of the Stream. [[state]] property must be `READY`. After method succeeds is set to `RECORDING`
|
* Starts the recording of the Stream. [[state]] property must be `READY`. After method succeeds is set to `RECORDING`
|
||||||
*
|
*
|
||||||
* @param mimeType The [MediaRecorder.mimeType](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/mimeType) to be used to record this Stream.
|
* @param options The [MediaRecorder.options](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/MediaRecorder#parameters) to be used to record this Stream.
|
||||||
* Make sure the platform supports it or the promise will return an error. If this parameter is not provided, the MediaRecorder will use the default codecs available in the platform
|
* For example:
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* var OV = new OpenVidu();
|
||||||
|
* var publisher = await OV.initPublisherAsync();
|
||||||
|
* var localRecorder = OV.initLocalRecorder(publisher.stream);
|
||||||
|
* var options = {
|
||||||
|
* mimeType: 'video/webm;codecs=vp8',
|
||||||
|
* audioBitsPerSecond:128000,
|
||||||
|
* videoBitsPerSecond:2500000
|
||||||
|
* };
|
||||||
|
* localRecorder.record(options);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If not specified, the default options preferred by the platform will be used.
|
||||||
*
|
*
|
||||||
* @returns A Promise (to which you can optionally subscribe to) that is resolved if the recording successfully started and rejected with an Error object if not
|
* @returns A Promise (to which you can optionally subscribe to) that is resolved if the recording successfully started and rejected with an Error object if not
|
||||||
*/
|
*/
|
||||||
record(mimeType?: string): Promise<void> {
|
record(options?: any): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
if (typeof MediaRecorder === 'undefined') {
|
if (typeof MediaRecorder === 'undefined') {
|
||||||
logger.error('MediaRecorder not supported on your browser. See compatibility in https://caniuse.com/#search=MediaRecorder');
|
logger.error('MediaRecorder not supported on your device. See compatibility in https://caniuse.com/#search=MediaRecorder');
|
||||||
throw (Error('MediaRecorder not supported on your browser. See compatibility in https://caniuse.com/#search=MediaRecorder'));
|
throw (Error('MediaRecorder not supported on your device. See compatibility in https://caniuse.com/#search=MediaRecorder'));
|
||||||
}
|
}
|
||||||
if (this.state !== LocalRecorderState.READY) {
|
if (this.state !== LocalRecorderState.READY) {
|
||||||
throw (Error('\'LocalRecord.record()\' needs \'LocalRecord.state\' to be \'READY\' (current value: \'' + this.state + '\'). Call \'LocalRecorder.clean()\' or init a new LocalRecorder before'));
|
throw (Error('\'LocalRecord.record()\' needs \'LocalRecord.state\' to be \'READY\' (current value: \'' + this.state + '\'). Call \'LocalRecorder.clean()\' or init a new LocalRecorder before'));
|
||||||
}
|
}
|
||||||
logger.log("Starting local recording of stream '" + this.stream.streamId + "' of connection '" + this.connectionId + "'");
|
logger.log("Starting local recording of stream '" + this.stream.streamId + "' of connection '" + this.connectionId + "'");
|
||||||
|
|
||||||
let options = {};
|
if (!options) {
|
||||||
if (typeof MediaRecorder.isTypeSupported === 'function') {
|
options = { mimeType: 'video/webm' };
|
||||||
if (!!mimeType) {
|
} else if (!options.mimeType) {
|
||||||
if (!MediaRecorder.isTypeSupported(mimeType)) {
|
options.mimeType = 'video/webm';
|
||||||
return reject(new Error('mimeType "' + mimeType + '" is not supported'));
|
|
||||||
}
|
|
||||||
options = { mimeType };
|
|
||||||
} else {
|
|
||||||
logger.log('No mimeType parameter provided. Using default codecs');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.warn('MediaRecorder#isTypeSupported is not supported. Using default codecs');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mediaRecorder = new MediaRecorder(this.stream.getMediaStream(), options);
|
this.mediaRecorder = new MediaRecorder(this.stream.getMediaStream(), options);
|
||||||
this.mediaRecorder.start(10);
|
this.mediaRecorder.start();
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mediaRecorder.ondataavailable = (e) => {
|
this.mediaRecorder.ondataavailable = (e) => {
|
||||||
|
if (e.data.size > 0) {
|
||||||
this.chunks.push(e.data);
|
this.chunks.push(e.data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.mediaRecorder.onerror = (e) => {
|
this.mediaRecorder.onerror = (e) => {
|
||||||
|
@ -131,10 +131,6 @@ export class LocalRecorder {
|
||||||
logger.log('MediaRecorder resumed (state=' + this.mediaRecorder.state + ')');
|
logger.log('MediaRecorder resumed (state=' + this.mediaRecorder.state + ')');
|
||||||
};
|
};
|
||||||
|
|
||||||
this.mediaRecorder.onwarning = (e) => {
|
|
||||||
logger.log('MediaRecorder warning: ' + e);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.state = LocalRecorderState.RECORDING;
|
this.state = LocalRecorderState.RECORDING;
|
||||||
return resolve();
|
return resolve();
|
||||||
|
|
||||||
|
@ -243,7 +239,6 @@ export class LocalRecorder {
|
||||||
const f = () => {
|
const f = () => {
|
||||||
delete this.blob;
|
delete this.blob;
|
||||||
this.chunks = [];
|
this.chunks = [];
|
||||||
delete this.mediaRecorder;
|
|
||||||
this.state = LocalRecorderState.READY;
|
this.state = LocalRecorderState.READY;
|
||||||
};
|
};
|
||||||
if (this.state === LocalRecorderState.RECORDING || this.state === LocalRecorderState.PAUSED) {
|
if (this.state === LocalRecorderState.RECORDING || this.state === LocalRecorderState.PAUSED) {
|
||||||
|
@ -267,7 +262,7 @@ export class LocalRecorder {
|
||||||
|
|
||||||
const url = window.URL.createObjectURL(<any>this.blob);
|
const url = window.URL.createObjectURL(<any>this.blob);
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = this.id + '.webm';
|
a.download = this.id + '.' + mime.extension(this.blob!.type);
|
||||||
a.click();
|
a.click();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
@ -352,7 +347,7 @@ export class LocalRecorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendable = new FormData();
|
const sendable = new FormData();
|
||||||
sendable.append('file', this.blob!, this.id + '.webm');
|
sendable.append('file', this.blob!, this.id + '.' + mime.extension(this.blob!.type));
|
||||||
|
|
||||||
http.onreadystatechange = () => {
|
http.onreadystatechange = () => {
|
||||||
if (http.readyState === 4) {
|
if (http.readyState === 4) {
|
||||||
|
@ -376,7 +371,7 @@ export class LocalRecorder {
|
||||||
private onStopDefault(): void {
|
private onStopDefault(): void {
|
||||||
logger.log('MediaRecorder stopped (state=' + this.mediaRecorder.state + ')');
|
logger.log('MediaRecorder stopped (state=' + this.mediaRecorder.state + ')');
|
||||||
|
|
||||||
this.blob = new Blob(this.chunks, { type: 'video/webm' });
|
this.blob = new Blob(this.chunks, { type: this.mediaRecorder.mimeType });
|
||||||
this.chunks = [];
|
this.chunks = [];
|
||||||
|
|
||||||
this.videoPreviewSrc = window.URL.createObjectURL(this.blob);
|
this.videoPreviewSrc = window.URL.createObjectURL(this.blob);
|
||||||
|
|
Loading…
Reference in New Issue