1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef MediaRecorder_h
8 #define MediaRecorder_h
9 
10 #include "mozilla/dom/MediaRecorderBinding.h"
11 #include "mozilla/DOMEventTargetHelper.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "nsIDocumentActivity.h"
14 
15 // Max size for allowing queue encoded data in memory
16 #define MAX_ALLOW_MEMORY_BUFFER 1024000
17 namespace mozilla {
18 
19 class AudioNodeStream;
20 class DOMMediaStream;
21 class ErrorResult;
22 class MediaInputPort;
23 struct MediaRecorderOptions;
24 class MediaStream;
25 class GlobalObject;
26 
27 namespace dom {
28 
29 class AudioNode;
30 
31 /**
32  * Implementation of https://dvcs.w3.org/hg/dap/raw-file/default/media-stream-capture/MediaRecorder.html
33  * The MediaRecorder accepts a mediaStream as input source passed from UA. When recorder starts,
34  * a MediaEncoder will be created and accept the mediaStream as input source.
35  * Encoder will get the raw data by track data changes, encode it by selected MIME Type, then store the encoded in EncodedBufferCache object.
36  * The encoded data will be extracted on every timeslice passed from Start function call or by RequestData function.
37  * Thread model:
38  * When the recorder starts, it creates a "Media Encoder" thread to read data from MediaEncoder object and store buffer in EncodedBufferCache object.
39  * Also extract the encoded data and create blobs on every timeslice passed from start function or RequestData function called by UA.
40  */
41 
42 class MediaRecorder final : public DOMEventTargetHelper,
43                             public nsIDocumentActivity
44 {
45   class Session;
46 
47 public:
48   MediaRecorder(DOMMediaStream& aSourceMediaStream,
49                 nsPIDOMWindowInner* aOwnerWindow);
50   MediaRecorder(AudioNode& aSrcAudioNode, uint32_t aSrcOutput,
51                 nsPIDOMWindowInner* aOwnerWindow);
52 
53   // nsWrapperCache
54   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
55 
GetParentObject()56   nsPIDOMWindowInner* GetParentObject() { return GetOwner(); }
57 
58   NS_DECL_ISUPPORTS_INHERITED
59   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaRecorder,
60                                            DOMEventTargetHelper)
61 
62   // WebIDL
63   // Start recording. If timeSlice has been provided, mediaRecorder will
64   // raise a dataavailable event containing the Blob of collected data on every timeSlice milliseconds.
65   // If timeSlice isn't provided, UA should call the RequestData to obtain the Blob data, also set the mTimeSlice to zero.
66   void Start(const Optional<int32_t>& timeSlice, ErrorResult & aResult);
67   // Stop the recording activiy. Including stop the Media Encoder thread, un-hook the mediaStreamListener to encoder.
68   void Stop(ErrorResult& aResult);
69   // Pause the mTrackUnionStream
70   void Pause(ErrorResult& aResult);
71 
72   void Resume(ErrorResult& aResult);
73   // Extract encoded data Blob from EncodedBufferCache.
74   void RequestData(ErrorResult& aResult);
75   // Return the The DOMMediaStream passed from UA.
Stream()76   DOMMediaStream* Stream() const { return mDOMStream; }
77   // The current state of the MediaRecorder object.
State()78   RecordingState State() const { return mState; }
79   // Return the current encoding MIME type selected by the MediaEncoder.
80   void GetMimeType(nsString &aMimeType);
81 
82   static bool IsTypeSupported(GlobalObject& aGlobal, const nsAString& aType);
83   static bool IsTypeSupported(const nsAString& aType);
84 
85   // Construct a recorder with a DOM media stream object as its source.
86   static already_AddRefed<MediaRecorder>
87   Constructor(const GlobalObject& aGlobal,
88               DOMMediaStream& aStream,
89               const MediaRecorderOptions& aInitDict,
90               ErrorResult& aRv);
91   // Construct a recorder with a Web Audio destination node as its source.
92   static already_AddRefed<MediaRecorder>
93   Constructor(const GlobalObject& aGlobal,
94               AudioNode& aSrcAudioNode,
95               uint32_t aSrcOutput,
96               const MediaRecorderOptions& aInitDict,
97               ErrorResult& aRv);
98 
99   /*
100    * Measure the size of the buffer, and memory occupied by mAudioEncoder
101    * and mVideoEncoder
102    */
103   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
104   // EventHandler
105   IMPL_EVENT_HANDLER(dataavailable)
IMPL_EVENT_HANDLER(error)106   IMPL_EVENT_HANDLER(error)
107   IMPL_EVENT_HANDLER(start)
108   IMPL_EVENT_HANDLER(stop)
109   IMPL_EVENT_HANDLER(warning)
110 
111   NS_DECL_NSIDOCUMENTACTIVITY
112 
113   uint32_t GetAudioBitrate() { return mAudioBitsPerSecond; }
GetVideoBitrate()114   uint32_t GetVideoBitrate() { return mVideoBitsPerSecond; }
GetBitrate()115   uint32_t GetBitrate() { return mBitsPerSecond; }
116 protected:
117   virtual ~MediaRecorder();
118 
119   MediaRecorder& operator = (const MediaRecorder& x) = delete;
120   // Create dataavailable event with Blob data and it runs in main thread
121   nsresult CreateAndDispatchBlobEvent(already_AddRefed<nsIDOMBlob>&& aBlob);
122   // Creating a simple event to notify UA simple event.
123   void DispatchSimpleEvent(const nsAString & aStr);
124   // Creating a error event with message.
125   void NotifyError(nsresult aRv);
126   // Set encoded MIME type.
127   void SetMimeType(const nsString &aMimeType);
128   void SetOptions(const MediaRecorderOptions& aInitDict);
129 
130   MediaRecorder(const MediaRecorder& x) = delete; // prevent bad usage
131   // Remove session pointer.
132   void RemoveSession(Session* aSession);
133   // Functions for Session to query input source info.
134   MediaStream* GetSourceMediaStream();
135   // DOM wrapper for source media stream. Will be null when input is audio node.
136   RefPtr<DOMMediaStream> mDOMStream;
137   // Source audio node. Will be null when input is a media stream.
138   RefPtr<AudioNode> mAudioNode;
139   // Pipe stream connecting non-destination source node and session track union
140   // stream of recorder. Will be null when input is media stream or destination
141   // node.
142   RefPtr<AudioNodeStream> mPipeStream;
143   // Connect source node to the pipe stream.
144   RefPtr<MediaInputPort> mInputPort;
145 
146   // The current state of the MediaRecorder object.
147   RecordingState mState;
148   // Hold the sessions reference and clean it when the DestroyRunnable for a
149   // session is running.
150   nsTArray<RefPtr<Session> > mSessions;
151 
152   nsCOMPtr<nsIDocument> mDocument;
153 
154   // It specifies the container format as well as the audio and video capture formats.
155   nsString mMimeType;
156 
157   uint32_t mAudioBitsPerSecond;
158   uint32_t mVideoBitsPerSecond;
159   uint32_t mBitsPerSecond;
160 private:
161   // Register MediaRecorder into Document to listen the activity changes.
162   void RegisterActivityObserver();
163   void UnRegisterActivityObserver();
164 
165   bool CheckPermission(const nsString &aType);
166 };
167 
168 } // namespace dom
169 } // namespace mozilla
170 
171 #endif
172