[WebIDL] Add support for converting dictionaries to JS
[WebKit-https.git] / Source / WebCore / Modules / mediastream / MediaStreamTrack.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2011, 2015 Ericsson AB. All rights reserved.
4  * Copyright (C) 2013 Apple Inc. All rights reserved.
5  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "MediaStreamTrack.h"
30
31 #if ENABLE(MEDIA_STREAM)
32
33 #include "Dictionary.h"
34 #include "Event.h"
35 #include "EventNames.h"
36 #include "JSOverconstrainedError.h"
37 #include "MediaConstraintsImpl.h"
38 #include "MediaSourceSettings.h"
39 #include "MediaStream.h"
40 #include "MediaStreamPrivate.h"
41 #include "MediaTrackConstraints.h"
42 #include "NotImplemented.h"
43 #include "OverconstrainedError.h"
44 #include "ScriptExecutionContext.h"
45 #include <wtf/NeverDestroyed.h>
46
47 namespace WebCore {
48
49 Ref<MediaStreamTrack> MediaStreamTrack::create(ScriptExecutionContext& context, Ref<MediaStreamTrackPrivate>&& privateTrack)
50 {
51     return adoptRef(*new MediaStreamTrack(context, WTFMove(privateTrack)));
52 }
53
54 MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, Ref<MediaStreamTrackPrivate>&& privateTrack)
55     : ActiveDOMObject(&context)
56     , m_private(WTFMove(privateTrack))
57     , m_weakPtrFactory(this)
58 {
59     suspendIfNeeded();
60
61     m_private->addObserver(*this);
62 }
63
64 MediaStreamTrack::~MediaStreamTrack()
65 {
66     m_private->removeObserver(*this);
67 }
68
69 const AtomicString& MediaStreamTrack::kind() const
70 {
71     static NeverDestroyed<AtomicString> audioKind("audio", AtomicString::ConstructFromLiteral);
72     static NeverDestroyed<AtomicString> videoKind("video", AtomicString::ConstructFromLiteral);
73
74     if (m_private->type() == RealtimeMediaSource::Audio)
75         return audioKind;
76     return videoKind;
77 }
78
79 const String& MediaStreamTrack::id() const
80 {
81     return m_private->id();
82 }
83
84 const String& MediaStreamTrack::label() const
85 {
86     return m_private->label();
87 }
88
89 bool MediaStreamTrack::enabled() const
90 {
91     return m_private->enabled();
92 }
93
94 void MediaStreamTrack::setEnabled(bool enabled)
95 {
96     m_private->setEnabled(enabled);
97 }
98
99 bool MediaStreamTrack::muted() const
100 {
101     return m_private->muted();
102 }
103
104 bool MediaStreamTrack::readonly() const
105 {
106     return m_private->readonly();
107 }
108
109 bool MediaStreamTrack::remote() const
110 {
111     return m_private->remote();
112 }
113
114 auto MediaStreamTrack::readyState() const -> State
115 {
116     return ended() ? State::Ended : State::Live;
117 }
118
119 bool MediaStreamTrack::ended() const
120 {
121     return m_ended || m_private->ended();
122 }
123
124 Ref<MediaStreamTrack> MediaStreamTrack::clone()
125 {
126     return MediaStreamTrack::create(*scriptExecutionContext(), m_private->clone());
127 }
128
129 void MediaStreamTrack::stopProducingData()
130 {
131     // NOTE: this method is called when the "stop" method is called from JS, using
132     // the "ImplementedAs" IDL attribute. This is done because ActiveDOMObject requires
133     // a "stop" method.
134
135     // http://w3c.github.io/mediacapture-main/#widl-MediaStreamTrack-stop-void
136     // 4.3.3.2 Methods
137     // When a MediaStreamTrack object's stop() method is invoked, the User Agent must run following steps:
138     // 1. Let track be the current MediaStreamTrack object.
139     // 2. If track is sourced by a non-local source, then abort these steps.
140     if (remote() || ended())
141         return;
142
143     // 3. Notify track's source that track is ended so that the source may be stopped, unless other
144     // MediaStreamTrack objects depend on it.
145     // 4. Set track's readyState attribute to ended.
146
147     // Set m_ended to true before telling the private to stop so we do not fire an 'ended' event.
148     m_ended = true;
149
150     m_private->endTrack();
151 }
152
153 RefPtr<MediaTrackConstraints> MediaStreamTrack::getConstraints() const
154 {
155     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=122428
156     notImplemented();
157     return 0;
158 }
159
160 RefPtr<MediaSourceSettings> MediaStreamTrack::getSettings() const
161 {
162     return MediaSourceSettings::create(m_private->settings());
163 }
164
165 RefPtr<RealtimeMediaSourceCapabilities> MediaStreamTrack::getCapabilities() const
166 {
167     return m_private->capabilities();
168 }
169
170 void MediaStreamTrack::applyConstraints(Ref<MediaConstraints>&& constraints, DOMPromise<void>&& promise)
171 {
172     if (!constraints->isValid()) {
173         promise.reject(TypeError);
174         return;
175     }
176
177     m_constraints = WTFMove(constraints);
178     m_promise = WTFMove(promise);
179
180     applyConstraints(*m_constraints);
181 }
182
183 void MediaStreamTrack::applyConstraints(const MediaConstraints& constraints)
184 {
185     auto weakThis = createWeakPtr();
186     std::function<void(const String&, const String&)> failureHandler = [weakThis](const String& failedConstraint, const String& message) {
187         if (!weakThis || !weakThis->m_promise)
188             return;
189
190         weakThis->m_promise->rejectType<IDLInterface<OverconstrainedError>>(OverconstrainedError::create(failedConstraint, message).get());
191     };
192
193     std::function<void()> successHandler = [weakThis]() {
194         if (!weakThis || !weakThis->m_promise)
195             return;
196
197         weakThis->m_promise->resolve();
198     };
199
200     m_private->applyConstraints(constraints, successHandler, failureHandler);
201 }
202
203 void MediaStreamTrack::addObserver(MediaStreamTrack::Observer* observer)
204 {
205     m_observers.append(observer);
206 }
207
208 void MediaStreamTrack::removeObserver(MediaStreamTrack::Observer* observer)
209 {
210     size_t pos = m_observers.find(observer);
211     if (pos != notFound)
212         m_observers.remove(pos);
213 }
214
215 void MediaStreamTrack::trackEnded(MediaStreamTrackPrivate&)
216 {
217     // http://w3c.github.io/mediacapture-main/#life-cycle
218     // When a MediaStreamTrack track ends for any reason other than the stop() method being invoked, the User Agent must queue a task that runs the following steps:
219     // 1. If the track's readyState attribute has the value ended already, then abort these steps.
220     if (m_ended)
221         return;
222
223     // 2. Set track's readyState attribute to ended.
224     m_ended = true;
225
226     if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped())
227         return;
228
229     // 3. Notify track's source that track is ended so that the source may be stopped, unless other MediaStreamTrack objects depend on it.
230     // 4. Fire a simple event named ended at the object.
231     dispatchEvent(Event::create(eventNames().endedEvent, false, false));
232
233     for (auto& observer : m_observers)
234         observer->trackDidEnd();
235
236     configureTrackRendering();
237 }
238     
239 void MediaStreamTrack::trackMutedChanged(MediaStreamTrackPrivate&)
240 {
241     if (scriptExecutionContext()->activeDOMObjectsAreSuspended() || scriptExecutionContext()->activeDOMObjectsAreStopped())
242         return;
243
244     AtomicString eventType = muted() ? eventNames().muteEvent : eventNames().unmuteEvent;
245     dispatchEvent(Event::create(eventType, false, false));
246
247     configureTrackRendering();
248 }
249
250 void MediaStreamTrack::trackSettingsChanged(MediaStreamTrackPrivate&)
251 {
252     configureTrackRendering();
253 }
254
255 void MediaStreamTrack::trackEnabledChanged(MediaStreamTrackPrivate&)
256 {
257     configureTrackRendering();
258 }
259
260 void MediaStreamTrack::configureTrackRendering()
261 {
262     // 4.3.1
263     // ... media from the source only flows when a MediaStreamTrack object is both unmuted and enabled
264 }
265
266 void MediaStreamTrack::stop()
267 {
268     stopProducingData();
269 }
270
271 const char* MediaStreamTrack::activeDOMObjectName() const
272 {
273     return "MediaStreamTrack";
274 }
275
276 bool MediaStreamTrack::canSuspendForDocumentSuspension() const
277 {
278     // FIXME: We should try and do better here.
279     return false;
280 }
281
282 AudioSourceProvider* MediaStreamTrack::audioSourceProvider()
283 {
284     return m_private->audioSourceProvider();
285 }
286
287 } // namespace WebCore
288
289 #endif // ENABLE(MEDIA_STREAM)