1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,417 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef _PEER_CONNECTION_MEDIA_H_ 1.9 +#define _PEER_CONNECTION_MEDIA_H_ 1.10 + 1.11 +#include <string> 1.12 +#include <vector> 1.13 +#include <map> 1.14 + 1.15 +#include "nspr.h" 1.16 +#include "prlock.h" 1.17 + 1.18 +#include "mozilla/RefPtr.h" 1.19 +#include "nsComponentManagerUtils.h" 1.20 + 1.21 +#ifdef USE_FAKE_MEDIA_STREAMS 1.22 +#include "FakeMediaStreams.h" 1.23 +#else 1.24 +#include "DOMMediaStream.h" 1.25 +#include "MediaSegment.h" 1.26 +#endif 1.27 + 1.28 +#include "AudioSegment.h" 1.29 + 1.30 +#ifdef MOZILLA_INTERNAL_API 1.31 +#include "Layers.h" 1.32 +#include "VideoUtils.h" 1.33 +#include "ImageLayers.h" 1.34 +#include "VideoSegment.h" 1.35 +#endif 1.36 + 1.37 +namespace mozilla { 1.38 +class DataChannel; 1.39 +namespace dom { 1.40 +class RTCInboundRTPStreamStats; 1.41 +class RTCOutboundRTPStreamStats; 1.42 +} 1.43 +} 1.44 + 1.45 +#include "nricectx.h" 1.46 +#include "nriceresolver.h" 1.47 +#include "nricemediastream.h" 1.48 +#include "MediaPipeline.h" 1.49 + 1.50 +namespace sipcc { 1.51 + 1.52 +class PeerConnectionImpl; 1.53 +class PeerConnectionMedia; 1.54 + 1.55 +/* Temporary for providing audio data */ 1.56 +class Fake_AudioGenerator { 1.57 + public: 1.58 + typedef mozilla::DOMMediaStream DOMMediaStream; 1.59 + 1.60 +Fake_AudioGenerator(DOMMediaStream* aStream) : mStream(aStream), mCount(0) { 1.61 + mTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.62 + MOZ_ASSERT(mTimer); 1.63 + 1.64 + // Make a track 1.65 + mozilla::AudioSegment *segment = new mozilla::AudioSegment(); 1.66 + mStream->GetStream()->AsSourceStream()->AddTrack(1, 16000, 0, segment); 1.67 + 1.68 + // Set the timer 1.69 + mTimer->InitWithFuncCallback(Callback, this, 100, nsITimer::TYPE_REPEATING_PRECISE); 1.70 + } 1.71 + 1.72 + static void Callback(nsITimer* timer, void *arg) { 1.73 + Fake_AudioGenerator* gen = static_cast<Fake_AudioGenerator*>(arg); 1.74 + 1.75 + nsRefPtr<mozilla::SharedBuffer> samples = mozilla::SharedBuffer::Create(1600 * sizeof(int16_t)); 1.76 + int16_t* data = static_cast<int16_t*>(samples->Data()); 1.77 + for (int i=0; i<1600; i++) { 1.78 + data[i] = ((gen->mCount % 8) * 4000) - (7*4000)/2; 1.79 + ++gen->mCount; 1.80 + } 1.81 + 1.82 + mozilla::AudioSegment segment; 1.83 + nsAutoTArray<const int16_t*,1> channelData; 1.84 + channelData.AppendElement(data); 1.85 + segment.AppendFrames(samples.forget(), channelData, 1600); 1.86 + gen->mStream->GetStream()->AsSourceStream()->AppendToTrack(1, &segment); 1.87 + } 1.88 + 1.89 + private: 1.90 + nsCOMPtr<nsITimer> mTimer; 1.91 + nsRefPtr<DOMMediaStream> mStream; 1.92 + int mCount; 1.93 +}; 1.94 + 1.95 +/* Temporary for providing video data */ 1.96 +#ifdef MOZILLA_INTERNAL_API 1.97 +class Fake_VideoGenerator { 1.98 + public: 1.99 + typedef mozilla::DOMMediaStream DOMMediaStream; 1.100 + typedef mozilla::gfx::IntSize IntSize; 1.101 + 1.102 + Fake_VideoGenerator(DOMMediaStream* aStream) { 1.103 + mStream = aStream; 1.104 + mCount = 0; 1.105 + mTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.106 + MOZ_ASSERT(mTimer); 1.107 + 1.108 + // Make a track 1.109 + mozilla::VideoSegment *segment = new mozilla::VideoSegment(); 1.110 + mStream->GetStream()->AsSourceStream()->AddTrack(1, mozilla::USECS_PER_S, 0, segment); 1.111 + mStream->GetStream()->AsSourceStream()->AdvanceKnownTracksTime(mozilla::STREAM_TIME_MAX); 1.112 + 1.113 + // Set the timer. Set to 10 fps. 1.114 + mTimer->InitWithFuncCallback(Callback, this, 100, nsITimer::TYPE_REPEATING_SLACK); 1.115 + } 1.116 + 1.117 + static void Callback(nsITimer* timer, void *arg) { 1.118 + Fake_VideoGenerator* gen = static_cast<Fake_VideoGenerator*>(arg); 1.119 + 1.120 + const uint32_t WIDTH = 640; 1.121 + const uint32_t HEIGHT = 480; 1.122 + 1.123 + // Allocate a single blank Image 1.124 + nsRefPtr<mozilla::layers::ImageContainer> container = 1.125 + mozilla::layers::LayerManager::CreateImageContainer(); 1.126 + 1.127 + nsRefPtr<mozilla::layers::Image> image = 1.128 + container->CreateImage(mozilla::ImageFormat::PLANAR_YCBCR); 1.129 + 1.130 + int len = ((WIDTH * HEIGHT) * 3 / 2); 1.131 + mozilla::layers::PlanarYCbCrImage* planar = 1.132 + static_cast<mozilla::layers::PlanarYCbCrImage*>(image.get()); 1.133 + uint8_t* frame = (uint8_t*) PR_Malloc(len); 1.134 + ++gen->mCount; 1.135 + memset(frame, (gen->mCount / 8) & 0xff, len); // Rotating colors 1.136 + 1.137 + const uint8_t lumaBpp = 8; 1.138 + const uint8_t chromaBpp = 4; 1.139 + 1.140 + mozilla::layers::PlanarYCbCrData data; 1.141 + data.mYChannel = frame; 1.142 + data.mYSize = IntSize(WIDTH, HEIGHT); 1.143 + data.mYStride = (int32_t) (WIDTH * lumaBpp / 8.0); 1.144 + data.mCbCrStride = (int32_t) (WIDTH * chromaBpp / 8.0); 1.145 + data.mCbChannel = frame + HEIGHT * data.mYStride; 1.146 + data.mCrChannel = data.mCbChannel + HEIGHT * data.mCbCrStride / 2; 1.147 + data.mCbCrSize = IntSize(WIDTH / 2, HEIGHT / 2); 1.148 + data.mPicX = 0; 1.149 + data.mPicY = 0; 1.150 + data.mPicSize = IntSize(WIDTH, HEIGHT); 1.151 + data.mStereoMode = mozilla::StereoMode::MONO; 1.152 + 1.153 + // SetData copies data, so we can free the frame 1.154 + planar->SetData(data); 1.155 + PR_Free(frame); 1.156 + 1.157 + // AddTrack takes ownership of segment 1.158 + mozilla::VideoSegment *segment = new mozilla::VideoSegment(); 1.159 + // 10 fps. 1.160 + segment->AppendFrame(image.forget(), mozilla::USECS_PER_S / 10, 1.161 + IntSize(WIDTH, HEIGHT)); 1.162 + 1.163 + gen->mStream->GetStream()->AsSourceStream()->AppendToTrack(1, segment); 1.164 + } 1.165 + 1.166 + private: 1.167 + nsCOMPtr<nsITimer> mTimer; 1.168 + nsRefPtr<DOMMediaStream> mStream; 1.169 + int mCount; 1.170 +}; 1.171 +#endif 1.172 + 1.173 + 1.174 +class SourceStreamInfo { 1.175 +public: 1.176 + typedef mozilla::DOMMediaStream DOMMediaStream; 1.177 + 1.178 + SourceStreamInfo(DOMMediaStream* aMediaStream, 1.179 + PeerConnectionMedia *aParent) 1.180 + : mMediaStream(aMediaStream), 1.181 + mParent(aParent) { 1.182 + MOZ_ASSERT(mMediaStream); 1.183 + } 1.184 + 1.185 + SourceStreamInfo(already_AddRefed<DOMMediaStream>& aMediaStream, 1.186 + PeerConnectionMedia *aParent) 1.187 + : mMediaStream(aMediaStream), 1.188 + mParent(aParent) { 1.189 + MOZ_ASSERT(mMediaStream); 1.190 + } 1.191 + 1.192 + // This method exists for stats and the unittests. 1.193 + // It allows visibility into the pipelines and flows. 1.194 + const std::map<mozilla::TrackID, mozilla::RefPtr<mozilla::MediaPipeline>>& 1.195 + GetPipelines() const { return mPipelines; } 1.196 + mozilla::RefPtr<mozilla::MediaPipeline> GetPipelineByLevel_m(int level); 1.197 + 1.198 +protected: 1.199 + std::map<mozilla::TrackID, mozilla::RefPtr<mozilla::MediaPipeline>> mPipelines; 1.200 + nsRefPtr<DOMMediaStream> mMediaStream; 1.201 + PeerConnectionMedia *mParent; 1.202 +}; 1.203 + 1.204 +// TODO(ekr@rtfm.com): Refactor {Local,Remote}SourceStreamInfo 1.205 +// bug 837539. 1.206 +class LocalSourceStreamInfo : public SourceStreamInfo { 1.207 +public: 1.208 + typedef mozilla::DOMMediaStream DOMMediaStream; 1.209 + 1.210 + LocalSourceStreamInfo(DOMMediaStream *aMediaStream, 1.211 + PeerConnectionMedia *aParent) 1.212 + : SourceStreamInfo(aMediaStream, aParent) {} 1.213 + 1.214 + ~LocalSourceStreamInfo() { 1.215 + mMediaStream = nullptr; 1.216 + } 1.217 + 1.218 + DOMMediaStream* GetMediaStream() { 1.219 + return mMediaStream; 1.220 + } 1.221 + void StorePipeline(int aTrack, mozilla::RefPtr<mozilla::MediaPipeline> aPipeline); 1.222 + 1.223 + void ExpectAudio(const mozilla::TrackID); 1.224 + void ExpectVideo(const mozilla::TrackID); 1.225 + unsigned AudioTrackCount(); 1.226 + unsigned VideoTrackCount(); 1.227 + void DetachTransport_s(); 1.228 + void DetachMedia_m(); 1.229 + 1.230 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo) 1.231 +private: 1.232 + nsTArray<mozilla::TrackID> mAudioTracks; 1.233 + nsTArray<mozilla::TrackID> mVideoTracks; 1.234 +}; 1.235 + 1.236 +class RemoteSourceStreamInfo : public SourceStreamInfo { 1.237 + public: 1.238 + typedef mozilla::DOMMediaStream DOMMediaStream; 1.239 + 1.240 + RemoteSourceStreamInfo(already_AddRefed<DOMMediaStream> aMediaStream, 1.241 + PeerConnectionMedia *aParent) 1.242 + : SourceStreamInfo(aMediaStream, aParent), 1.243 + mTrackTypeHints(0) {} 1.244 + 1.245 + DOMMediaStream* GetMediaStream() { 1.246 + return mMediaStream; 1.247 + } 1.248 + void StorePipeline(int aTrack, bool aIsVideo, 1.249 + mozilla::RefPtr<mozilla::MediaPipeline> aPipeline); 1.250 + 1.251 + bool SetUsingBundle_m(int aLevel, bool decision); 1.252 + 1.253 + void DetachTransport_s(); 1.254 + void DetachMedia_m(); 1.255 + 1.256 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteSourceStreamInfo) 1.257 + 1.258 +public: 1.259 + DOMMediaStream::TrackTypeHints mTrackTypeHints; 1.260 + private: 1.261 + std::map<int, bool> mTypes; 1.262 +}; 1.263 + 1.264 +class PeerConnectionMedia : public sigslot::has_slots<> { 1.265 + public: 1.266 + PeerConnectionMedia(PeerConnectionImpl *parent); 1.267 + ~PeerConnectionMedia() {} 1.268 + 1.269 + nsresult Init(const std::vector<mozilla::NrIceStunServer>& stun_servers, 1.270 + const std::vector<mozilla::NrIceTurnServer>& turn_servers); 1.271 + // WARNING: This destroys the object! 1.272 + void SelfDestruct(); 1.273 + 1.274 + mozilla::RefPtr<mozilla::NrIceCtx> ice_ctx() const { return mIceCtx; } 1.275 + 1.276 + mozilla::RefPtr<mozilla::NrIceMediaStream> ice_media_stream(size_t i) const { 1.277 + // TODO(ekr@rtfm.com): If someone asks for a value that doesn't exist, 1.278 + // make one. 1.279 + if (i >= mIceStreams.size()) { 1.280 + return nullptr; 1.281 + } 1.282 + return mIceStreams[i]; 1.283 + } 1.284 + 1.285 + size_t num_ice_media_streams() const { 1.286 + return mIceStreams.size(); 1.287 + } 1.288 + 1.289 + // Add a stream 1.290 + nsresult AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id); 1.291 + 1.292 + // Remove a stream 1.293 + nsresult RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id); 1.294 + 1.295 + // Get a specific local stream 1.296 + uint32_t LocalStreamsLength() 1.297 + { 1.298 + return mLocalSourceStreams.Length(); 1.299 + } 1.300 + LocalSourceStreamInfo* GetLocalStream(int index); 1.301 + 1.302 + // Get a specific remote stream 1.303 + uint32_t RemoteStreamsLength() 1.304 + { 1.305 + return mRemoteSourceStreams.Length(); 1.306 + } 1.307 + RemoteSourceStreamInfo* GetRemoteStream(int index); 1.308 + 1.309 + bool SetUsingBundle_m(int level, bool decision); 1.310 + bool UpdateFilterFromRemoteDescription_m( 1.311 + int level, 1.312 + nsAutoPtr<mozilla::MediaPipelineFilter> filter); 1.313 + 1.314 + // Add a remote stream. Returns the index in index 1.315 + nsresult AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo, int *aIndex); 1.316 + nsresult AddRemoteStreamHint(int aIndex, bool aIsVideo); 1.317 + 1.318 + const nsCOMPtr<nsIThread>& GetMainThread() const { return mMainThread; } 1.319 + const nsCOMPtr<nsIEventTarget>& GetSTSThread() const { return mSTSThread; } 1.320 + 1.321 + // Get a transport flow either RTP/RTCP for a particular stream 1.322 + // A stream can be of audio/video/datachannel/budled(?) types 1.323 + mozilla::RefPtr<mozilla::TransportFlow> GetTransportFlow(int aStreamIndex, 1.324 + bool aIsRtcp) { 1.325 + int index_inner = aStreamIndex * 2 + (aIsRtcp ? 1 : 0); 1.326 + 1.327 + if (mTransportFlows.find(index_inner) == mTransportFlows.end()) 1.328 + return nullptr; 1.329 + 1.330 + return mTransportFlows[index_inner]; 1.331 + } 1.332 + 1.333 + // Add a transport flow 1.334 + void AddTransportFlow(int aIndex, bool aRtcp, 1.335 + const mozilla::RefPtr<mozilla::TransportFlow> &aFlow) { 1.336 + int index_inner = aIndex * 2 + (aRtcp ? 1 : 0); 1.337 + 1.338 + MOZ_ASSERT(!mTransportFlows[index_inner]); 1.339 + mTransportFlows[index_inner] = aFlow; 1.340 + } 1.341 + 1.342 + mozilla::RefPtr<mozilla::MediaSessionConduit> GetConduit(int aStreamIndex, bool aReceive) { 1.343 + int index_inner = aStreamIndex * 2 + (aReceive ? 0 : 1); 1.344 + 1.345 + if (mConduits.find(index_inner) == mConduits.end()) 1.346 + return nullptr; 1.347 + 1.348 + return mConduits[index_inner]; 1.349 + } 1.350 + 1.351 + // Add a conduit 1.352 + void AddConduit(int aIndex, bool aReceive, 1.353 + const mozilla::RefPtr<mozilla::MediaSessionConduit> &aConduit) { 1.354 + int index_inner = aIndex * 2 + (aReceive ? 0 : 1); 1.355 + 1.356 + MOZ_ASSERT(!mConduits[index_inner]); 1.357 + mConduits[index_inner] = aConduit; 1.358 + } 1.359 + 1.360 + // ICE state signals 1.361 + sigslot::signal2<mozilla::NrIceCtx*, mozilla::NrIceCtx::GatheringState> 1.362 + SignalIceGatheringStateChange; 1.363 + sigslot::signal2<mozilla::NrIceCtx*, mozilla::NrIceCtx::ConnectionState> 1.364 + SignalIceConnectionStateChange; 1.365 + 1.366 + private: 1.367 + // Shutdown media transport. Must be called on STS thread. 1.368 + void ShutdownMediaTransport_s(); 1.369 + 1.370 + // Final destruction of the media stream. Must be called on the main 1.371 + // thread. 1.372 + void SelfDestruct_m(); 1.373 + 1.374 + // ICE events 1.375 + void IceGatheringStateChange_s(mozilla::NrIceCtx* ctx, 1.376 + mozilla::NrIceCtx::GatheringState state); 1.377 + void IceConnectionStateChange_s(mozilla::NrIceCtx* ctx, 1.378 + mozilla::NrIceCtx::ConnectionState state); 1.379 + void IceStreamReady(mozilla::NrIceMediaStream *aStream); 1.380 + 1.381 + void IceGatheringStateChange_m(mozilla::NrIceCtx* ctx, 1.382 + mozilla::NrIceCtx::GatheringState state); 1.383 + void IceConnectionStateChange_m(mozilla::NrIceCtx* ctx, 1.384 + mozilla::NrIceCtx::ConnectionState state); 1.385 + 1.386 + // The parent PC 1.387 + PeerConnectionImpl *mParent; 1.388 + 1.389 + // A list of streams returned from GetUserMedia 1.390 + mozilla::Mutex mLocalSourceStreamsLock; 1.391 + nsTArray<nsRefPtr<LocalSourceStreamInfo> > mLocalSourceStreams; 1.392 + 1.393 + // A list of streams provided by the other side 1.394 + nsTArray<nsRefPtr<RemoteSourceStreamInfo> > mRemoteSourceStreams; 1.395 + 1.396 + // ICE objects 1.397 + mozilla::RefPtr<mozilla::NrIceCtx> mIceCtx; 1.398 + std::vector<mozilla::RefPtr<mozilla::NrIceMediaStream> > mIceStreams; 1.399 + 1.400 + // DNS 1.401 + nsRefPtr<mozilla::NrIceResolver> mDNSResolver; 1.402 + 1.403 + // Transport flows: even is RTP, odd is RTCP 1.404 + std::map<int, mozilla::RefPtr<mozilla::TransportFlow> > mTransportFlows; 1.405 + 1.406 + // Conduits: even is receive, odd is transmit (for easier correlation with 1.407 + // flows) 1.408 + std::map<int, mozilla::RefPtr<mozilla::MediaSessionConduit> > mConduits; 1.409 + 1.410 + // The main thread. 1.411 + nsCOMPtr<nsIThread> mMainThread; 1.412 + 1.413 + // The STS thread. 1.414 + nsCOMPtr<nsIEventTarget> mSTSThread; 1.415 + 1.416 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeerConnectionMedia) 1.417 +}; 1.418 + 1.419 +} // namespace sipcc 1.420 +#endif