1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_SOURCE_H_
6 #define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_SOURCE_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "base/compiler_specific.h"
13 #include "base/macros.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/optional.h"
16 #include "base/threading/thread_checker.h"
17 #include "media/base/video_frame.h"
18 #include "media/capture/video_capture_types.h"
19 #include "third_party/blink/public/common/media/video_capture.h"
20 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
21 #include "third_party/blink/public/platform/modules/mediastream/media_stream_types.h"
22 #include "third_party/blink/public/platform/modules/mediastream/secure_display_link_tracker.h"
23 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
24 #include "third_party/blink/public/platform/web_common.h"
25 #include "third_party/blink/public/platform/web_media_stream_source.h"
26 #include "third_party/blink/public/platform/web_media_stream_track.h"
27 #include "third_party/blink/public/web/modules/mediastream/encoded_video_frame.h"
28 
29 namespace base {
30 class SingleThreadTaskRunner;
31 }
32 
33 namespace blink {
34 
35 class MediaStreamVideoTrack;
36 class VideoTrackAdapter;
37 class VideoTrackAdapterSettings;
38 
39 // MediaStreamVideoSource is an interface used for sending video frames to a
40 // MediaStreamVideoTrack.
41 // https://dev.w3.org/2011/webrtc/editor/getusermedia.html
42 // The purpose of this base class is to be able to implement different
43 // MediaStreamVideoSources such as local video capture, video sources received
44 // on a PeerConnection or a source created in NaCl.
45 // All methods calls will be done from the main render thread.
46 class BLINK_MODULES_EXPORT MediaStreamVideoSource
47     : public WebPlatformMediaStreamSource {
48  public:
49   enum {
50     // Default resolution. If no constraints are specified and the delegate
51     // support it, this is the resolution that will be used.
52     kDefaultWidth = 640,
53     kDefaultHeight = 480,
54 
55     kDefaultFrameRate = 30,
56     kUnknownFrameRate = 0,
57   };
58 
59   enum class RestartResult { IS_RUNNING, IS_STOPPED, INVALID_STATE };
60   // RestartCallback is used for both the StopForRestart and Restart operations.
61   using RestartCallback = base::OnceCallback<void(RestartResult)>;
62 
63   MediaStreamVideoSource();
64   ~MediaStreamVideoSource() override;
65 
66   // Returns the MediaStreamVideoSource object owned by |source|.
67   static MediaStreamVideoSource* GetVideoSource(
68       const WebMediaStreamSource& source);
69 
70   // Puts |track| in the registered tracks list.
71   void AddTrack(MediaStreamVideoTrack* track,
72                 const VideoTrackAdapterSettings& track_adapter_settings,
73                 const VideoCaptureDeliverFrameCB& frame_callback,
74                 const EncodedVideoFrameCB& encoded_frame_callback,
75                 const VideoTrackSettingsCallback& settings_callback,
76                 const VideoTrackFormatCallback& format_callback,
77                 ConstraintsOnceCallback callback);
78   void RemoveTrack(MediaStreamVideoTrack* track, base::OnceClosure callback);
79 
80   // Reconfigures this MediaStreamVideoSource to use |adapter_settings| on
81   // |track|, as long as |track| is connected to this source.
82   // Do not invoke if |track| is connected to a different source, as the
83   // internal state of |track| might become inconsistent with that of its
84   // source.
85   void ReconfigureTrack(MediaStreamVideoTrack* track,
86                         const VideoTrackAdapterSettings& adapter_settings);
87 
88   // Tries to temporarily stop this source so that it can be later restarted
89   // with a different video format. Unlike MediaStreamVideoSource::StopSource(),
90   // a temporary stop for restart does not change the ready state of the source.
91   // Once the attempt to temporarily stop the source is completed, |callback|
92   // is invoked with IS_STOPPED if the source actually stopped, or IS_RUNNING
93   // if the source did not stop and is still running.
94   // This method can only be called after a source has started. This can be
95   // verified by checking that the IsRunning() method returns true.
96   // Any attempt to invoke StopForRestart() before the source has started
97   // results in no action and |callback| invoked with INVALID_STATE.
98   void StopForRestart(RestartCallback callback);
99 
100   // Tries to restart a source that was previously temporarily stopped using the
101   // supplied |new_format|. This method can be invoked only after a successful
102   // call to StopForRestart().
103   // Once the attempt to restart the source is completed, |callback| is invoked
104   // with IS_RUNNING if the source restarted and IS_STOPPED if the source
105   // remained stopped. Note that it is not guaranteed that the source actually
106   // restarts using |new_format| as its configuration. After a successful
107   // restart, the actual configured format for the source (if available) can be
108   // obtained with a call to GetCurrentFormat().
109   // Note also that, since frames are delivered on a different thread, it is
110   // possible that frames using the old format are delivered for a while after
111   // a successful restart. Code relying on Restart() cannot assume that new
112   // frames are guaranteed to arrive in the new format until the first frame in
113   // the new format is received.
114   // This method can only be called after a successful stop for restart (i.e.,
115   // after the callback passed to StopForRestart() is invoked with a value of
116   // IS_STOPPED). Any attempt to invoke Restart() when the source is not in this
117   // state results in no action and |callback| invoked with INVALID_STATE.
118   void Restart(const media::VideoCaptureFormat& new_format,
119                RestartCallback callback);
120 
121   // Called by |track| to notify the source whether it has any paths to a
122   // consuming endpoint.
123   void UpdateHasConsumers(MediaStreamVideoTrack* track, bool has_consumers);
124 
125   void UpdateCapturingLinkSecure(MediaStreamVideoTrack* track, bool is_secure);
126 
127   // Request underlying source to capture a new frame.
RequestRefreshFrame()128   virtual void RequestRefreshFrame() {}
129 
130   // Optionally overridden by subclasses to implement handling frame drop
131   // events.
OnFrameDropped(media::VideoCaptureFrameDropReason reason)132   virtual void OnFrameDropped(media::VideoCaptureFrameDropReason reason) {}
133 
134   // Optionally overridden by subclasses to implement handling log messages.
OnLog(const std::string & message)135   virtual void OnLog(const std::string& message) {}
136 
137   // Enables or disables an heuristic to detect frames from rotated devices.
138   void SetDeviceRotationDetection(bool enabled);
139 
140   // Returns the task runner where video frames will be delivered on.
141   base::SingleThreadTaskRunner* io_task_runner() const;
142 
143   // Implementations must return the capture format if available.
144   // Implementations supporting devices of type MEDIA_DEVICE_VIDEO_CAPTURE
145   // must return a value.
146   virtual base::Optional<media::VideoCaptureFormat> GetCurrentFormat() const;
147 
148   // Implementations must return the capture parameters if available.
149   // Implementations supporting devices of type MEDIA_DEVICE_VIDEO_CAPTURE
150   // must return a value. The format in the returned VideoCaptureParams must
151   // coincide with the value returned by GetCurrentFormat().
152   virtual base::Optional<media::VideoCaptureParams> GetCurrentCaptureParams()
153       const;
154 
155   // Returns true if encoded output can be enabled in the source.
156   virtual bool SupportsEncodedOutput() const;
157 
158   // Notifies the source about that the number of encoded sinks have been
159   // updated. Note: Can only be called if the number of encoded sinks have
160   // actually changed!
161   void UpdateNumEncodedSinks();
162 
IsRunning()163   bool IsRunning() const { return state_ == STARTED; }
164 
NumTracks()165   size_t NumTracks() const {
166     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
167     return tracks_.size();
168   }
169 
GetWeakPtr()170   base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() {
171     return weak_factory_.GetWeakPtr();
172   }
173 
174  protected:
175   // MediaStreamSource implementation.
176   void DoChangeSource(const MediaStreamDevice& new_device) override;
177   void DoStopSource() override;
178 
179   // Sets ready state and notifies the ready state to all registered tracks.
180   virtual void SetReadyState(WebMediaStreamSource::ReadyState state);
181 
182   // Sets muted state and notifies it to all registered tracks.
183   virtual void SetMutedState(bool state);
184 
185   // An implementation must start capturing frames after this method is called.
186   // When the source has started or failed to start OnStartDone must be called.
187   // An implementation must call |frame_callback| on the IO thread with the
188   // captured frames, and |encoded_frame_callback| with encoded frames if
189   // supported and enabled via OnEncodedSinkEnabled.
190   virtual void StartSourceImpl(VideoCaptureDeliverFrameCB frame_callback,
191                                EncodedVideoFrameCB encoded_frame_callback) = 0;
192   void OnStartDone(mojom::MediaStreamRequestResult result);
193 
194   // A subclass that supports restart must override this method such that it
195   // immediately stop producing video frames after this method is called.
196   // The stop is intended to be temporary and to be followed by a restart. Thus,
197   // connected tracks should not be disconnected or notified about the source no
198   // longer producing frames. Once the source is stopped, the implementation
199   // must invoke OnStopForRestartDone() with true. If the source cannot stop,
200   // OnStopForRestartDone() must invoked with false.
201   // It can be assumed that this method is invoked only when the source is
202   // running.
203   // Note that if this method is overridden, RestartSourceImpl() must also be
204   // overridden following the respective contract. Otherwise, behavior is
205   // undefined.
206   // The default implementation does not support restart and just calls
207   // OnStopForRestartDone() with false.
208   virtual void StopSourceForRestartImpl();
209 
210   // This method should be called by implementations once an attempt to stop
211   // for restart using StopSourceForRestartImpl() is completed.
212   // |did_stop_for_restart| must true if the source is stopped and false if
213   // the source is running.
214   void OnStopForRestartDone(bool did_stop_for_restart);
215 
216   // A subclass that supports restart must override this method such that it
217   // tries to start producing frames after this method is called. If successful,
218   // the source should return to the same state as if it was started normally
219   // and invoke OnRestartDone() with true. The implementation should preferably
220   // restart to produce frames with the format specified in |new_format|.
221   // However, if this is not possible, the implementation is allowed to restart
222   // using a different format. In this case OnRestartDone() should be invoked
223   // with true as well. If it is impossible to restart the source with any
224   // format, the source should remain stopped and OnRestartDone() should be
225   // invoked with false.
226   // This method can only be invoked when the source is temporarily stopped
227   // after a successful OnStopForRestartDone(). Otherwise behavior is undefined.
228   // Note that if this method is overridden, StopSourceForRestartImpl() must
229   // also be overridden following the respective contract. Otherwise, behavior
230   // is undefined.
231   virtual void RestartSourceImpl(const media::VideoCaptureFormat& new_format);
232 
233   // This method should be called by implementations once an attempt to restart
234   // the source completes. |did_restart| must be true if the source is running
235   // and false if the source is stopped.
236   void OnRestartDone(bool did_restart);
237 
238   // An implementation must immediately stop producing video frames after this
239   // method has been called. After this method has been called,
240   // MediaStreamVideoSource may be deleted.
241   virtual void StopSourceImpl() = 0;
242 
243   // Optionally overridden by subclasses to act on whether there are any
244   // consumers present. When none are present, the source can stop delivering
245   // frames, giving it the option of running in an "idle" state to minimize
246   // resource usage.
OnHasConsumers(bool has_consumers)247   virtual void OnHasConsumers(bool has_consumers) {}
248 
249   // Optionally overridden by subclasses to act on whether the capturing link
250   // has become secure or insecure.
OnCapturingLinkSecured(bool is_secure)251   virtual void OnCapturingLinkSecured(bool is_secure) {}
252 
253   // Optionally overridden by subclasses to implement changing source.
ChangeSourceImpl(const MediaStreamDevice & new_device)254   virtual void ChangeSourceImpl(const MediaStreamDevice& new_device) {}
255 
256   // Optionally override by subclasses to implement encoded source control.
257   // The method is called when at least one encoded sink has been added.
OnEncodedSinkEnabled()258   virtual void OnEncodedSinkEnabled() {}
259 
260   // Optionally override by subclasses to implement encoded source control.
261   // The method is called when the last encoded sink has been removed.
OnEncodedSinkDisabled()262   virtual void OnEncodedSinkDisabled() {}
263 
264   enum State {
265     NEW,
266     STARTING,
267     STOPPING_FOR_RESTART,
268     STOPPED_FOR_RESTART,
269     RESTARTING,
270     STARTED,
271     ENDED
272   };
state()273   State state() const { return state_; }
274 
275   THREAD_CHECKER(thread_checker_);
276 
277  private:
278   // Trigger all cached callbacks from AddTrack. AddTrack is successful
279   // if the capture delegate has started and the constraints provided in
280   // AddTrack match the format that was used to start the device.
281   // Note that it must be ok to delete the MediaStreamVideoSource object
282   // in the context of the callback. If gUM fails, the implementation will
283   // simply drop the references to the blink source and track which will lead
284   // to this object being deleted.
285   void FinalizeAddPendingTracks();
286 
287   // Actually adds |track| to this source, provided the source has started.
288   void FinalizeAddTrack(MediaStreamVideoTrack* track,
289                         const VideoCaptureDeliverFrameCB& frame_callback,
290                         const VideoTrackAdapterSettings& adapter_settings);
291   void StartFrameMonitoring();
292   void UpdateTrackSettings(MediaStreamVideoTrack* track,
293                            const VideoTrackAdapterSettings& adapter_settings);
294   void DidStopSource(RestartResult result);
295   void NotifyCapturingLinkSecured(size_t num_encoded_sinks);
296   size_t CountEncodedSinks() const;
297 
298   State state_;
299 
300   struct PendingTrackInfo {
301     PendingTrackInfo(
302         MediaStreamVideoTrack* track,
303         const VideoCaptureDeliverFrameCB& frame_callback,
304         const EncodedVideoFrameCB& encoded_frame_callback,
305         const VideoTrackSettingsCallback& settings_callback,
306         const VideoTrackFormatCallback& format_callback,
307         std::unique_ptr<VideoTrackAdapterSettings> adapter_settings,
308         ConstraintsOnceCallback callback);
309     PendingTrackInfo(PendingTrackInfo&& other);
310     PendingTrackInfo& operator=(PendingTrackInfo&& other);
311     ~PendingTrackInfo();
312 
313     MediaStreamVideoTrack* track;
314     VideoCaptureDeliverFrameCB frame_callback;
315     EncodedVideoFrameCB encoded_frame_callback;
316     VideoTrackSettingsCallback settings_callback;
317     VideoTrackFormatCallback format_callback;
318     // TODO(guidou): Make |adapter_settings| a regular field instead of a
319     // unique_ptr.
320     std::unique_ptr<VideoTrackAdapterSettings> adapter_settings;
321     ConstraintsOnceCallback callback;
322   };
323   std::vector<PendingTrackInfo> pending_tracks_;
324 
325   // |restart_callback_| is used for notifying both StopForRestart and Restart,
326   // since it is impossible to have a situation where there can be callbacks
327   // for both at the same time.
328   RestartCallback restart_callback_;
329 
330   // |track_adapter_| delivers video frames to the tracks on the IO-thread.
331   scoped_refptr<VideoTrackAdapter> track_adapter_;
332 
333   // Tracks that currently are connected to this source.
334   std::vector<MediaStreamVideoTrack*> tracks_;
335 
336   // Tracks that have no paths to a consuming endpoint, and so do not need
337   // frames delivered from the source. This is a subset of |tracks_|.
338   std::vector<MediaStreamVideoTrack*> suspended_tracks_;
339 
340   // This is used for tracking if all connected video sinks are secure.
341   SecureDisplayLinkTracker<MediaStreamVideoTrack> secure_tracker_;
342 
343   // This flag enables a heuristic to detect device rotation based on frame
344   // size.
345   bool enable_device_rotation_detection_ = false;
346 
347   // Callback that needs to trigger after removing the track. If this object
348   // died before this callback is resolved, we still need to trigger the
349   // callback to notify the caller that the request is canceled.
350   base::OnceClosure remove_last_track_callback_;
351 
352   // NOTE: Weak pointers must be invalidated before all other member variables.
353   base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_{this};
354 
355   DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoSource);
356 };
357 
358 }  // namespace blink
359 
360 #endif  // THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_SOURCE_H_
361