Skip to content

Commit 03d2747

Browse files
committed
1 parent ef373f7 commit 03d2747

34 files changed

+165
-4886
lines changed

AudioStreamRecorder/MediaRecorder.js

Lines changed: 85 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function MediaRecorderWrapper(mediaStream) {
1616
// if user chosen only audio option; and he tried to pass MediaStream with
1717
// both audio and video tracks;
1818
// using a dirty workaround to generate audio-only stream so that we can get audio/ogg output.
19-
if (this.type == 'audio' && mediaStream.getVideoTracks && mediaStream.getVideoTracks().length) {
19+
if (this.type == 'audio' && mediaStream.getVideoTracks && mediaStream.getVideoTracks().length && !navigator.mozGetUserMedia) {
2020
var context = new AudioContext();
2121
var mediaStreamSource = context.createMediaStreamSource(mediaStream);
2222

@@ -25,87 +25,106 @@ function MediaRecorderWrapper(mediaStream) {
2525

2626
mediaStream = destination.stream;
2727
}
28-
28+
2929
// void start(optional long timeSlice)
3030
// timestamp to fire "ondataavailable"
31-
31+
3232
// starting a recording session; which will initiate "Reading Thread"
3333
// "Reading Thread" are used to prevent main-thread blocking scenarios
3434
this.start = function(mTimeSlice) {
3535
mTimeSlice = mTimeSlice || 1000;
3636

37-
mediaRecorder = new MediaRecorder(mediaStream);
38-
mediaRecorder.ondataavailable = function(e) {
39-
console.log('ondataavailable', e.data.type, e.data.size, e.data);
40-
// mediaRecorder.state == 'recording' means that media recorder is associated with "session"
41-
// mediaRecorder.state == 'stopped' means that media recorder is detached from the "session" ... in this case; "session" will also be deleted.
42-
43-
if (!e.data.size) {
44-
console.warn('Recording of', e.data.type, 'failed.');
45-
return;
46-
}
47-
48-
// at this stage, Firefox MediaRecorder API doesn't allow to choose the output mimeType format!
49-
var blob = new window.Blob([e.data], {
50-
type: e.data.type || self.mimeType || 'audio/ogg' // It specifies the container format as well as the audio and video capture formats.
51-
});
52-
53-
// Dispatching OnDataAvailable Handler
54-
self.ondataavailable(blob);
55-
};
56-
57-
mediaRecorder.onstop = function(error) {
58-
// for video recording on Firefox, it will be fired quickly.
59-
// because work on VideoFrameContainer is still in progress
60-
// https://wiki.mozilla.org/Gecko:MediaRecorder
61-
self.onstop(error);
62-
};
63-
64-
// http://www.w3.org/TR/2012/WD-dom-20121206/#error-names-table
65-
// showBrowserSpecificIndicator: got neither video nor audio access
66-
// "VideoFrameContainer" can't be accessed directly; unable to find any wrapper using it.
67-
// that's why there is no video recording support on firefox
68-
69-
// video recording fails because there is no encoder available there
70-
// http://dxr.mozilla.org/mozilla-central/source/content/media/MediaRecorder.cpp#317
71-
72-
// Maybe "Read Thread" doesn't fire video-track read notification;
73-
// that's why shutdown notification is received; and "Read Thread" is stopped.
74-
75-
// https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html#error-handling
76-
mediaRecorder.onerror = function(error) {
77-
console.error(error);
78-
self.start(mTimeSlice);
79-
};
80-
81-
mediaRecorder.onwarning = function(warning) {
82-
console.warn(warning);
83-
};
84-
85-
// void start(optional long mTimeSlice)
86-
// The interval of passing encoded data from EncodedBufferCache to onDataAvailable
87-
// handler. "mTimeSlice < 0" means Session object does not push encoded data to
88-
// onDataAvailable, instead, it passive wait the client side pull encoded data
89-
// by calling requestData API.
90-
mediaRecorder.start(mTimeSlice);
91-
92-
// Start recording. If timeSlice has been provided, mediaRecorder will
93-
// raise a dataavailable event containing the Blob of collected data on every timeSlice milliseconds.
94-
// If timeSlice isn't provided, UA should call the RequestData to obtain the Blob data, also set the mTimeSlice to zero.
37+
isStopRecording = false;
38+
function startRecording() {
39+
if(isStopRecording) return;
40+
41+
mediaRecorder = new MediaRecorder(mediaStream);
42+
43+
mediaRecorder.ondataavailable = function(e) {
44+
console.log('ondataavailable', e.data.type, e.data.size, e.data);
45+
// mediaRecorder.state == 'recording' means that media recorder is associated with "session"
46+
// mediaRecorder.state == 'stopped' means that media recorder is detached from the "session" ... in this case; "session" will also be deleted.
47+
48+
if (!e.data.size) {
49+
console.warn('Recording of', e.data.type, 'failed.');
50+
return;
51+
}
52+
53+
// at this stage, Firefox MediaRecorder API doesn't allow to choose the output mimeType format!
54+
var blob = new window.Blob([e.data], {
55+
type: e.data.type || self.mimeType || 'audio/ogg' // It specifies the container format as well as the audio and video capture formats.
56+
});
57+
58+
// Dispatching OnDataAvailable Handler
59+
self.ondataavailable(blob);
60+
};
61+
62+
mediaRecorder.onstop = function(error) {
63+
// for video recording on Firefox, it will be fired quickly.
64+
// because work on VideoFrameContainer is still in progress
65+
// https://wiki.mozilla.org/Gecko:MediaRecorder
66+
67+
// self.onstop(error);
68+
};
69+
70+
// http://www.w3.org/TR/2012/WD-dom-20121206/#error-names-table
71+
// showBrowserSpecificIndicator: got neither video nor audio access
72+
// "VideoFrameContainer" can't be accessed directly; unable to find any wrapper using it.
73+
// that's why there is no video recording support on firefox
74+
75+
// video recording fails because there is no encoder available there
76+
// http://dxr.mozilla.org/mozilla-central/source/content/media/MediaRecorder.cpp#317
77+
78+
// Maybe "Read Thread" doesn't fire video-track read notification;
79+
// that's why shutdown notification is received; and "Read Thread" is stopped.
80+
81+
// https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html#error-handling
82+
mediaRecorder.onerror = function(error) {
83+
console.error(error);
84+
self.start(mTimeSlice);
85+
};
86+
87+
mediaRecorder.onwarning = function(warning) {
88+
console.warn(warning);
89+
};
90+
91+
// void start(optional long mTimeSlice)
92+
// The interval of passing encoded data from EncodedBufferCache to onDataAvailable
93+
// handler. "mTimeSlice < 0" means Session object does not push encoded data to
94+
// onDataAvailable, instead, it passive wait the client side pull encoded data
95+
// by calling requestData API.
96+
mediaRecorder.start(0);
97+
98+
// Start recording. If timeSlice has been provided, mediaRecorder will
99+
// raise a dataavailable event containing the Blob of collected data on every timeSlice milliseconds.
100+
// If timeSlice isn't provided, UA should call the RequestData to obtain the Blob data, also set the mTimeSlice to zero.
101+
102+
setTimeout(function() {
103+
mediaRecorder.stop();
104+
startRecording();
105+
}, mTimeSlice);
106+
}
107+
108+
// dirty workaround to fix Firefox 2nd+ intervals
109+
startRecording();
95110
};
96111

112+
var isStopRecording = false;
113+
97114
this.stop = function() {
98-
if (mediaRecorder && mediaRecorder.state == 'recording') {
99-
mediaRecorder.stop();
115+
isStopRecording = true;
116+
117+
if(self.onstop) {
118+
self.onstop({});
100119
}
101120
};
102121

103-
this.ondataavailable = this.onstop = function() { };
122+
this.ondataavailable = this.onstop = function() {};
104123

105124
// Reference to itself
106125
var self = this;
107-
108-
if(!self.mimeType) {
126+
127+
if (!self.mimeType && !!mediaStream.getAudioTracks) {
109128
self.mimeType = mediaStream.getAudioTracks().length && mediaStream.getVideoTracks().length ? 'video/webm' : 'audio/ogg';
110129
}
111130

MediaStreamRecorder-standalone.js

Lines changed: 74 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ function MediaRecorderWrapper(mediaStream) {
144144
// if user chosen only audio option; and he tried to pass MediaStream with
145145
// both audio and video tracks;
146146
// using a dirty workaround to generate audio-only stream so that we can get audio/ogg output.
147-
if (this.type == 'audio' && mediaStream.getVideoTracks && mediaStream.getVideoTracks().length) {
147+
if (this.type == 'audio' && mediaStream.getVideoTracks && mediaStream.getVideoTracks().length && !navigator.mozGetUserMedia) {
148148
var context = new AudioContext();
149149
var mediaStreamSource = context.createMediaStreamSource(mediaStream);
150150

@@ -153,87 +153,106 @@ function MediaRecorderWrapper(mediaStream) {
153153

154154
mediaStream = destination.stream;
155155
}
156-
156+
157157
// void start(optional long timeSlice)
158158
// timestamp to fire "ondataavailable"
159-
159+
160160
// starting a recording session; which will initiate "Reading Thread"
161161
// "Reading Thread" are used to prevent main-thread blocking scenarios
162162
this.start = function(mTimeSlice) {
163163
mTimeSlice = mTimeSlice || 1000;
164+
isStopRecording = false;
164165

165-
mediaRecorder = new MediaRecorder(mediaStream);
166-
mediaRecorder.ondataavailable = function(e) {
167-
console.log('ondataavailable', e.data.type, e.data.size, e.data);
168-
// mediaRecorder.state == 'recording' means that media recorder is associated with "session"
169-
// mediaRecorder.state == 'stopped' means that media recorder is detached from the "session" ... in this case; "session" will also be deleted.
166+
function startRecording() {
167+
if(isStopRecording) return;
170168

171-
if (!e.data.size) {
172-
console.warn('Recording of', e.data.type, 'failed.');
173-
return;
174-
}
169+
mediaRecorder = new MediaRecorder(mediaStream);
175170

176-
// at this stage, Firefox MediaRecorder API doesn't allow to choose the output mimeType format!
177-
var blob = new window.Blob([e.data], {
178-
type: e.data.type || self.mimeType || 'audio/ogg' // It specifies the container format as well as the audio and video capture formats.
179-
});
171+
mediaRecorder.ondataavailable = function(e) {
172+
console.log('ondataavailable', e.data.type, e.data.size, e.data);
173+
// mediaRecorder.state == 'recording' means that media recorder is associated with "session"
174+
// mediaRecorder.state == 'stopped' means that media recorder is detached from the "session" ... in this case; "session" will also be deleted.
180175

181-
// Dispatching OnDataAvailable Handler
182-
self.ondataavailable(blob);
183-
};
176+
if (!e.data.size) {
177+
console.warn('Recording of', e.data.type, 'failed.');
178+
return;
179+
}
184180

185-
mediaRecorder.onstop = function(error) {
186-
// for video recording on Firefox, it will be fired quickly.
187-
// because work on VideoFrameContainer is still in progress
188-
// https://wiki.mozilla.org/Gecko:MediaRecorder
189-
self.onstop(error);
190-
};
181+
// at this stage, Firefox MediaRecorder API doesn't allow to choose the output mimeType format!
182+
var blob = new window.Blob([e.data], {
183+
type: e.data.type || self.mimeType || 'audio/ogg' // It specifies the container format as well as the audio and video capture formats.
184+
});
191185

192-
// http://www.w3.org/TR/2012/WD-dom-20121206/#error-names-table
193-
// showBrowserSpecificIndicator: got neither video nor audio access
194-
// "VideoFrameContainer" can't be accessed directly; unable to find any wrapper using it.
195-
// that's why there is no video recording support on firefox
186+
// Dispatching OnDataAvailable Handler
187+
self.ondataavailable(blob);
188+
};
196189

197-
// video recording fails because there is no encoder available there
198-
// http://dxr.mozilla.org/mozilla-central/source/content/media/MediaRecorder.cpp#317
190+
mediaRecorder.onstop = function(error) {
191+
// for video recording on Firefox, it will be fired quickly.
192+
// because work on VideoFrameContainer is still in progress
193+
// https://wiki.mozilla.org/Gecko:MediaRecorder
199194

200-
// Maybe "Read Thread" doesn't fire video-track read notification;
201-
// that's why shutdown notification is received; and "Read Thread" is stopped.
195+
// self.onstop(error);
196+
};
202197

203-
// https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html#error-handling
204-
mediaRecorder.onerror = function(error) {
205-
console.error(error);
206-
self.start(mTimeSlice);
207-
};
198+
// http://www.w3.org/TR/2012/WD-dom-20121206/#error-names-table
199+
// showBrowserSpecificIndicator: got neither video nor audio access
200+
// "VideoFrameContainer" can't be accessed directly; unable to find any wrapper using it.
201+
// that's why there is no video recording support on firefox
208202

209-
mediaRecorder.onwarning = function(warning) {
210-
console.warn(warning);
211-
};
203+
// video recording fails because there is no encoder available there
204+
// http://dxr.mozilla.org/mozilla-central/source/content/media/MediaRecorder.cpp#317
212205

213-
// void start(optional long mTimeSlice)
214-
// The interval of passing encoded data from EncodedBufferCache to onDataAvailable
215-
// handler. "mTimeSlice < 0" means Session object does not push encoded data to
216-
// onDataAvailable, instead, it passive wait the client side pull encoded data
217-
// by calling requestData API.
218-
mediaRecorder.start(mTimeSlice);
206+
// Maybe "Read Thread" doesn't fire video-track read notification;
207+
// that's why shutdown notification is received; and "Read Thread" is stopped.
219208

220-
// Start recording. If timeSlice has been provided, mediaRecorder will
221-
// raise a dataavailable event containing the Blob of collected data on every timeSlice milliseconds.
222-
// If timeSlice isn't provided, UA should call the RequestData to obtain the Blob data, also set the mTimeSlice to zero.
209+
// https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html#error-handling
210+
mediaRecorder.onerror = function(error) {
211+
console.error(error);
212+
self.start(mTimeSlice);
213+
};
214+
215+
mediaRecorder.onwarning = function(warning) {
216+
console.warn(warning);
217+
};
218+
219+
// void start(optional long mTimeSlice)
220+
// The interval of passing encoded data from EncodedBufferCache to onDataAvailable
221+
// handler. "mTimeSlice < 0" means Session object does not push encoded data to
222+
// onDataAvailable, instead, it passive wait the client side pull encoded data
223+
// by calling requestData API.
224+
mediaRecorder.start(0);
225+
226+
// Start recording. If timeSlice has been provided, mediaRecorder will
227+
// raise a dataavailable event containing the Blob of collected data on every timeSlice milliseconds.
228+
// If timeSlice isn't provided, UA should call the RequestData to obtain the Blob data, also set the mTimeSlice to zero.
229+
230+
setTimeout(function() {
231+
mediaRecorder.stop();
232+
startRecording();
233+
}, mTimeSlice);
234+
}
235+
236+
// dirty workaround to fix Firefox 2nd+ intervals
237+
startRecording();
223238
};
224239

240+
var isStopRecording = false;
241+
225242
this.stop = function() {
226-
if (mediaRecorder && mediaRecorder.state == 'recording') {
227-
mediaRecorder.stop();
243+
isStopRecording = true;
244+
245+
if(self.onstop) {
246+
self.onstop({});
228247
}
229248
};
230249

231-
this.ondataavailable = this.onstop = function() { };
250+
this.ondataavailable = this.onstop = function() {};
232251

233252
// Reference to itself
234253
var self = this;
235-
236-
if(!self.mimeType) {
254+
255+
if (!self.mimeType && !!mediaStream.getAudioTracks) {
237256
self.mimeType = mediaStream.getAudioTracks().length && mediaStream.getVideoTracks().length ? 'video/webm' : 'audio/ogg';
238257
}
239258

demos/video-recorder.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
<title>WebRTC Video Recording using MediaStreamRecorder</title>
1212

1313
<!--
14-
data-scripts-dir: ../
15-
src: ../MediaStreamRecorder-v1.2.js
14+
data-scripts-dir=""
15+
src="../MediaStreamRecorder-v1.2.js"
16+
data-require="WhammyRecorder,MediaRecorder"
1617
-->
1718
<script
1819
src="https://cdn.webrtc-experiment.com/MediaStreamRecorder-v1.2.js"
1920
data-require="WhammyRecorder,MediaRecorder"
20-
data-scripts-dir="https://cdn.webrtc-experiment.com/msr/">
21+
data-scripts-dir="https://cdn.webrtc-experiment.com/msr/"
22+
>
2123
</script>
2224

2325
<style>

0 commit comments

Comments
 (0)