1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * Copyright (C) 2011 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 "AllAudioCapabilities.h" 34#include "AllVideoCapabilities.h" 35#include "AudioStreamTrack.h" 36#include "Dictionary.h" 37#include "Event.h" 38#include "ExceptionCode.h" 39#include "ExceptionCodePlaceholder.h" 40#include "MediaConstraintsImpl.h" 41#include "MediaSourceStates.h" 42#include "MediaStream.h" 43#include "MediaStreamCenter.h" 44#include "MediaStreamPrivate.h" 45#include "MediaStreamTrackSourcesCallback.h" 46#include "MediaStreamTrackSourcesRequest.h" 47#include "MediaTrackConstraints.h" 48#include "NotImplemented.h" 49#include "VideoStreamTrack.h" 50#include <wtf/Functional.h> 51#include <wtf/NeverDestroyed.h> 52 53namespace WebCore { 54 55MediaStreamTrack::MediaStreamTrack(ScriptExecutionContext& context, MediaStreamTrackPrivate& privateTrack, const Dictionary* constraints) 56 : RefCounted() 57 , ActiveDOMObject(&context) 58 , m_privateTrack(privateTrack) 59 , m_eventDispatchScheduled(false) 60 , m_stoppingTrack(false) 61{ 62 suspendIfNeeded(); 63 64 m_privateTrack->setClient(this); 65 66 if (constraints) 67 applyConstraints(*constraints); 68} 69 70MediaStreamTrack::MediaStreamTrack(MediaStreamTrack& other) 71 : RefCounted() 72 , ActiveDOMObject(other.scriptExecutionContext()) 73 , m_privateTrack(*other.privateTrack().clone()) 74 , m_eventDispatchScheduled(false) 75 , m_stoppingTrack(false) 76{ 77 suspendIfNeeded(); 78 79 m_privateTrack->setClient(this); 80} 81 82MediaStreamTrack::~MediaStreamTrack() 83{ 84 m_privateTrack->setClient(nullptr); 85} 86 87void MediaStreamTrack::setSource(PassRefPtr<MediaStreamSource> newSource) 88{ 89 m_privateTrack->setSource(newSource); 90} 91 92const String& MediaStreamTrack::id() const 93{ 94 return m_privateTrack->id(); 95} 96 97const String& MediaStreamTrack::label() const 98{ 99 return m_privateTrack->label(); 100} 101 102bool MediaStreamTrack::enabled() const 103{ 104 return m_privateTrack->enabled(); 105} 106 107void MediaStreamTrack::setEnabled(bool enabled) 108{ 109 m_privateTrack->setEnabled(enabled); 110} 111 112bool MediaStreamTrack::stopped() const 113{ 114 return m_privateTrack->stopped(); 115} 116 117bool MediaStreamTrack::muted() const 118{ 119 return m_privateTrack->muted(); 120} 121 122bool MediaStreamTrack::readonly() const 123{ 124 return m_privateTrack->readonly(); 125} 126 127bool MediaStreamTrack::remote() const 128{ 129 return m_privateTrack->remote(); 130} 131 132const AtomicString& MediaStreamTrack::readyState() const 133{ 134 static NeverDestroyed<AtomicString> ended("ended", AtomicString::ConstructFromLiteral); 135 static NeverDestroyed<AtomicString> live("live", AtomicString::ConstructFromLiteral); 136 static NeverDestroyed<AtomicString> newState("new", AtomicString::ConstructFromLiteral); 137 138 switch (m_privateTrack->readyState()) { 139 case MediaStreamSource::Live: 140 return live; 141 case MediaStreamSource::New: 142 return newState; 143 case MediaStreamSource::Ended: 144 return ended; 145 } 146 147 ASSERT_NOT_REACHED(); 148 return emptyAtom; 149} 150 151void MediaStreamTrack::getSources(ScriptExecutionContext* context, PassRefPtr<MediaStreamTrackSourcesCallback> callback, ExceptionCode& ec) 152{ 153 RefPtr<MediaStreamTrackSourcesRequest> request = MediaStreamTrackSourcesRequest::create(context, callback); 154 if (!MediaStreamCenter::shared().getMediaStreamTrackSources(request.release())) 155 ec = NOT_SUPPORTED_ERR; 156} 157 158RefPtr<MediaTrackConstraints> MediaStreamTrack::getConstraints() const 159{ 160 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=122428 161 notImplemented(); 162 return 0; 163} 164 165RefPtr<MediaSourceStates> MediaStreamTrack::states() const 166{ 167 return MediaSourceStates::create(m_privateTrack->states()); 168} 169 170RefPtr<MediaStreamCapabilities> MediaStreamTrack::getCapabilities() const 171{ 172 // The source may be shared by multiple tracks, so its states is not necessarily 173 // in sync with the track state. A track that is new or has ended always has a source 174 // type of "none". 175 RefPtr<MediaStreamSourceCapabilities> sourceCapabilities = m_privateTrack->capabilities(); 176 MediaStreamSource::ReadyState readyState = m_privateTrack->readyState(); 177 if (readyState == MediaStreamSource::New || readyState == MediaStreamSource::Ended) 178 sourceCapabilities->setSourceType(MediaStreamSourceStates::None); 179 180 return MediaStreamCapabilities::create(sourceCapabilities.release()); 181} 182 183void MediaStreamTrack::applyConstraints(const Dictionary& constraints) 184{ 185 m_constraints->initialize(constraints); 186 m_privateTrack->applyConstraints(m_constraints); 187} 188 189void MediaStreamTrack::applyConstraints(PassRefPtr<MediaConstraints>) 190{ 191 // FIXME: apply the new constraints to the track 192 // https://bugs.webkit.org/show_bug.cgi?id=122428 193} 194 195RefPtr<MediaStreamTrack> MediaStreamTrack::clone() 196{ 197 if (m_privateTrack->type() == MediaStreamSource::Audio) 198 return AudioStreamTrack::create(*this); 199 200 return VideoStreamTrack::create(*this); 201} 202 203void MediaStreamTrack::stopProducingData() 204{ 205 // NOTE: this method is called when the "stop" method is called from JS, using 206 // the "ImplementedAs" IDL attribute. This is done because ActiveDOMObject requires 207 // a "stop" method. 208 209 // The stop method should "Permanently stop the generation of data for track's source", but it 210 // should not post an 'ended' event. 211 m_stoppingTrack = true; 212 m_privateTrack->stop(MediaStreamTrackPrivate::StopTrackAndStopSource); 213 m_stoppingTrack = false; 214} 215 216bool MediaStreamTrack::ended() const 217{ 218 return m_privateTrack->ended(); 219} 220 221void MediaStreamTrack::addObserver(MediaStreamTrack::Observer* observer) 222{ 223 m_observers.append(observer); 224} 225 226void MediaStreamTrack::removeObserver(MediaStreamTrack::Observer* observer) 227{ 228 size_t pos = m_observers.find(observer); 229 if (pos != notFound) 230 m_observers.remove(pos); 231} 232 233void MediaStreamTrack::trackReadyStateChanged() 234{ 235 if (stopped()) 236 return; 237 238 MediaStreamSource::ReadyState readyState = m_privateTrack->readyState(); 239 if (readyState == MediaStreamSource::Live) 240 scheduleEventDispatch(Event::create(eventNames().startedEvent, false, false)); 241 else if (readyState == MediaStreamSource::Ended && !m_stoppingTrack) 242 scheduleEventDispatch(Event::create(eventNames().endedEvent, false, false)); 243 244 configureTrackRendering(); 245} 246 247void MediaStreamTrack::trackMutedChanged() 248{ 249 if (stopped()) 250 return; 251 252 if (muted()) 253 scheduleEventDispatch(Event::create(eventNames().muteEvent, false, false)); 254 else 255 scheduleEventDispatch(Event::create(eventNames().unmuteEvent, false, false)); 256 257 configureTrackRendering(); 258} 259 260void MediaStreamTrack::trackEnabledChanged() 261{ 262 if (stopped()) 263 return; 264 265 setEnabled(m_privateTrack->enabled()); 266 configureTrackRendering(); 267} 268 269void MediaStreamTrack::configureTrackRendering() 270{ 271 if (stopped()) 272 return; 273 274 // 4.3.1 275 // ... media from the source only flows when a MediaStreamTrack object is both unmuted and enabled 276} 277 278void MediaStreamTrack::trackDidEnd() 279{ 280 m_privateTrack->setReadyState(MediaStreamSource::Ended); 281 282 for (Vector<Observer*>::iterator i = m_observers.begin(); i != m_observers.end(); ++i) 283 (*i)->trackDidEnd(); 284} 285 286void MediaStreamTrack::stop() 287{ 288 m_privateTrack->stop(MediaStreamTrackPrivate::StopTrackOnly); 289} 290 291void MediaStreamTrack::scheduleEventDispatch(PassRefPtr<Event> event) 292{ 293 { 294 MutexLocker locker(m_mutex); 295 m_scheduledEvents.append(event); 296 if (m_eventDispatchScheduled) 297 return; 298 m_eventDispatchScheduled = true; 299 } 300 301 callOnMainThread(bind(&MediaStreamTrack::dispatchQueuedEvents, this)); 302} 303 304void MediaStreamTrack::dispatchQueuedEvents() 305{ 306 Vector<RefPtr<Event>> events; 307 { 308 MutexLocker locker(m_mutex); 309 m_eventDispatchScheduled = false; 310 events.swap(m_scheduledEvents); 311 } 312 if (!scriptExecutionContext()) 313 return; 314 315 for (auto it = events.begin(); it != events.end(); ++it) 316 dispatchEvent((*it).release()); 317 318 events.clear(); 319} 320 321} // namespace WebCore 322 323#endif // ENABLE(MEDIA_STREAM) 324