RTCRtpScriptTransformer.h (7523B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #ifndef MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCRTPSCRIPTTRANSFORMER_H_ 8 #define MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCRTPSCRIPTTRANSFORMER_H_ 9 10 #include <memory> 11 12 #include "js/RootingAPI.h" 13 #include "mozilla/Maybe.h" 14 #include "mozilla/RefPtr.h" 15 #include "mozilla/dom/ReadableStream.h" 16 #include "mozilla/dom/WritableStream.h" 17 #include "nsCOMArray.h" 18 #include "nsCycleCollectionParticipant.h" 19 #include "nsISupports.h" 20 #include "nsTArray.h" 21 #include "nsTHashSet.h" 22 #include "nsWrapperCache.h" 23 24 class nsPIDOMWindowInner; 25 26 namespace webrtc { 27 class TransformableFrameInterface; 28 } 29 30 namespace mozilla { 31 class FrameTransformerProxy; 32 33 namespace dom { 34 class Worker; 35 class WorkerPrivate; 36 37 // Dirt simple source for ReadableStream that accepts nsISupports 38 // Might be suitable to move someplace else, with some polish. 39 class nsISupportsStreamSource final : public UnderlyingSourceAlgorithmsWrapper { 40 public: 41 nsISupportsStreamSource(); 42 nsISupportsStreamSource(const nsISupportsStreamSource&) = delete; 43 nsISupportsStreamSource(nsISupportsStreamSource&&) = delete; 44 nsISupportsStreamSource& operator=(const nsISupportsStreamSource&) = delete; 45 nsISupportsStreamSource& operator=(nsISupportsStreamSource&&) = delete; 46 47 NS_DECL_ISUPPORTS_INHERITED 48 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsISupportsStreamSource, 49 UnderlyingSourceAlgorithmsWrapper) 50 51 void Init(ReadableStream* aStream); 52 53 void Enqueue(nsISupports* aThing); 54 55 // From UnderlyingSourceAlgorithmsWrapper 56 already_AddRefed<Promise> PullCallbackImpl( 57 JSContext* aCx, ReadableStreamControllerBase& aController, 58 ErrorResult& aRv) override; 59 60 void EnqueueOneThingFromQueue(JSContext* aCx); 61 62 private: 63 virtual ~nsISupportsStreamSource(); 64 65 // Calls ReadableStream::EnqueueNative, which is MOZ_CAN_RUN_SCRIPT. 66 MOZ_CAN_RUN_SCRIPT_BOUNDARY void EnqueueToStream(JSContext* aCx, 67 nsISupports* aThing); 68 69 RefPtr<ReadableStream> mStream; 70 RefPtr<Promise> mThingQueuedPromise; 71 // mozilla::Queue is not cycle-collector friendly :( 72 nsCOMArray<nsISupports> mQueue; 73 }; 74 75 class RTCRtpScriptTransformer; 76 77 class WritableStreamRTCFrameSink final 78 : public UnderlyingSinkAlgorithmsWrapper { 79 public: 80 explicit WritableStreamRTCFrameSink(RTCRtpScriptTransformer* aTransformer); 81 WritableStreamRTCFrameSink(const WritableStreamRTCFrameSink&) = delete; 82 WritableStreamRTCFrameSink(WritableStreamRTCFrameSink&&) = delete; 83 WritableStreamRTCFrameSink& operator=(const WritableStreamRTCFrameSink&) = 84 delete; 85 WritableStreamRTCFrameSink& operator=(WritableStreamRTCFrameSink&&) = delete; 86 87 NS_DECL_ISUPPORTS_INHERITED 88 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WritableStreamRTCFrameSink, 89 UnderlyingSinkAlgorithmsWrapper) 90 91 already_AddRefed<Promise> WriteCallbackImpl( 92 JSContext* aCx, JS::Handle<JS::Value> aChunk, 93 WritableStreamDefaultController& aController, 94 ErrorResult& aError) override; 95 96 private: 97 virtual ~WritableStreamRTCFrameSink(); 98 RefPtr<RTCRtpScriptTransformer> mTransformer; 99 }; 100 101 class RTCEncodedFrameBase; 102 103 // Here's the basic flow. All of this happens on the worker thread. 104 // 0. We register with a FrameTransformerProxy. 105 // 1. That FrameTransformerProxy dispatches webrtc::TransformableFrameInterface 106 // to us (from either the encoder/depacketizer thread), via our 107 // TransformFrame method. 108 // 2. We wrap these frames in RTCEncodedAudio/VideoFrame, and feed them to 109 // mReadableSource, which queues them. 110 // 3. mReadableSource.PullCallbackImpl consumes that queue, and feeds the 111 // frames to mReadable. 112 // 4. JS worker code consumes from mReadable, does whatever transformation it 113 // wants, then writes the frames to mWritable. 114 // 5. mWritableSink.WriteCallback passes those frames to us. 115 // 6. We unwrap the webrtc::TransformableFrameInterface from these frames. 116 // 7. We pass these unwrapped frames back to the FrameTransformerProxy. 117 // (FrameTransformerProxy handles any dispatching/synchronization necessary) 118 // 8. Eventually, that FrameTransformerProxy calls NotifyReleased (possibly at 119 // our prompting). 120 class RTCRtpScriptTransformer final : public nsISupports, 121 public nsWrapperCache { 122 public: 123 explicit RTCRtpScriptTransformer(nsIGlobalObject* aGlobal); 124 125 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult Init(JSContext* aCx, 126 JS::Handle<JS::Value> aOptions, 127 WorkerPrivate* aWorkerPrivate, 128 FrameTransformerProxy* aProxy); 129 130 void NotifyReleased(); 131 132 void TransformFrame( 133 std::unique_ptr<webrtc::TransformableFrameInterface> aFrame); 134 already_AddRefed<Promise> OnTransformedFrame(RTCEncodedFrameBase* aFrame, 135 ErrorResult& aError); 136 137 // nsISupports 138 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 139 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(RTCRtpScriptTransformer) 140 141 JSObject* WrapObject(JSContext* aCx, 142 JS::Handle<JSObject*> aGivenProto) override; 143 144 nsIGlobalObject* GetParentObject() const { return mGlobal; } 145 146 // WebIDL Interface 147 already_AddRefed<mozilla::dom::ReadableStream> Readable() const { 148 return do_AddRef(mReadable); 149 } 150 already_AddRefed<mozilla::dom::WritableStream> Writable() const { 151 return do_AddRef(mWritable); 152 } 153 154 void GetOptions(JSContext* aCx, JS::MutableHandle<JS::Value> aVal, 155 ErrorResult& aError); 156 157 already_AddRefed<Promise> GenerateKeyFrame(const Optional<nsAString>& aRid); 158 void GenerateKeyFrameError(const Maybe<std::string>& aRid, 159 const CopyableErrorResult& aResult); 160 already_AddRefed<Promise> SendKeyFrameRequest(); 161 void KeyFrameRequestDone(); 162 163 // Public to ease implementation of cycle collection functions 164 using GenerateKeyFramePromises = 165 nsTHashMap<nsCStringHashKey, nsTArray<RefPtr<Promise>>>; 166 167 private: 168 virtual ~RTCRtpScriptTransformer(); 169 void RejectPendingPromises(); 170 // empty string means no rid 171 void ResolveGenerateKeyFramePromises(const std::string& aRid, 172 uint64_t aTimestamp); 173 174 nsCOMPtr<nsIGlobalObject> mGlobal; 175 176 RefPtr<FrameTransformerProxy> mProxy; 177 RefPtr<nsISupportsStreamSource> mReadableSource; 178 RefPtr<ReadableStream> mReadable; 179 RefPtr<WritableStream> mWritable; 180 RefPtr<WritableStreamRTCFrameSink> mWritableSink; 181 182 JS::Heap<JS::Value> mOptions; 183 uint64_t mLastEnqueuedFrameCounter = 0; 184 uint64_t mLastReceivedFrameCounter = 0; 185 nsTArray<RefPtr<Promise>> mKeyFrameRequestPromises; 186 // Contains the promise returned for each call to GenerateKeyFrame(rid), in 187 // the order in which it was called, keyed by the rid (empty string if not 188 // passed). If there is already a promise in here for a given rid, we do not 189 // ask the FrameTransformerProxy again, and just bulk resolve/reject. 190 GenerateKeyFramePromises mGenerateKeyFramePromises; 191 Maybe<bool> mVideo; 192 RefPtr<StrongWorkerRef> mWorkerRef; 193 }; 194 195 } // namespace dom 196 } // namespace mozilla 197 198 #endif // MOZILLA_DOM_MEDIA_WEBRTC_JSAPI_RTCRTPSCRIPTTRANSFORMER_H_