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

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: tommi@s comments. Added dummy Source/platform/exported/WebMediaRecorderHandlerClient.cpp 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 static String MediaRecorderStateToString(MediaRecorder::MediaRecorderState state )
22 {
23 switch (state) {
24 case MediaRecorder::MediaRecorderState::Inactive:
25 return "inactive";
26 case MediaRecorder::MediaRecorderState::Recording:
27 return "recording";
28 case MediaRecorder::MediaRecorderState::Paused:
29 return "paused";
30 }
31
32 ASSERT_NOT_REACHED();
33 return String();
34 }
35
36 } // namespace
37
38 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, ExceptionState& exceptionState)
39 {
40 MediaRecorder* recorder = new MediaRecorder(context, stream, String(), excep tionState);
41 recorder->suspendIfNeeded();
42
43 return recorder;
44 }
45
46 MediaRecorder* MediaRecorder::create(ExecutionContext* context, MediaStream* str eam, const String& mimeType, ExceptionState& exceptionState)
47 {
48 MediaRecorder* recorder = new MediaRecorder(context, stream, mimeType, excep tionState);
49 recorder->suspendIfNeeded();
50
51 return recorder;
52 }
53
54 MediaRecorder::MediaRecorder(ExecutionContext* context, MediaStream* stream, con st String& mimeType, ExceptionState& exceptionState)
55 : ActiveDOMObject(context)
56 , m_stream(stream)
57 , m_stopped(false)
58 , m_mimeType(mimeType)
59 , m_ignoreMutedMedia(true)
60 , m_state(MediaRecorderState::Inactive)
61 , m_dispatchScheduledEventRunner(this, &MediaRecorder::dispatchScheduledEven t)
62 {
63 m_recorderHandler = adoptPtr(Platform::current()->createMediaRecorderHandler ());
64
65 // TODO(mcasas): Once http://crbug.com/262211 has landed the Chromium parts,
66 // and more concretetely the createMediaRecorderHandler() implementation,
67 // ASSERT() here for |m_recorderHandler|.
68 if (!m_recorderHandler) {
69 m_stopped = true;
70 exceptionState.throwDOMException(NotSupportedError, "No MediaRecorder ha ndler can be created.");
71 return;
72 }
73
74 if (!m_recorderHandler->initialize(this, stream->descriptor(), m_mimeType)) {
75 m_stopped = true;
76 exceptionState.throwDOMException(NotSupportedError, "Failed to initializ e native MediaRecorder.");
77 return;
78 }
79 }
80
81 String MediaRecorder::state() const {
esprehn 2015/08/12 22:27:34 braces go on the next line
mcasas 2015/08/13 09:31:50 Done.
82 return MediaRecorderStateToString(m_state);
83 }
84
85 void MediaRecorder::start(ExceptionState& exceptionState)
86 {
87 if (m_state != MediaRecorderState::Inactive) {
88 exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + MediaRecorderStateToString(m_state) + "'.");
89 return;
90 }
91 m_state = MediaRecorderState::Recording;
esprehn 2015/08/12 22:27:34 You don't need the prefix since the enum is nested
mcasas 2015/08/13 09:31:50 I do because State is an enum class.
92
93 m_recorderHandler->start();
94 }
95
96 void MediaRecorder::start(int& timeSlice, ExceptionState& exceptionState)
97 {
98 if (m_state != MediaRecorderState::Inactive) {
99 exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + MediaRecorderStateToString(m_state) + "'.");
100 return;
101 }
102 m_state = MediaRecorderState::Recording;
103
104 m_recorderHandler->start(timeSlice);
105 }
106
107 void MediaRecorder::stop(ExceptionState& exceptionState)
108 {
109 if (m_state == MediaRecorderState::Inactive) {
110 exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + MediaRecorderStateToString(m_state) + "'.");
111 return;
112 }
113
114 // Raise a dataavailable event containing the Blob of data that has been gat hered.
115 // Raise a stop event.
116 doStop();
117 }
118
119 void MediaRecorder::pause(ExceptionState& exceptionState)
120 {
121 if (m_state == MediaRecorderState::Inactive) {
122 exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + MediaRecorderStateToString(m_state) + "'.");
123 return;
124 }
125 if (m_state == MediaRecorderState::Paused)
126 return;
127
128 m_state = MediaRecorderState::Paused;
129
130 m_recorderHandler->pause();
131
132 scheduleDispatchEvent(Event::create(EventTypeNames::pause));
133 }
134
135 void MediaRecorder::resume(ExceptionState& exceptionState)
136 {
137 if (m_state == MediaRecorderState::Inactive) {
138 exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + MediaRecorderStateToString(m_state) + "'.");
139 return;
140 }
141 if (m_state == MediaRecorderState::Recording)
142 return;
143
144 m_state = MediaRecorderState::Recording;
145
146 m_recorderHandler->resume();
147 }
148
149 void MediaRecorder::requestData(ExceptionState& exceptionState)
150 {
151 if (m_state != MediaRecorderState::Recording) {
152 exceptionState.throwDOMException(InvalidStateError, "The MediaRecorder's state is '" + MediaRecorderStateToString(m_state) + "'.");
153 return;
154 }
155
156 createBlobEvent(BlobData::create());
157 }
158
159 String MediaRecorder::canRecordMimeType(const String& mimeType)
160 {
161 RawPtr<WebMediaRecorderHandler> handler = Platform::current()->createMediaRe corderHandler();
162 if (!handler)
163 return "";
164
165 // MediaRecorder canRecordMimeType() MUST return 'probably' "if the UA is
166 // confident that mimeType represents a type that it can record" [1], but a
167 // number of reasons could prevent the recording from happening as expected,
168 // so 'maybe' is a better option: "Implementors are encouraged to return
169 // "maybe" unless the type can be confidently established as being supported
170 // or not.". Hence this method returns '' or 'maybe', never 'probably'.
171 // [1] http://w3c.github.io/mediacapture-record/MediaRecorder.html#methods
esprehn 2015/08/12 22:27:34 We should get probably removed from the spec if we
mcasas 2015/08/13 09:31:50 I agree, this is a source of confusion, and might
172 return handler->canSupportMimeType(mimeType) ? "maybe" : "";
173 }
174
175 const AtomicString& MediaRecorder::interfaceName() const
176 {
177 return EventTargetNames::MediaRecorder;
178 }
179
180 ExecutionContext* MediaRecorder::executionContext() const
181 {
182 return ActiveDOMObject::executionContext();
183 }
184
185 void MediaRecorder::stop()
186 {
187 if (m_stopped)
188 return;
189
190 m_stopped = true;
191 m_stream.clear();
192 m_recorderHandler.clear();
193
194 m_dispatchScheduledEventRunner.stop();
195 }
196
197 void MediaRecorder::writeData(const char* data, size_t length, bool lastInSlice)
198 {
199 ASSERT(m_state == MediaRecorderState::Recording);
200
201 if (m_stopped) {
202 m_stopped = false;
203 scheduleDispatchEvent(Event::create(EventTypeNames::start));
204 }
205
206 // TODO(mcasas): Use |lastInSlice| to indicate to JS that recording is done.
207
208 OwnPtr<BlobData> blobData = BlobData::create();
209 blobData->appendBytes(data, length);
210 createBlobEvent(blobData.release());
211 }
212
213 void MediaRecorder::failOutOfMemory(const WebString& message)
214 {
215 scheduleDispatchEvent(MediaRecorderErrorEvent::create(
216 EventTypeNames::error, false, false, "OutOfMemory", message));
217
218 if (m_state == MediaRecorderState::Recording)
219 doStop();
220 }
221
222 void MediaRecorder::failIllegalStreamModification(const WebString& message)
223 {
224 scheduleDispatchEvent(MediaRecorderErrorEvent::create(
225 EventTypeNames::error, false, false, "IllegalStreamModification", messag e));
226
227 if (m_state == MediaRecorderState::Recording)
228 doStop();
229 }
230
231 void MediaRecorder::failOtherRecordingError(const WebString& message)
232 {
233 scheduleDispatchEvent(MediaRecorderErrorEvent::create(
234 EventTypeNames::error, false, false, "OtherRecordingError", message));
235
236 if (m_state == MediaRecorderState::Recording)
237 doStop();
238 }
239
240 void MediaRecorder::createBlobEvent(PassOwnPtr<BlobData> blobData)
241 {
242 // blobData (Move-only) -> BlobDataHandle (ref-cnt) -> Blob
esprehn 2015/08/12 22:27:34 remove comment
mcasas 2015/08/13 09:31:50 Done.
243 const long long length = blobData->length();
244 RefPtr<BlobDataHandle> blob_data_handle =
esprehn 2015/08/12 22:27:34 blobDataHandle, no _ names in blink.
mcasas 2015/08/13 09:31:50 Done.
245 BlobDataHandle::create(blobData, length);
246
247 scheduleDispatchEvent(BlobEvent::create(EventTypeNames::dataavailable,
248 false, false, Blob::create(blob_data_handle)));
249 }
250
251 void MediaRecorder::doStop()
252 {
253 ASSERT(m_state != MediaRecorderState::Inactive);
254 m_state = MediaRecorderState::Inactive;
255
256 m_recorderHandler->stop();
257
258 createBlobEvent(BlobData::create());
259
260 scheduleDispatchEvent(Event::create(EventTypeNames::stop));
261 }
262
263 void MediaRecorder::scheduleDispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
264 {
265 m_scheduledEvents.append(event);
266
267 m_dispatchScheduledEventRunner.runAsync();
268 }
269
270 void MediaRecorder::dispatchScheduledEvent()
271 {
272 if (m_stopped)
273 return;
274
275 WillBeHeapVector<RefPtrWillBeMember<Event>> events;
276 events.swap(m_scheduledEvents);
277
278 WillBeHeapVector<RefPtrWillBeMember<Event>>::iterator it = events.begin();
279 for (; it != events.end(); ++it)
280 dispatchEvent((*it).release());
281
282 events.clear();
283 }
284
285 DEFINE_TRACE(MediaRecorder)
286 {
287 visitor->trace(m_stream);
288 RefCountedGarbageCollectedEventTargetWithInlineData<MediaRecorder>::trace(vi sitor);
289 ActiveDOMObject::trace(visitor);
290 }
291
292 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698