| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_H_ |
| #define CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <unordered_set> |
| |
| #include "base/containers/queue.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "base/process/process.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/values.h" |
| #include "content/common/content_export.h" |
| #include "content/public/browser/global_routing_id.h" |
| #include "content/public/browser/peer_connection_tracker_host_observer.h" |
| #include "content/public/browser/render_process_host_observer.h" |
| #include "media/media_buildflags.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "services/device/public/mojom/wake_lock.mojom.h" |
| #include "ui/shell_dialogs/select_file_dialog.h" |
| |
| namespace media { |
| class AudioDebugRecordingSession; |
| } |
| |
| namespace content { |
| |
| class WebContents; |
| class WebRtcInternalsConnectionsObserver; |
| class WebRTCInternalsUIObserver; |
| |
| // This is a singleton class running in the browser UI thread. |
| // It collects peer connection infomation from the renderers, |
| // forwards the data to WebRTCInternalsUIObserver and |
| // sends data collecting commands to the renderers. |
| class CONTENT_EXPORT WebRTCInternals : public PeerConnectionTrackerHostObserver, |
| public RenderProcessHostObserver, |
| public ui::SelectFileDialog::Listener { |
| public: |
| // * CreateSingletonInstance() ensures that no previous instantiation of the |
| // class was performed, then instantiates the class and returns the object. |
| // * GetInstance() returns the object previously constructed using |
| // CreateSingletonInstance(). It may return null in tests. |
| // * Creation is separated from access because WebRTCInternals may only be |
| // created from a context that allows blocking. If GetInstance were allowed |
| // to instantiate, as with a lazily constructed singleton, it would be |
| // difficult to guarantee that its construction is always first attempted |
| // from a context that allows it. |
| static WebRTCInternals* CreateSingletonInstance(); |
| static WebRTCInternals* GetInstance(); |
| |
| ~WebRTCInternals() override; |
| |
| // PeerConnectionTrackerHostObserver implementation. |
| void OnPeerConnectionAdded(GlobalRenderFrameHostId frame_id, |
| int lid, |
| base::ProcessId pid, |
| const std::string& url, |
| const std::string& rtc_configuration) override; |
| void OnPeerConnectionRemoved(GlobalRenderFrameHostId frame_id, |
| int lid) override; |
| void OnPeerConnectionUpdated(GlobalRenderFrameHostId frame_id, |
| int lid, |
| const std::string& type, |
| const std::string& value) override; |
| void OnAddStandardStats(GlobalRenderFrameHostId frame_id, |
| int lid, |
| base::Value::List value) override; |
| void OnGetUserMedia(GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| bool audio, |
| bool video, |
| const std::string& audio_constraints, |
| const std::string& video_constraints) override; |
| void OnGetUserMediaSuccess(GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| const std::string& stream_id, |
| const std::string& audio_track_info, |
| const std::string& video_track_info) override; |
| void OnGetUserMediaFailure(GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| const std::string& error, |
| const std::string& error_message) override; |
| |
| void OnGetDisplayMedia(GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| bool audio, |
| bool video, |
| const std::string& audio_constraints, |
| const std::string& video_constraints) override; |
| void OnGetDisplayMediaSuccess(GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| const std::string& stream_id, |
| const std::string& audio_track_info, |
| const std::string& video_track_info) override; |
| void OnGetDisplayMediaFailure(GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| const std::string& error, |
| const std::string& error_message) override; |
| |
| // Methods for adding or removing WebRTCInternalsUIObserver. |
| void AddObserver(WebRTCInternalsUIObserver* observer); |
| void RemoveObserver(WebRTCInternalsUIObserver* observer); |
| |
| // Methods for adding or removing WebRtcInternalsConnectionsObserver. |
| // |observer| is notified when there is a change in the count of active WebRTC |
| // connections. |
| void AddConnectionsObserver(WebRtcInternalsConnectionsObserver* observer); |
| void RemoveConnectionsObserver(WebRtcInternalsConnectionsObserver* observer); |
| |
| // Sends all update data to |observer|. |
| void UpdateObserver(WebRTCInternalsUIObserver* observer); |
| |
| // Enables or disables diagnostic audio recordings for debugging purposes. |
| void EnableAudioDebugRecordings(content::WebContents* web_contents); |
| void DisableAudioDebugRecordings(); |
| |
| bool IsAudioDebugRecordingsEnabled() const; |
| const base::FilePath& GetAudioDebugRecordingsFilePath() const; |
| |
| // Enables or disables diagnostic event log. |
| void EnableLocalEventLogRecordings(content::WebContents* web_contents); |
| void DisableLocalEventLogRecordings(); |
| |
| bool IsEventLogRecordingsEnabled() const; |
| bool CanToggleEventLogRecordings() const; |
| |
| int num_connected_connections() const { return num_connected_connections_; } |
| |
| protected: |
| // Constructor/Destructor are protected to allow tests to derive from the |
| // class and do per-instance testing without having to use the global |
| // instance. |
| // The default ctor sets |aggregate_updates_ms| to 500ms. |
| WebRTCInternals(); |
| WebRTCInternals(int aggregate_updates_ms, bool should_block_power_saving); |
| |
| mojo::Remote<device::mojom::WakeLock> wake_lock_; |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(WebRtcAudioDebugRecordingsBrowserTest, |
| CallWithAudioDebugRecordings); |
| FRIEND_TEST_ALL_PREFIXES(WebRtcAudioDebugRecordingsBrowserTest, |
| CallWithAudioDebugRecordingsEnabledThenDisabled); |
| FRIEND_TEST_ALL_PREFIXES(WebRtcAudioDebugRecordingsBrowserTest, |
| TwoCallsWithAudioDebugRecordings); |
| FRIEND_TEST_ALL_PREFIXES(WebRtcInternalsTest, |
| AudioDebugRecordingsFileSelectionCanceled); |
| |
| static WebRTCInternals* g_webrtc_internals; |
| |
| void SendUpdate(const std::string& event_name, base::Value event_data); |
| void SendUpdate(const std::string& event_name, base::Value::Dict event_data); |
| |
| // RenderProcessHostObserver implementation. |
| void RenderProcessExited(RenderProcessHost* host, |
| const ChildProcessTerminationInfo& info) override; |
| |
| // ui::SelectFileDialog::Listener implementation. |
| void FileSelected(const ui::SelectedFileInfo& file, int index) override; |
| void FileSelectionCanceled() override; |
| |
| // Called when a renderer exits (including crashes). |
| void OnRendererExit(int render_process_id); |
| |
| // Enables diagnostic audio recordings on all render process hosts using |
| // |audio_debug_recordings_file_path_|. |
| void EnableAudioDebugRecordingsOnAllRenderProcessHosts(); |
| |
| // Updates the number of open PeerConnections. Called when a PeerConnection |
| // is stopped or removed. |
| void MaybeClosePeerConnection(base::Value& record); |
| |
| void MaybeMarkPeerConnectionAsConnected(base::Value& record); |
| void MaybeMarkPeerConnectionAsNotConnected(base::Value& record); |
| |
| // Called whenever a PeerConnection is created or stopped in order to |
| // request/cancel a wake lock on suspending the current application for power |
| // saving. |
| void UpdateWakeLock(); |
| |
| // Convenient method to access `peer_connection_data_` as a Value::List. |
| base::Value::List& peer_connection_data() { |
| return peer_connection_data_.GetList(); |
| } |
| |
| device::mojom::WakeLock* GetWakeLock(); |
| |
| // Called on a timer to deliver updates to javascript. |
| // We throttle and bulk together updates to avoid DOS like scenarios where |
| // a page uses a lot of peerconnection instances with many event |
| // notifications. |
| void ProcessPendingUpdates(); |
| |
| // Returns an iterator for peer_connection_data_.GetList (an end() iterator |
| // if not found). |
| base::Value::List::iterator FindRecord(GlobalRenderFrameHostId frame_id, |
| int lid); |
| |
| base::ObserverList<WebRTCInternalsUIObserver>::Unchecked observers_; |
| |
| base::ObserverList<WebRtcInternalsConnectionsObserver> connections_observers_; |
| |
| // |peer_connection_data_| is a list containing all the PeerConnection |
| // updates. Stored as a Value rather than as a List::Value so it can be passed |
| // as a Value without having to copy it. |
| // |
| // Each item of the list represents the data for one PeerConnection, which |
| // contains these fields: |
| // "rid" -- the renderer id. |
| // "pid" -- OS process id of the renderer that creates the PeerConnection. |
| // "lid" -- local Id assigned to the PeerConnection. |
| // "url" -- url of the web page that created the PeerConnection. |
| // "rtcConfiguration" -- serialized rtcConfiguration object. |
| // "constraints" -- serialized legacy peerconnection constraints. |
| // used to initialize the PeerConnection respectively. |
| // "log" -- a List contains all the updates for the PeerConnection. Each |
| // list item is a DictionaryValue containing "time", which is the number of |
| // milliseconds since epoch as a string, and "type" and "value", both of which |
| // are strings representing the event. |
| base::Value peer_connection_data_; |
| |
| // A list of getUserMedia requests or updates. |
| // Each item is a DictionaryValue that contains some of these fields |
| // depending on the type: |
| // "rid" -- the renderer id. |
| // "pid" -- OS process id of the renderer that creates the PeerConnection. |
| // "origin" -- the security origin of the request. |
| // "audio" -- the serialized audio constraints if audio is requested. |
| // "video" -- the serialized video constraints if video is requested. |
| // "timestamp" -- time of the request |
| // "stream_id" -- the resulting stream id. |
| // "audio_track_info" -- the serialized audio track (track id and label). |
| // "video_track_info" -- the serialized video track (track id and label). |
| base::Value::List get_user_media_requests_; |
| |
| // For managing select file dialog. |
| scoped_refptr<ui::SelectFileDialog> select_file_dialog_; |
| enum class SelectionType { |
| kRtcEventLogs, |
| kAudioDebugRecordings |
| } selection_type_; |
| |
| // Diagnostic audio recording state. |
| base::FilePath audio_debug_recordings_file_path_; |
| std::unique_ptr<media::AudioDebugRecordingSession> |
| audio_debug_recording_session_; |
| |
| // If non-empty, WebRTC (local) event logging should be enabled using this |
| // path, and may not be turned off, except by restarting the browser. |
| const base::FilePath command_line_derived_logging_path_; |
| |
| // Diagnostic event log recording state. These are meaningful only when |
| // |command_line_derived_logging_path_| is empty. |
| bool event_log_recordings_; |
| base::FilePath event_log_recordings_file_path_; |
| |
| // While |num_connected_connections_| is greater than zero, request a wake |
| // lock service. This prevents the application from being suspended while |
| // remoting. |
| int num_connected_connections_; |
| const bool should_block_power_saving_; |
| |
| // Set of render process hosts that |this| is registered as an observer on. |
| std::unordered_set<int> render_process_id_set_; |
| |
| // Used to bulk up updates that we send to javascript. |
| // The class owns the value/dictionary and command name of an update. |
| // For each update, a PendingUpdate is stored in the |pending_updates_| queue |
| // and deleted as soon as the update has been delivered. |
| // The class is moveble and not copyable to avoid copying while still allowing |
| // us to use an stl container without needing scoped_ptr or similar. |
| // The class is single threaded, so all operations must occur on the same |
| // thread. |
| class PendingUpdate { |
| public: |
| PendingUpdate(const std::string& event_name, base::Value event_data); |
| PendingUpdate(PendingUpdate&& other); |
| |
| PendingUpdate(const PendingUpdate&) = delete; |
| PendingUpdate& operator=(const PendingUpdate&) = delete; |
| |
| ~PendingUpdate(); |
| |
| const std::string& event_name() const; |
| const base::Value* event_data() const; |
| |
| private: |
| base::ThreadChecker thread_checker_; |
| const std::string event_name_; |
| base::Value event_data_; |
| }; |
| |
| base::queue<PendingUpdate> pending_updates_; |
| const int aggregate_updates_ms_; |
| |
| // Weak factory for this object that we use for bulking up updates. |
| base::WeakPtrFactory<WebRTCInternals> weak_factory_{this}; |
| |
| // Helper functions for getUserMedia/getDisplayMedia. |
| void OnGetMedia(const std::string& request_type, |
| GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| bool audio, |
| bool video, |
| const std::string& audio_constraints, |
| const std::string& video_constraints); |
| void OnGetMediaSuccess(const std::string& request_type, |
| GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| const std::string& stream_id, |
| const std::string& audio_track_info, |
| const std::string& video_track_info); |
| void OnGetMediaFailure(const std::string& request_type, |
| GlobalRenderFrameHostId frame_id, |
| base::ProcessId pid, |
| int request_id, |
| const std::string& error, |
| const std::string& error_message); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_WEBRTC_WEBRTC_INTERNALS_H_ |