2012-04-29 20:11:34 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef NSDOMMEDIASTREAM_H_
|
|
|
|
#define NSDOMMEDIASTREAM_H_
|
|
|
|
|
|
|
|
#include "nsIDOMMediaStream.h"
|
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2013-02-15 00:04:11 -08:00
|
|
|
#include "nsWrapperCache.h"
|
2013-09-05 10:29:38 -07:00
|
|
|
#include "StreamBuffer.h"
|
2013-09-05 13:25:17 -07:00
|
|
|
#include "nsIDOMWindow.h"
|
2014-05-01 03:50:00 -07:00
|
|
|
#include "nsIPrincipal.h"
|
|
|
|
#include "mozilla/PeerIdentity.h"
|
2012-04-29 20:11:34 -07:00
|
|
|
|
2012-10-24 16:21:32 -07:00
|
|
|
class nsXPCClassInfo;
|
|
|
|
|
2012-07-19 02:58:48 -07:00
|
|
|
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
|
|
|
// GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing
|
|
|
|
// currentTime getter.
|
|
|
|
#ifdef GetCurrentTime
|
|
|
|
#undef GetCurrentTime
|
|
|
|
#endif
|
2013-02-15 00:04:11 -08:00
|
|
|
// X11 has a #define for CurrentTime. Unbelievable :-(.
|
2013-03-14 18:01:02 -07:00
|
|
|
// See content/media/webaudio/AudioContext.h for more fun!
|
2013-02-15 00:04:11 -08:00
|
|
|
#ifdef CurrentTime
|
|
|
|
#undef CurrentTime
|
|
|
|
#endif
|
2012-07-19 02:58:48 -07:00
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
namespace mozilla {
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
class MediaStream;
|
|
|
|
|
2013-04-16 22:18:24 -07:00
|
|
|
namespace dom {
|
2013-05-21 12:17:47 -07:00
|
|
|
class AudioNode;
|
2013-04-16 22:18:24 -07:00
|
|
|
class MediaStreamTrack;
|
2013-04-16 22:18:37 -07:00
|
|
|
class AudioStreamTrack;
|
|
|
|
class VideoStreamTrack;
|
2014-05-23 02:34:14 -07:00
|
|
|
class AudioTrack;
|
|
|
|
class VideoTrack;
|
|
|
|
class AudioTrackList;
|
|
|
|
class VideoTrackList;
|
|
|
|
class MediaTrackListListener;
|
2013-04-16 22:18:24 -07:00
|
|
|
}
|
|
|
|
|
2013-08-24 06:53:11 -07:00
|
|
|
class MediaStreamDirectListener;
|
|
|
|
|
2012-04-29 20:11:34 -07:00
|
|
|
/**
|
|
|
|
* DOM wrapper for MediaStreams.
|
|
|
|
*/
|
2013-02-15 00:04:11 -08:00
|
|
|
class DOMMediaStream : public nsIDOMMediaStream,
|
|
|
|
public nsWrapperCache
|
2012-04-29 20:11:34 -07:00
|
|
|
{
|
2013-02-15 00:01:58 -08:00
|
|
|
friend class DOMLocalMediaStream;
|
2013-04-16 22:18:24 -07:00
|
|
|
typedef dom::MediaStreamTrack MediaStreamTrack;
|
2013-04-16 22:18:37 -07:00
|
|
|
typedef dom::AudioStreamTrack AudioStreamTrack;
|
|
|
|
typedef dom::VideoStreamTrack VideoStreamTrack;
|
2014-05-23 02:34:14 -07:00
|
|
|
typedef dom::AudioTrack AudioTrack;
|
|
|
|
typedef dom::VideoTrack VideoTrack;
|
|
|
|
typedef dom::AudioTrackList AudioTrackList;
|
|
|
|
typedef dom::VideoTrackList VideoTrackList;
|
|
|
|
typedef dom::MediaTrackListListener MediaTrackListListener;
|
2012-04-29 20:11:34 -07:00
|
|
|
|
|
|
|
public:
|
2013-05-02 22:02:55 -07:00
|
|
|
typedef uint8_t TrackTypeHints;
|
|
|
|
|
2013-04-16 22:18:24 -07:00
|
|
|
DOMMediaStream();
|
2012-04-29 20:11:34 -07:00
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMMediaStream)
|
2012-04-29 20:11:34 -07:00
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
nsIDOMWindow* GetParentObject() const
|
|
|
|
{
|
|
|
|
return mWindow;
|
|
|
|
}
|
2014-04-08 15:27:18 -07:00
|
|
|
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
2012-04-29 20:11:34 -07:00
|
|
|
|
2013-04-16 22:18:37 -07:00
|
|
|
// WebIDL
|
2013-02-15 00:04:11 -08:00
|
|
|
double CurrentTime();
|
2013-07-24 03:11:35 -07:00
|
|
|
|
2013-04-16 22:18:37 -07:00
|
|
|
void GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks);
|
|
|
|
void GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks);
|
2014-08-13 18:40:54 -07:00
|
|
|
void GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks);
|
|
|
|
bool HasTrack(const MediaStreamTrack& aTrack) const;
|
2013-04-16 22:18:37 -07:00
|
|
|
|
2013-07-24 03:11:35 -07:00
|
|
|
MediaStream* GetStream() const { return mStream; }
|
|
|
|
|
2013-08-24 06:53:11 -07:00
|
|
|
/**
|
|
|
|
* Overridden in DOMLocalMediaStreams to allow getUserMedia to pass
|
|
|
|
* data directly to RTCPeerConnection without going through graph queuing.
|
|
|
|
* Returns a bool to let us know if direct data will be delivered.
|
|
|
|
*/
|
|
|
|
virtual bool AddDirectListener(MediaStreamDirectListener *aListener) { return false; }
|
|
|
|
virtual void RemoveDirectListener(MediaStreamDirectListener *aListener) {}
|
|
|
|
|
2013-08-25 23:07:19 -07:00
|
|
|
/**
|
|
|
|
* Overridden in DOMLocalMediaStreams to allow getUserMedia to disable
|
|
|
|
* media at the SourceMediaStream.
|
|
|
|
*/
|
|
|
|
virtual void SetTrackEnabled(TrackID aTrackID, bool aEnabled);
|
|
|
|
|
2014-08-26 22:03:49 -07:00
|
|
|
virtual void StopTrack(TrackID aTrackID);
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
bool IsFinished();
|
2012-04-29 20:11:34 -07:00
|
|
|
/**
|
|
|
|
* Returns a principal indicating who may access this stream. The stream contents
|
|
|
|
* can only be accessed by principals subsuming this principal.
|
|
|
|
*/
|
|
|
|
nsIPrincipal* GetPrincipal() { return mPrincipal; }
|
|
|
|
|
2014-05-01 03:50:00 -07:00
|
|
|
/**
|
|
|
|
* These are used in WebRTC. A peerIdentity constrained MediaStream cannot be sent
|
|
|
|
* across the network to anything other than a peer with the provided identity.
|
|
|
|
* If this is set, then mPrincipal should be an instance of nsNullPrincipal.
|
|
|
|
*/
|
|
|
|
PeerIdentity* GetPeerIdentity() const { return mPeerIdentity; }
|
|
|
|
void SetPeerIdentity(PeerIdentity* aPeerIdentity)
|
|
|
|
{
|
|
|
|
mPeerIdentity = aPeerIdentity;
|
|
|
|
}
|
|
|
|
|
2012-04-29 20:11:34 -07:00
|
|
|
/**
|
|
|
|
* Indicate that data will be contributed to this stream from origin aPrincipal.
|
|
|
|
* If aPrincipal is null, this is ignored. Otherwise, from now on the contents
|
|
|
|
* of this stream can only be accessed by principals that subsume aPrincipal.
|
|
|
|
* Returns true if the stream's principal changed.
|
|
|
|
*/
|
|
|
|
bool CombineWithPrincipal(nsIPrincipal* aPrincipal);
|
|
|
|
|
2014-05-01 03:50:00 -07:00
|
|
|
/**
|
|
|
|
* This is used in WebRTC to move from a protected state (nsNullPrincipal) to
|
|
|
|
* one where the stream is accessible to script. Don't call this.
|
|
|
|
* CombineWithPrincipal is almost certainly more appropriate.
|
|
|
|
*/
|
2014-04-25 07:30:00 -07:00
|
|
|
void SetPrincipal(nsIPrincipal* aPrincipal);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to learn about dynamic changes in principal occur.
|
|
|
|
* Operations relating to these observers must be confined to the main thread.
|
|
|
|
*/
|
|
|
|
class PrincipalChangeObserver
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual void PrincipalChanged(DOMMediaStream* aMediaStream) = 0;
|
|
|
|
};
|
|
|
|
bool AddPrincipalChangeObserver(PrincipalChangeObserver* aObserver);
|
|
|
|
bool RemovePrincipalChangeObserver(PrincipalChangeObserver* aObserver);
|
2014-05-01 03:50:00 -07:00
|
|
|
|
2012-04-29 20:11:40 -07:00
|
|
|
/**
|
2013-05-02 22:02:55 -07:00
|
|
|
* Called when this stream's MediaStreamGraph has been shut down. Normally
|
|
|
|
* MSGs are only shut down when all streams have been removed, so this
|
|
|
|
* will only be called during a forced shutdown due to application exit.
|
2012-04-29 20:11:40 -07:00
|
|
|
*/
|
2013-05-02 22:02:55 -07:00
|
|
|
void NotifyMediaStreamGraphShutdown();
|
2013-07-24 19:07:34 -07:00
|
|
|
/**
|
|
|
|
* Called when the main-thread state of the MediaStream changed.
|
|
|
|
*/
|
|
|
|
void NotifyStreamStateChanged();
|
2012-10-06 22:34:30 -07:00
|
|
|
|
2013-05-02 22:02:55 -07:00
|
|
|
// Indicate what track types we eventually expect to add to this stream
|
2012-10-06 22:34:30 -07:00
|
|
|
enum {
|
2013-05-02 22:02:55 -07:00
|
|
|
HINT_CONTENTS_AUDIO = 1 << 0,
|
2014-08-25 06:27:25 -07:00
|
|
|
HINT_CONTENTS_VIDEO = 1 << 1,
|
|
|
|
HINT_CONTENTS_UNKNOWN = 1 << 2
|
2012-10-06 22:34:30 -07:00
|
|
|
};
|
2013-05-02 22:02:55 -07:00
|
|
|
TrackTypeHints GetHintContents() const { return mHintContents; }
|
|
|
|
void SetHintContents(TrackTypeHints aHintContents) { mHintContents = aHintContents; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an nsDOMMediaStream whose underlying stream is a SourceMediaStream.
|
|
|
|
*/
|
|
|
|
static already_AddRefed<DOMMediaStream>
|
|
|
|
CreateSourceStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents);
|
2012-04-29 20:11:40 -07:00
|
|
|
|
2012-07-31 05:17:22 -07:00
|
|
|
/**
|
|
|
|
* Create an nsDOMMediaStream whose underlying stream is a TrackUnionStream.
|
|
|
|
*/
|
2013-02-15 00:04:11 -08:00
|
|
|
static already_AddRefed<DOMMediaStream>
|
2013-05-02 22:02:55 -07:00
|
|
|
CreateTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents = 0);
|
2012-07-31 05:17:22 -07:00
|
|
|
|
2013-05-02 22:07:37 -07:00
|
|
|
void SetLogicalStreamStartTime(StreamTime aTime)
|
|
|
|
{
|
|
|
|
mLogicalStreamStartTime = aTime;
|
|
|
|
}
|
|
|
|
|
2013-05-02 22:02:55 -07:00
|
|
|
// Notifications from StreamListener.
|
|
|
|
// CreateDOMTrack should only be called when it's safe to run script.
|
2013-04-16 22:18:24 -07:00
|
|
|
MediaStreamTrack* CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType);
|
|
|
|
MediaStreamTrack* GetDOMTrackFor(TrackID aTrackID);
|
|
|
|
|
2013-05-02 22:02:55 -07:00
|
|
|
class OnTracksAvailableCallback {
|
|
|
|
public:
|
|
|
|
OnTracksAvailableCallback(uint8_t aExpectedTracks = 0)
|
|
|
|
: mExpectedTracks(aExpectedTracks) {}
|
|
|
|
virtual ~OnTracksAvailableCallback() {}
|
|
|
|
virtual void NotifyTracksAvailable(DOMMediaStream* aStream) = 0;
|
|
|
|
TrackTypeHints GetExpectedTracks() { return mExpectedTracks; }
|
|
|
|
void SetExpectedTracks(TrackTypeHints aExpectedTracks) { mExpectedTracks = aExpectedTracks; }
|
|
|
|
private:
|
|
|
|
TrackTypeHints mExpectedTracks;
|
|
|
|
};
|
|
|
|
// When one track of the appropriate type has been added for each bit set
|
|
|
|
// in aCallback->GetExpectedTracks(), run aCallback->NotifyTracksAvailable.
|
|
|
|
// It is allowed to do anything, including run script.
|
|
|
|
// aCallback may run immediately during this call if tracks are already
|
|
|
|
// available!
|
|
|
|
// We only care about track additions, we'll fire the notification even if
|
|
|
|
// some of the tracks have been removed.
|
|
|
|
// Takes ownership of aCallback.
|
2013-11-22 12:14:29 -08:00
|
|
|
// If GetExpectedTracks() returns 0, the callback will be fired as soon as there are any tracks.
|
2013-05-02 22:02:55 -07:00
|
|
|
void OnTracksAvailable(OnTracksAvailableCallback* aCallback);
|
|
|
|
|
2013-07-24 19:07:34 -07:00
|
|
|
/**
|
|
|
|
* Add an nsISupports object that this stream will keep alive as long as
|
|
|
|
* the stream is not finished.
|
|
|
|
*/
|
|
|
|
void AddConsumerToKeepAlive(nsISupports* aConsumer)
|
|
|
|
{
|
|
|
|
if (!IsFinished() && !mNotifiedOfMediaStreamGraphShutdown) {
|
|
|
|
mConsumersToKeepAlive.AppendElement(aConsumer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-23 02:34:14 -07:00
|
|
|
/**
|
|
|
|
* If loading and playing a MediaStream in a media element, for each
|
|
|
|
* MediaStreamTrack in the MediaStream, create a corresponding AudioTrack or
|
|
|
|
* VideoTrack during the phase of resource fetching.
|
|
|
|
*/
|
|
|
|
void ConstructMediaTracks(AudioTrackList* aAudioTrackList,
|
|
|
|
VideoTrackList* aVideoTrackList);
|
|
|
|
|
2014-08-26 23:40:09 -07:00
|
|
|
void NotifyMediaStreamTrackCreated(MediaStreamTrack* aTrack);
|
2014-05-23 02:34:14 -07:00
|
|
|
|
2014-08-26 23:40:09 -07:00
|
|
|
void NotifyMediaStreamTrackEnded(MediaStreamTrack* aTrack);
|
2014-05-23 02:34:14 -07:00
|
|
|
|
2012-04-29 20:11:34 -07:00
|
|
|
protected:
|
2014-06-24 09:36:43 -07:00
|
|
|
virtual ~DOMMediaStream();
|
|
|
|
|
2013-05-01 04:24:16 -07:00
|
|
|
void Destroy();
|
2013-05-02 22:02:55 -07:00
|
|
|
void InitSourceStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents);
|
|
|
|
void InitTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents);
|
2013-04-16 22:18:24 -07:00
|
|
|
void InitStreamCommon(MediaStream* aStream);
|
2014-05-23 02:34:14 -07:00
|
|
|
already_AddRefed<AudioTrack> CreateAudioTrack(AudioStreamTrack* aStreamTrack);
|
|
|
|
already_AddRefed<VideoTrack> CreateVideoTrack(VideoStreamTrack* aStreamTrack);
|
2013-11-22 12:14:29 -08:00
|
|
|
|
2013-05-02 22:02:55 -07:00
|
|
|
void CheckTracksAvailable();
|
2013-04-16 22:18:24 -07:00
|
|
|
|
|
|
|
class StreamListener;
|
|
|
|
friend class StreamListener;
|
2013-02-15 00:04:11 -08:00
|
|
|
|
2013-05-02 22:07:37 -07:00
|
|
|
// StreamTime at which the currentTime attribute would return 0.
|
|
|
|
StreamTime mLogicalStreamStartTime;
|
|
|
|
|
2013-02-15 00:04:11 -08:00
|
|
|
// We need this to track our parent object.
|
|
|
|
nsCOMPtr<nsIDOMWindow> mWindow;
|
2013-01-04 09:16:32 -08:00
|
|
|
|
2012-04-29 20:11:34 -07:00
|
|
|
// MediaStream is owned by the graph, but we tell it when to die, and it won't
|
|
|
|
// die until we let it.
|
|
|
|
MediaStream* mStream;
|
2012-10-06 22:34:30 -07:00
|
|
|
|
2013-04-16 22:18:24 -07:00
|
|
|
nsAutoTArray<nsRefPtr<MediaStreamTrack>,2> mTracks;
|
|
|
|
nsRefPtr<StreamListener> mListener;
|
|
|
|
|
2013-05-02 22:02:55 -07:00
|
|
|
nsTArray<nsAutoPtr<OnTracksAvailableCallback> > mRunOnTracksAvailable;
|
|
|
|
|
2013-07-24 19:07:34 -07:00
|
|
|
// Keep these alive until the stream finishes
|
|
|
|
nsTArray<nsCOMPtr<nsISupports> > mConsumersToKeepAlive;
|
|
|
|
|
2013-05-02 22:02:55 -07:00
|
|
|
// Indicate what track types we eventually expect to add to this stream
|
|
|
|
uint8_t mHintContents;
|
|
|
|
// Indicate what track types have been added to this stream
|
|
|
|
uint8_t mTrackTypesAvailable;
|
|
|
|
bool mNotifiedOfMediaStreamGraphShutdown;
|
2014-04-25 07:30:00 -07:00
|
|
|
|
2014-05-23 02:34:14 -07:00
|
|
|
// Send notifications to AudioTrackList or VideoTrackList, if this MediaStream
|
|
|
|
// is consumed by a HTMLMediaElement.
|
|
|
|
nsTArray<MediaTrackListListener> mMediaTrackListListeners;
|
|
|
|
|
2014-04-25 07:30:00 -07:00
|
|
|
private:
|
|
|
|
void NotifyPrincipalChanged();
|
|
|
|
|
|
|
|
// Principal identifying who may access the contents of this stream.
|
|
|
|
// If null, this stream can be used by anyone because it has no content yet.
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
|
|
nsTArray<PrincipalChangeObserver*> mPrincipalChangeObservers;
|
|
|
|
// this is used in gUM and WebRTC to identify peers that this stream
|
|
|
|
// is allowed to be sent to
|
|
|
|
nsAutoPtr<PeerIdentity> mPeerIdentity;
|
2012-04-29 20:11:34 -07:00
|
|
|
};
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
class DOMLocalMediaStream : public DOMMediaStream,
|
|
|
|
public nsIDOMLocalMediaStream
|
2012-10-24 16:21:32 -07:00
|
|
|
{
|
|
|
|
public:
|
2013-02-15 00:01:58 -08:00
|
|
|
DOMLocalMediaStream() {}
|
2012-10-24 16:21:32 -07:00
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
|
2014-04-08 15:27:18 -07:00
|
|
|
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
2013-02-15 00:04:11 -08:00
|
|
|
|
|
|
|
virtual void Stop();
|
2012-10-24 16:21:32 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
|
|
|
|
*/
|
2013-02-15 00:04:11 -08:00
|
|
|
static already_AddRefed<DOMLocalMediaStream>
|
2013-05-02 22:02:55 -07:00
|
|
|
CreateSourceStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents);
|
2012-10-24 16:21:32 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream.
|
|
|
|
*/
|
2013-02-15 00:04:11 -08:00
|
|
|
static already_AddRefed<DOMLocalMediaStream>
|
2013-05-02 22:02:55 -07:00
|
|
|
CreateTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents = 0);
|
2014-07-08 14:23:16 -07:00
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual ~DOMLocalMediaStream();
|
2012-10-24 16:21:32 -07:00
|
|
|
};
|
|
|
|
|
2013-05-21 12:17:47 -07:00
|
|
|
class DOMAudioNodeMediaStream : public DOMMediaStream
|
|
|
|
{
|
|
|
|
typedef dom::AudioNode AudioNode;
|
|
|
|
public:
|
|
|
|
DOMAudioNodeMediaStream(AudioNode* aNode);
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a DOMAudioNodeMediaStream whose underlying stream is a TrackUnionStream.
|
|
|
|
*/
|
|
|
|
static already_AddRefed<DOMAudioNodeMediaStream>
|
|
|
|
CreateTrackUnionStream(nsIDOMWindow* aWindow,
|
|
|
|
AudioNode* aNode,
|
|
|
|
TrackTypeHints aHintContents = 0);
|
|
|
|
|
2014-07-08 14:23:16 -07:00
|
|
|
protected:
|
|
|
|
~DOMAudioNodeMediaStream();
|
|
|
|
|
2013-05-21 12:17:47 -07:00
|
|
|
private:
|
|
|
|
// If this object wraps a stream owned by an AudioNode, we need to ensure that
|
|
|
|
// the node isn't cycle-collected too early.
|
|
|
|
nsRefPtr<AudioNode> mStreamNode;
|
|
|
|
};
|
|
|
|
|
2013-02-15 00:01:58 -08:00
|
|
|
}
|
|
|
|
|
2012-04-29 20:11:34 -07:00
|
|
|
#endif /* NSDOMMEDIASTREAM_H_ */
|