Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2013 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 #include "content/browser/media/webrtc_internals.h"
      6 
      7 #include "content/browser/media/webrtc_internals_ui_observer.h"
      8 #include "content/public/browser/browser_thread.h"
      9 #include "content/public/browser/child_process_data.h"
     10 #include "content/public/browser/notification_service.h"
     11 #include "content/public/browser/notification_types.h"
     12 #include "content/public/browser/render_process_host.h"
     13 
     14 using base::ProcessId;
     15 using std::string;
     16 
     17 namespace content {
     18 
     19 namespace {
     20 // Makes sure that |dict| has a ListValue under path "log".
     21 static base::ListValue* EnsureLogList(base::DictionaryValue* dict) {
     22   base::ListValue* log = NULL;
     23   if (!dict->GetList("log", &log)) {
     24     log = new base::ListValue();
     25     if (log)
     26       dict->Set("log", log);
     27   }
     28   return log;
     29 }
     30 
     31 }  // namespace
     32 
     33 WebRTCInternals::WebRTCInternals() : is_recording_rtp_(false) {
     34   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
     35                  NotificationService::AllBrowserContextsAndSources());
     36 
     37   BrowserChildProcessObserver::Add(this);
     38 }
     39 
     40 WebRTCInternals::~WebRTCInternals() {
     41   BrowserChildProcessObserver::Remove(this);
     42 }
     43 
     44 WebRTCInternals* WebRTCInternals::GetInstance() {
     45   return Singleton<WebRTCInternals>::get();
     46 }
     47 
     48 void WebRTCInternals::OnAddPeerConnection(int render_process_id,
     49                                           ProcessId pid,
     50                                           int lid,
     51                                           const string& url,
     52                                           const string& servers,
     53                                           const string& constraints) {
     54   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     55 
     56   base::DictionaryValue* dict = new base::DictionaryValue();
     57   if (!dict)
     58     return;
     59 
     60   dict->SetInteger("rid", render_process_id);
     61   dict->SetInteger("pid", static_cast<int>(pid));
     62   dict->SetInteger("lid", lid);
     63   dict->SetString("servers", servers);
     64   dict->SetString("constraints", constraints);
     65   dict->SetString("url", url);
     66   peer_connection_data_.Append(dict);
     67 
     68   if (observers_.size() > 0)
     69     SendUpdate("addPeerConnection", dict);
     70 }
     71 
     72 void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
     73   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     74   for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
     75     base::DictionaryValue* dict = NULL;
     76     peer_connection_data_.GetDictionary(i, &dict);
     77 
     78     int this_pid = 0;
     79     int this_lid = 0;
     80     dict->GetInteger("pid", &this_pid);
     81     dict->GetInteger("lid", &this_lid);
     82 
     83     if (this_pid != static_cast<int>(pid) || this_lid != lid)
     84       continue;
     85 
     86     peer_connection_data_.Remove(i, NULL);
     87 
     88     if (observers_.size() > 0) {
     89       base::DictionaryValue id;
     90       id.SetInteger("pid", static_cast<int>(pid));
     91       id.SetInteger("lid", lid);
     92       SendUpdate("removePeerConnection", &id);
     93     }
     94     break;
     95   }
     96 }
     97 
     98 void WebRTCInternals::OnUpdatePeerConnection(
     99     ProcessId pid, int lid, const string& type, const string& value) {
    100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    101 
    102   for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
    103     base::DictionaryValue* record = NULL;
    104     peer_connection_data_.GetDictionary(i, &record);
    105 
    106     int this_pid = 0, this_lid = 0;
    107     record->GetInteger("pid", &this_pid);
    108     record->GetInteger("lid", &this_lid);
    109 
    110     if (this_pid != static_cast<int>(pid) || this_lid != lid)
    111       continue;
    112 
    113     // Append the update to the end of the log.
    114     base::ListValue* log = EnsureLogList(record);
    115     if (!log)
    116       return;
    117 
    118     base::DictionaryValue* log_entry = new base::DictionaryValue();
    119     if (!log_entry)
    120       return;
    121 
    122     log_entry->SetString("type", type);
    123     log_entry->SetString("value", value);
    124     log->Append(log_entry);
    125 
    126     if (observers_.size() > 0) {
    127       base::DictionaryValue update;
    128       update.SetInteger("pid", static_cast<int>(pid));
    129       update.SetInteger("lid", lid);
    130       update.SetString("type", type);
    131       update.SetString("value", value);
    132 
    133       SendUpdate("updatePeerConnection", &update);
    134     }
    135     return;
    136   }
    137 }
    138 
    139 void WebRTCInternals::OnAddStats(base::ProcessId pid, int lid,
    140                                  const base::ListValue& value) {
    141   if (observers_.size() == 0)
    142     return;
    143 
    144   base::DictionaryValue dict;
    145   dict.SetInteger("pid", static_cast<int>(pid));
    146   dict.SetInteger("lid", lid);
    147 
    148   base::ListValue* list = value.DeepCopy();
    149   if (!list)
    150     return;
    151 
    152   dict.Set("reports", list);
    153 
    154   SendUpdate("addStats", &dict);
    155 }
    156 
    157 void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
    158   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    159   observers_.AddObserver(observer);
    160 }
    161 
    162 void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
    163   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    164   observers_.RemoveObserver(observer);
    165 }
    166 
    167 void WebRTCInternals::SendAllUpdates() {
    168   if (observers_.size() > 0)
    169     SendUpdate("updateAllPeerConnections", &peer_connection_data_);
    170 }
    171 
    172 void WebRTCInternals::StartRtpRecording() {
    173   if (!is_recording_rtp_) {
    174     is_recording_rtp_ = true;
    175     // TODO(justinlin): start RTP recording.
    176   }
    177 }
    178 
    179 void WebRTCInternals::StopRtpRecording() {
    180   if (is_recording_rtp_) {
    181     is_recording_rtp_ = false;
    182     // TODO(justinlin): stop RTP recording.
    183   }
    184 }
    185 
    186 void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
    187   DCHECK_GT(observers_.size(), (size_t)0);
    188 
    189   FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
    190                     observers_,
    191                     OnUpdate(command, value));
    192 }
    193 
    194 void WebRTCInternals::BrowserChildProcessCrashed(
    195     const ChildProcessData& data) {
    196   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    197   OnRendererExit(data.id);
    198 }
    199 
    200 void WebRTCInternals::Observe(int type,
    201                               const NotificationSource& source,
    202                               const NotificationDetails& details) {
    203   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    204   DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
    205   OnRendererExit(Source<RenderProcessHost>(source)->GetID());
    206 }
    207 
    208 void WebRTCInternals::OnRendererExit(int render_process_id) {
    209   // Iterates from the end of the list to remove the PeerConnections created
    210   // by the exitting renderer.
    211   for (int i = peer_connection_data_.GetSize() - 1; i >= 0; --i) {
    212     base::DictionaryValue* record = NULL;
    213     peer_connection_data_.GetDictionary(i, &record);
    214 
    215     int this_rid = 0;
    216     record->GetInteger("rid", &this_rid);
    217 
    218     if (this_rid == render_process_id) {
    219       if (observers_.size() > 0) {
    220         int lid = 0, pid = 0;
    221         record->GetInteger("lid", &lid);
    222         record->GetInteger("pid", &pid);
    223 
    224         base::DictionaryValue update;
    225         update.SetInteger("lid", lid);
    226         update.SetInteger("pid", pid);
    227         SendUpdate("removePeerConnection", &update);
    228       }
    229       peer_connection_data_.Remove(i, NULL);
    230     }
    231   }
    232 }
    233 
    234 // TODO(justlin): Calls this method as necessary to update the recording status
    235 // UI.
    236 void WebRTCInternals::SendRtpRecordingUpdate() {
    237   DCHECK(is_recording_rtp_);
    238   base::DictionaryValue update;
    239   // TODO(justinlin): Fill in |update| with values as appropriate.
    240   SendUpdate("updateDumpStatus", &update);
    241 }
    242 
    243 }  // namespace content
    244