Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: Source/modules/mediastream/MediaRecorder.cpp

Issue 1255873002: MediaRecorder Blink part (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/mediastream/MediaRecorder.h"
7
8 #include "core/dom/DOMError.h"
9 #include "core/fileapi/Blob.h"
10 #include "modules/EventModules.h"
11 #include "modules/EventTargetModules.h"
12 #include "modules/mediastream/BlobEvent.h"
13 #include "modules/mediastream/MediaRecorderErrorEvent.h"
14 #include "public/platform/Platform.h"
15 #include "public/platform/WebMediaStream.h"
16
17 namespace blink {
18
19 namespace {
20
21 const AtomicString& inactiveState()
22 {
23 DEFINE_STATIC_LOCAL(const AtomicString, ended, ("inactive", AtomicString::Co nstructFromLiteral));
24 return ended;
25 }
26
27 const AtomicString& recordingState()
28 {
29 DEFINE_STATIC_LOCAL(const AtomicString, ended, ("recording", AtomicString::C onstructFromLiteral));
30 return ended;
31 }
32
33 const AtomicString& pausedState()
34 {
35 DEFINE_STATIC_LOCAL(const AtomicString, ended, ("paused", AtomicString::Cons tructFromLiteral));
36 return ended;
37 }
38
39 } // namespace
40
41 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, ExceptionState& exceptionState)
42 {
43 MediaRecorder* recorder = new MediaRecorder(context, stream, String(), excep tionState);
44 recorder->suspendIfNeeded();
45
46 return recorder;
47 }
48
49 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, const String& mimeType, ExceptionState& exceptionState)
50 {
51 MediaRecorder* recorder = new MediaRecorder(context, stream, mimeType, excep tionState);
52 recorder->suspendIfNeeded();
53
54 return recorder;
55 }
56
57 MediaRecorder::MediaRecorder(ExecutionContext* context, MediaStream* stream, con st String& mimeType, ExceptionState& exceptionState)
58 : ActiveDOMObject(context)
59 , m_stream(stream)
60 , m_stopped(false)
61 , m_mimeType(mimeType)
62 , m_state(inactiveState())
63 , m_ignoreMutedMedia(true)
64 , m_dispatchScheduledEventRunner(this, &MediaRecorder::dispatchScheduledEven t)
65 {
66 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ());
67
68 if (!m_recorderHandler) {
69 m_stopped = true;
70 exceptionState.throwDOMException(NotSupportedError,
71 "No MediaRecorder handler can be created.");
Peter Beverloo 2015/07/29 16:54:22 I find this more often in media code, but if I wer
mcasas 2015/07/30 13:20:36 I can imagine an unsupported mimeType, f.i. record
72 return;
73 }
74
75 if (!m_recorderHandler->initialize(this, stream->descriptor(), m_mimeType)) {
76 m_stopped = true;
77 exceptionState.throwDOMException(NotSupportedError,
78 "Failed to initialize native MediaRecorder.");
79 return;
80 }
81 }
82
83 MediaRecorder::~MediaRecorder()
84 {
85 }
86
87 void MediaRecorder::start(ExceptionState& exceptionState)
88 {
89 if (m_state != inactiveState()) {
90 exceptionState.throwDOMException(InvalidStateError,
91 "The MediaRecorder's state is '" + m_state + "'.");
92 return;
93 }
94 m_state = recordingState();
95
96 m_recorderHandler->start();
97 }
98
99 void MediaRecorder::start(int& timeSlice, ExceptionState& exceptionState)
100 {
101 if (m_state != inactiveState()) {
102 exceptionState.throwDOMException(InvalidStateError,
103 "The MediaRecorder's state is '" + m_state + "'.");
104 return;
105 }
106 m_state = recordingState();
107
108 m_recorderHandler->start(timeSlice);
109 }
110
111 void MediaRecorder::stop(ExceptionState& exceptionState)
112 {
113 if (m_state == inactiveState()) {
114 exceptionState.throwDOMException(InvalidStateError,
115 "The MediaRecorder's state is '" + m_state + "'.");
116 return;
117 }
118
119 // Raise a dataavailable event containing the Blob of data that has been gat hered.
120 // Raise a stop event.
121 doStop();
122 }
123
124 void MediaRecorder::pause(ExceptionState& exceptionState)
125 {
126 if (m_state == inactiveState()) {
127 exceptionState.throwDOMException(InvalidStateError,
128 "The MediaRecorder's state is '" + m_state + "'.");
129 return;
130 }
131 if (m_state == pausedState())
132 return;
133
134 m_state = pausedState();
135
136 m_recorderHandler->pause();
137
138 scheduleDispatchEvent(Event::create(EventTypeNames::pause));
139 }
140
141 void MediaRecorder::resume(ExceptionState& exceptionState)
142 {
143 if (m_state == inactiveState()) {
144 exceptionState.throwDOMException(InvalidStateError,
145 "The MediaRecorder's state is '" + m_state + "'.");
146 return;
147 }
148 if (m_state == recordingState())
149 return;
150
151 m_state = recordingState();
152
153 m_recorderHandler->resume();
154 }
155
156 void MediaRecorder::requestData(ExceptionState& exceptionState)
157 {
158 if (m_state != recordingState()) {
159 exceptionState.throwDOMException(InvalidStateError,
160 "The MediaRecorder's state is '" + m_state + "'.");
161 return;
162 }
163
164 createBlobEvent(BlobData::create());
165 }
166
167 String MediaRecorder::canRecordMimeType(const String& mimeType)
168 {
169 RawPtr<WebMediaRecorderHandler> handler = Platform::current()->createMediaRe corderHandler();
Peter Beverloo 2015/07/29 16:54:22 This is a bit unfortunate. The embedder could end
mcasas 2015/07/30 13:20:36 I know :( Is there any way to have a WebMediaStrea
170 if (!handler)
171 return "";
172
173 return handler->canSupportMimeType(mimeType) ? "maybe" : "";
Peter Beverloo 2015/07/29 16:54:22 This is a tri-state: (1) The empty string if th
mcasas 2015/07/30 13:20:36 Yes but the same doc says: "Implementors are encou
174 }
175
176 const AtomicString& MediaRecorder::interfaceName() const
177 {
178 return EventTargetNames::MediaRecorder;
179 }
180
181 ExecutionContext* MediaRecorder::executionContext() const
182 {
183 return ActiveDOMObject::executionContext();
184 }
185
186 void MediaRecorder::suspend()
187 {
188 m_dispatchScheduledEventRunner.suspend();
189 }
190
191 void MediaRecorder::resume()
192 {
193 m_dispatchScheduledEventRunner.resume();
194 }
195
196 void MediaRecorder::stop()
197 {
198 if (m_stopped)
199 return;
200
201 m_stopped = true;
202 m_stream.clear();
203 m_recorderHandler.clear();
204
205 m_dispatchScheduledEventRunner.stop();
206 }
207
208 void MediaRecorder::writeData(const char* data, size_t length, bool lastInSlice)
209 {
210 ASSERT(m_state == recordingState());
211
212 if (m_stopped) {
213 m_stopped = false;
214 scheduleDispatchEvent(Event::create(EventTypeNames::start));
215 }
216
217 // TODO(mcasas): Use |lastInSlice| to indicate to JS that recording is done.
218
219 OwnPtr<BlobData> blobData = BlobData::create();
220 blobData->appendBytes(data, length);
221 createBlobEvent(blobData.release());
222 }
223
224 void MediaRecorder::failOutOfMemory(const WebString& message)
225 {
226 scheduleDispatchEvent(MediaRecorderErrorEvent::create(
227 EventTypeNames::error, false, false, "OutOfMemory", message));
228
229 if (m_state == recordingState())
230 doStop();
231 }
232
233 void MediaRecorder::failIllegalStreamModification(const WebString& message)
234 {
235 scheduleDispatchEvent(MediaRecorderErrorEvent::create(
236 EventTypeNames::error, false, false, "IllegalStreamModification", messag e));
237
238 if (m_state == recordingState())
239 doStop();
240 }
241
242 void MediaRecorder::failOtherRecordingError(const WebString& message)
243 {
244 scheduleDispatchEvent(MediaRecorderErrorEvent::create(
245 EventTypeNames::error, false, false, "OtherRecordingError", message));
246
247 if (m_state == recordingState())
248 doStop();
249 }
250
251 void MediaRecorder::createBlobEvent(PassOwnPtr<BlobData> blobData)
252 {
253 // blobData (Move-only) -> BlobDataHandle (ref-cnt) -> Blob
254 const long long length = blobData->length();
255 RefPtr<BlobDataHandle> blob_data_handle =
256 BlobDataHandle::create(blobData, length);
257
258 scheduleDispatchEvent(BlobEvent::create(EventTypeNames::dataavailable,
259 false, false, Blob::create(blob_data_handle)));
260 }
261
262 void MediaRecorder::doStop()
263 {
264 ASSERT(m_state != inactiveState());
265 m_state = inactiveState();
266
267 m_recorderHandler->stop();
268
269 createBlobEvent(BlobData::create());
Peter Beverloo 2015/07/29 16:54:22 Is this correct? Suppose that you have this code:
mcasas 2015/07/30 13:20:36 I presume it has to do with the way start() is cal
270
271 scheduleDispatchEvent(Event::create(EventTypeNames::stop));
272 }
273
274 void MediaRecorder::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
275 {
276 m_scheduledEvents.append(event);
277
278 m_dispatchScheduledEventRunner.runAsync();
279 }
280
281 void MediaRecorder::dispatchScheduledEvent()
282 {
283 if (m_stopped)
284 return;
285
286 WillBeHeapVector<RefPtrWillBeMember<Event>> events;
287 events.swap(m_scheduledEvents);
288
289 WillBeHeapVector<RefPtrWillBeMember<Event>>::iterator it = events.begin();
290 for (; it != events.end(); ++it)
291 dispatchEvent((*it).release());
292
293 events.clear();
294 }
295
296 DEFINE_TRACE(MediaRecorder)
297 {
298 visitor->trace(m_stream);
299 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor);
300 ActiveDOMObject::trace(visitor);
301 }
302
303 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698