Unreviewed, rolling out r238844, r238846, and r238874.
[WebKit-https.git] / Source / WebCore / Modules / mediarecorder / MediaRecorder.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25
26 #include "config.h"
27 #include "MediaRecorder.h"
28
29 #if ENABLE(MEDIA_STREAM)
30
31 #include "Blob.h"
32 #include "BlobEvent.h"
33 #include "Document.h"
34 #include "EventNames.h"
35 #include "MediaRecorderErrorEvent.h"
36 #include "MediaRecorderPrivateMock.h"
37
38 namespace WebCore {
39
40 Ref<MediaRecorder> MediaRecorder::create(Document& document, Ref<MediaStream>&& stream, Options&& options)
41 {
42     auto recorder = adoptRef(*new MediaRecorder(document, WTFMove(stream), WTFMove(options)));
43     recorder->suspendIfNeeded();
44     return recorder;
45 }
46
47 MediaRecorder::MediaRecorder(Document& document, Ref<MediaStream>&& stream, Options&& option)
48     : ActiveDOMObject(&document)
49     , m_options(WTFMove(option))
50     , m_stream(WTFMove(stream))
51     , m_private(makeUniqueRef<MediaRecorderPrivateMock>()) // FIXME: we will need to decide which MediaRecorderPrivate instance to create based on the mock enabled feature flag
52 {
53     m_tracks = WTF::map(m_stream->getTracks(), [] (auto&& track) -> Ref<MediaStreamTrackPrivate> {
54         return track->privateTrack();
55     });
56     m_stream->addObserver(this);
57 }
58
59 MediaRecorder::~MediaRecorder()
60 {
61     m_stream->removeObserver(this);
62     stopRecordingInternal();
63 }
64
65 void MediaRecorder::stop()
66 {
67     m_isActive = false;
68     stopRecordingInternal();
69 }
70
71 const char* MediaRecorder::activeDOMObjectName() const
72 {
73     return "MediaRecorder";
74 }
75
76 bool MediaRecorder::canSuspendForDocumentSuspension() const
77 {
78     return false; // FIXME: We should do better here as this prevents entering PageCache.
79 }
80
81 ExceptionOr<void> MediaRecorder::startRecording(std::optional<int> timeslice)
82 {
83     UNUSED_PARAM(timeslice);
84     if (state() != RecordingState::Inactive)
85         return Exception { InvalidStateError, "The MediaRecorder's state must be inactive in order to start recording"_s };
86     
87     for (auto& track : m_tracks)
88         track->addObserver(*this);
89
90     m_state = RecordingState::Recording;
91     return { };
92 }
93
94 ExceptionOr<void> MediaRecorder::stopRecording()
95 {
96     if (state() == RecordingState::Inactive)
97         return Exception { InvalidStateError, "The MediaRecorder's state cannot be inactive"_s };
98
99     scheduleDeferredTask([this] {
100         if (!m_isActive || state() == RecordingState::Inactive)
101             return;
102
103         stopRecordingInternal();
104         ASSERT(m_state == RecordingState::Inactive);
105         dispatchEvent(BlobEvent::create(eventNames().dataavailableEvent, Event::CanBubble::No, Event::IsCancelable::No, m_private->fetchData()));
106         if (!m_isActive)
107             return;
108         dispatchEvent(Event::create(eventNames().stopEvent, Event::CanBubble::No, Event::IsCancelable::No));
109     });
110     return { };
111 }
112
113 void MediaRecorder::stopRecordingInternal()
114 {
115     if (state() != RecordingState::Recording)
116         return;
117
118     for (auto& track : m_tracks)
119         track->removeObserver(*this);
120
121     m_state = RecordingState::Inactive;
122 }
123
124 void MediaRecorder::didAddOrRemoveTrack()
125 {
126     scheduleDeferredTask([this] {
127         if (!m_isActive || state() == RecordingState::Inactive)
128             return;
129         auto event = MediaRecorderErrorEvent::create(eventNames().errorEvent, Exception { UnknownError, "Track cannot be added to or removed from the MediaStream while recording is happening"_s });
130         setNewRecordingState(RecordingState::Inactive, WTFMove(event));
131     });
132 }
133
134 void MediaRecorder::trackEnded(MediaStreamTrackPrivate&)
135 {
136     auto position = m_tracks.findMatching([](auto& track) {
137         return !track->ended();
138     });
139     if (position != notFound)
140         return;
141
142     stopRecording();
143 }
144
145 void MediaRecorder::sampleBufferUpdated(MediaStreamTrackPrivate& track, MediaSample& mediaSample)
146 {
147     m_private->sampleBufferUpdated(track, mediaSample);
148 }
149
150 void MediaRecorder::audioSamplesAvailable(MediaStreamTrackPrivate& track, const MediaTime& mediaTime, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t sampleCount)
151 {
152     m_private->audioSamplesAvailable(track, mediaTime, audioData, description, sampleCount);
153 }
154
155 void MediaRecorder::setNewRecordingState(RecordingState newState, Ref<Event>&& event)
156 {
157     m_state = newState;
158     dispatchEvent(WTFMove(event));
159 }
160
161 void MediaRecorder::scheduleDeferredTask(Function<void()>&& function)
162 {
163     ASSERT(function);
164     auto* scriptExecutionContext = this->scriptExecutionContext();
165     if (!scriptExecutionContext)
166         return;
167     scriptExecutionContext->postTask([protectedThis = makeRef(*this), function = WTFMove(function)] (auto&) {
168         function();
169     });
170 }
171
172 } // namespace WebCore
173
174 #endif // ENABLE(MEDIA_STREAM)