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 #include "content/renderer/media/peer_connection_tracker.h"
      5 
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "content/common/media/peer_connection_tracker_messages.h"
      8 #include "content/renderer/media/rtc_media_constraints.h"
      9 #include "content/renderer/media/rtc_peer_connection_handler.h"
     10 #include "content/renderer/render_thread_impl.h"
     11 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
     12 #include "third_party/WebKit/public/platform/WebMediaStream.h"
     13 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
     14 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
     15 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h"
     16 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
     17 #include "third_party/WebKit/public/web/WebDocument.h"
     18 #include "third_party/WebKit/public/web/WebFrame.h"
     19 #include "third_party/WebKit/public/web/WebUserMediaRequest.h"
     20 
     21 using std::string;
     22 using webrtc::MediaConstraintsInterface;
     23 using blink::WebRTCPeerConnectionHandlerClient;
     24 
     25 namespace content {
     26 
     27 static string SerializeServers(
     28     const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers) {
     29   string result = "[";
     30   for (size_t i = 0; i < servers.size(); ++i) {
     31     result += servers[i].uri;
     32     if (i != servers.size() - 1)
     33       result += ", ";
     34   }
     35   result += "]";
     36   return result;
     37 }
     38 
     39 static string SerializeMediaConstraints(
     40     const RTCMediaConstraints& constraints) {
     41   string result;
     42   MediaConstraintsInterface::Constraints mandatory = constraints.GetMandatory();
     43   if (!mandatory.empty()) {
     44     result += "mandatory: {";
     45     for (size_t i = 0; i < mandatory.size(); ++i) {
     46       result += mandatory[i].key + ":" + mandatory[i].value;
     47       if (i != mandatory.size() - 1)
     48         result += ", ";
     49     }
     50     result += "}";
     51   }
     52   MediaConstraintsInterface::Constraints optional = constraints.GetOptional();
     53   if (!optional.empty()) {
     54     if (!result.empty())
     55       result += ", ";
     56     result += "optional: {";
     57     for (size_t i = 0; i < optional.size(); ++i) {
     58       result += optional[i].key + ":" + optional[i].value;
     59       if (i != optional.size() - 1)
     60         result += ", ";
     61     }
     62     result += "}";
     63   }
     64   return result;
     65 }
     66 
     67 static string SerializeMediaStreamComponent(
     68     const blink::WebMediaStreamTrack component) {
     69   string id = base::UTF16ToUTF8(component.source().id());
     70   return id;
     71 }
     72 
     73 static string SerializeMediaDescriptor(
     74     const blink::WebMediaStream& stream) {
     75   string label = base::UTF16ToUTF8(stream.id());
     76   string result = "label: " + label;
     77   blink::WebVector<blink::WebMediaStreamTrack> tracks;
     78   stream.audioTracks(tracks);
     79   if (!tracks.isEmpty()) {
     80     result += ", audio: [";
     81     for (size_t i = 0; i < tracks.size(); ++i) {
     82       result += SerializeMediaStreamComponent(tracks[i]);
     83       if (i != tracks.size() - 1)
     84         result += ", ";
     85     }
     86     result += "]";
     87   }
     88   stream.videoTracks(tracks);
     89   if (!tracks.isEmpty()) {
     90     result += ", video: [";
     91     for (size_t i = 0; i < tracks.size(); ++i) {
     92       result += SerializeMediaStreamComponent(tracks[i]);
     93       if (i != tracks.size() - 1)
     94         result += ", ";
     95     }
     96     result += "]";
     97   }
     98   return result;
     99 }
    100 
    101 #define GET_STRING_OF_STATE(state)                \
    102   case WebRTCPeerConnectionHandlerClient::state:  \
    103     result = #state;                              \
    104     break;
    105 
    106 static string GetSignalingStateString(
    107     WebRTCPeerConnectionHandlerClient::SignalingState state) {
    108   string result;
    109   switch (state) {
    110     GET_STRING_OF_STATE(SignalingStateStable)
    111     GET_STRING_OF_STATE(SignalingStateHaveLocalOffer)
    112     GET_STRING_OF_STATE(SignalingStateHaveRemoteOffer)
    113     GET_STRING_OF_STATE(SignalingStateHaveLocalPrAnswer)
    114     GET_STRING_OF_STATE(SignalingStateHaveRemotePrAnswer)
    115     GET_STRING_OF_STATE(SignalingStateClosed)
    116     default:
    117       NOTREACHED();
    118       break;
    119   }
    120   return result;
    121 }
    122 
    123 static string GetIceConnectionStateString(
    124     WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
    125   string result;
    126   switch (state) {
    127     GET_STRING_OF_STATE(ICEConnectionStateStarting)
    128     GET_STRING_OF_STATE(ICEConnectionStateChecking)
    129     GET_STRING_OF_STATE(ICEConnectionStateConnected)
    130     GET_STRING_OF_STATE(ICEConnectionStateCompleted)
    131     GET_STRING_OF_STATE(ICEConnectionStateFailed)
    132     GET_STRING_OF_STATE(ICEConnectionStateDisconnected)
    133     GET_STRING_OF_STATE(ICEConnectionStateClosed)
    134     default:
    135       NOTREACHED();
    136       break;
    137   }
    138   return result;
    139 }
    140 
    141 static string GetIceGatheringStateString(
    142     WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
    143   string result;
    144   switch (state) {
    145     GET_STRING_OF_STATE(ICEGatheringStateNew)
    146     GET_STRING_OF_STATE(ICEGatheringStateGathering)
    147     GET_STRING_OF_STATE(ICEGatheringStateComplete)
    148     default:
    149       NOTREACHED();
    150       break;
    151   }
    152   return result;
    153 }
    154 
    155 // Builds a DictionaryValue from the StatsReport.
    156 // The caller takes the ownership of the returned value.
    157 // Note:
    158 // The format must be consistent with what webrtc_internals.js expects.
    159 // If you change it here, you must change webrtc_internals.js as well.
    160 static base::DictionaryValue* GetDictValueStats(
    161     const webrtc::StatsReport& report) {
    162   if (report.values.empty())
    163     return NULL;
    164 
    165   base::DictionaryValue* dict = new base::DictionaryValue();
    166   dict->SetDouble("timestamp", report.timestamp);
    167 
    168   base::ListValue* values = new base::ListValue();
    169   dict->Set("values", values);
    170 
    171   for (size_t i = 0; i < report.values.size(); ++i) {
    172     values->AppendString(report.values[i].name);
    173     values->AppendString(report.values[i].value);
    174   }
    175   return dict;
    176 }
    177 
    178 // Builds a DictionaryValue from the StatsReport.
    179 // The caller takes the ownership of the returned value.
    180 static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) {
    181   scoped_ptr<base::DictionaryValue> stats, result;
    182 
    183   stats.reset(GetDictValueStats(report));
    184   if (!stats)
    185     return NULL;
    186 
    187   result.reset(new base::DictionaryValue());
    188   // Note:
    189   // The format must be consistent with what webrtc_internals.js expects.
    190   // If you change it here, you must change webrtc_internals.js as well.
    191   result->Set("stats", stats.release());
    192   result->SetString("id", report.id);
    193   result->SetString("type", report.type);
    194 
    195   return result.release();
    196 }
    197 
    198 class InternalStatsObserver : public webrtc::StatsObserver {
    199  public:
    200   InternalStatsObserver(int lid)
    201       : lid_(lid){}
    202 
    203   virtual void OnComplete(
    204       const std::vector<webrtc::StatsReport>& reports) OVERRIDE {
    205     base::ListValue list;
    206 
    207     for (size_t i = 0; i < reports.size(); ++i) {
    208       base::DictionaryValue* report = GetDictValue(reports[i]);
    209       if (report)
    210         list.Append(report);
    211     }
    212 
    213     if (!list.empty())
    214       RenderThreadImpl::current()->Send(
    215           new PeerConnectionTrackerHost_AddStats(lid_, list));
    216   }
    217 
    218  protected:
    219   virtual ~InternalStatsObserver() {}
    220 
    221  private:
    222   int lid_;
    223 };
    224 
    225 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
    226 }
    227 
    228 PeerConnectionTracker::~PeerConnectionTracker() {
    229 }
    230 
    231 bool PeerConnectionTracker::OnControlMessageReceived(
    232     const IPC::Message& message) {
    233   bool handled = true;
    234   IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message)
    235     IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats)
    236     IPC_MESSAGE_UNHANDLED(handled = false)
    237   IPC_END_MESSAGE_MAP()
    238   return handled;
    239 }
    240 
    241 void PeerConnectionTracker::OnGetAllStats() {
    242   for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin();
    243        it != peer_connection_id_map_.end(); ++it) {
    244 
    245     talk_base::scoped_refptr<InternalStatsObserver> observer(
    246         new talk_base::RefCountedObject<InternalStatsObserver>(it->second));
    247 
    248     it->first->GetStats(
    249         observer,
    250         NULL,
    251         webrtc::PeerConnectionInterface::kStatsOutputLevelDebug);
    252   }
    253 }
    254 
    255 void PeerConnectionTracker::RegisterPeerConnection(
    256     RTCPeerConnectionHandler* pc_handler,
    257     const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers,
    258     const RTCMediaConstraints& constraints,
    259     const blink::WebFrame* frame) {
    260   DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()";
    261   PeerConnectionInfo info;
    262 
    263   info.lid = GetNextLocalID();
    264   info.servers = SerializeServers(servers);
    265   info.constraints = SerializeMediaConstraints(constraints);
    266   info.url = frame->document().url().spec();
    267   RenderThreadImpl::current()->Send(
    268       new PeerConnectionTrackerHost_AddPeerConnection(info));
    269 
    270   DCHECK(peer_connection_id_map_.find(pc_handler) ==
    271          peer_connection_id_map_.end());
    272   peer_connection_id_map_[pc_handler] = info.lid;
    273 }
    274 
    275 void PeerConnectionTracker::UnregisterPeerConnection(
    276     RTCPeerConnectionHandler* pc_handler) {
    277   DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()";
    278 
    279   std::map<RTCPeerConnectionHandler*, int>::iterator it =
    280       peer_connection_id_map_.find(pc_handler);
    281 
    282   if (it == peer_connection_id_map_.end()) {
    283     // The PeerConnection might not have been registered if its initilization
    284     // failed.
    285     return;
    286   }
    287 
    288   RenderThreadImpl::current()->Send(
    289       new PeerConnectionTrackerHost_RemovePeerConnection(it->second));
    290 
    291   peer_connection_id_map_.erase(it);
    292 }
    293 
    294 void PeerConnectionTracker::TrackCreateOffer(
    295     RTCPeerConnectionHandler* pc_handler,
    296     const RTCMediaConstraints& constraints) {
    297   SendPeerConnectionUpdate(
    298       pc_handler, "createOffer",
    299       "constraints: {" + SerializeMediaConstraints(constraints) + "}");
    300 }
    301 
    302 void PeerConnectionTracker::TrackCreateAnswer(
    303     RTCPeerConnectionHandler* pc_handler,
    304     const RTCMediaConstraints& constraints) {
    305   SendPeerConnectionUpdate(
    306       pc_handler, "createAnswer",
    307       "constraints: {" + SerializeMediaConstraints(constraints) + "}");
    308 }
    309 
    310 void PeerConnectionTracker::TrackSetSessionDescription(
    311     RTCPeerConnectionHandler* pc_handler,
    312     const blink::WebRTCSessionDescription& desc,
    313     Source source) {
    314   string sdp = base::UTF16ToUTF8(desc.sdp());
    315   string type = base::UTF16ToUTF8(desc.type());
    316 
    317   string value = "type: " + type + ", sdp: " + sdp;
    318   SendPeerConnectionUpdate(
    319       pc_handler,
    320       source == SOURCE_LOCAL ? "setLocalDescription" : "setRemoteDescription",
    321       value);
    322 }
    323 
    324 void PeerConnectionTracker::TrackUpdateIce(
    325       RTCPeerConnectionHandler* pc_handler,
    326       const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers,
    327       const RTCMediaConstraints& options) {
    328   string servers_string = "servers: " + SerializeServers(servers);
    329   string constraints =
    330       "constraints: {" + SerializeMediaConstraints(options) + "}";
    331 
    332   SendPeerConnectionUpdate(
    333       pc_handler, "updateIce", servers_string + ", " + constraints);
    334 }
    335 
    336 void PeerConnectionTracker::TrackAddIceCandidate(
    337       RTCPeerConnectionHandler* pc_handler,
    338       const blink::WebRTCICECandidate& candidate,
    339       Source source) {
    340   string value = "mid: " + base::UTF16ToUTF8(candidate.sdpMid()) + ", " +
    341                  "candidate: " + base::UTF16ToUTF8(candidate.candidate());
    342   SendPeerConnectionUpdate(
    343       pc_handler,
    344       source == SOURCE_LOCAL ? "onIceCandidate" : "addIceCandidate", value);
    345 }
    346 
    347 void PeerConnectionTracker::TrackAddStream(
    348     RTCPeerConnectionHandler* pc_handler,
    349     const blink::WebMediaStream& stream,
    350     Source source){
    351   SendPeerConnectionUpdate(
    352       pc_handler, source == SOURCE_LOCAL ? "addStream" : "onAddStream",
    353       SerializeMediaDescriptor(stream));
    354 }
    355 
    356 void PeerConnectionTracker::TrackRemoveStream(
    357     RTCPeerConnectionHandler* pc_handler,
    358     const blink::WebMediaStream& stream,
    359     Source source){
    360   SendPeerConnectionUpdate(
    361       pc_handler, source == SOURCE_LOCAL ? "removeStream" : "onRemoveStream",
    362       SerializeMediaDescriptor(stream));
    363 }
    364 
    365 void PeerConnectionTracker::TrackCreateDataChannel(
    366     RTCPeerConnectionHandler* pc_handler,
    367     const webrtc::DataChannelInterface* data_channel,
    368     Source source) {
    369   string value = "label: " + data_channel->label() +
    370                  ", reliable: " + (data_channel->reliable() ? "true" : "false");
    371   SendPeerConnectionUpdate(
    372       pc_handler,
    373       source == SOURCE_LOCAL ? "createLocalDataChannel" : "onRemoteDataChannel",
    374       value);
    375 }
    376 
    377 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) {
    378   SendPeerConnectionUpdate(pc_handler, "stop", std::string());
    379 }
    380 
    381 void PeerConnectionTracker::TrackSignalingStateChange(
    382       RTCPeerConnectionHandler* pc_handler,
    383       WebRTCPeerConnectionHandlerClient::SignalingState state) {
    384   SendPeerConnectionUpdate(
    385       pc_handler, "signalingStateChange", GetSignalingStateString(state));
    386 }
    387 
    388 void PeerConnectionTracker::TrackIceConnectionStateChange(
    389       RTCPeerConnectionHandler* pc_handler,
    390       WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
    391   SendPeerConnectionUpdate(
    392       pc_handler, "iceConnectionStateChange",
    393       GetIceConnectionStateString(state));
    394 }
    395 
    396 void PeerConnectionTracker::TrackIceGatheringStateChange(
    397       RTCPeerConnectionHandler* pc_handler,
    398       WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
    399   SendPeerConnectionUpdate(
    400       pc_handler, "iceGatheringStateChange",
    401       GetIceGatheringStateString(state));
    402 }
    403 
    404 void PeerConnectionTracker::TrackSessionDescriptionCallback(
    405     RTCPeerConnectionHandler* pc_handler, Action action,
    406     const string& callback_type, const string& value) {
    407   string update_type;
    408   switch (action) {
    409     case ACTION_SET_LOCAL_DESCRIPTION:
    410       update_type = "setLocalDescription";
    411       break;
    412     case ACTION_SET_REMOTE_DESCRIPTION:
    413       update_type = "setRemoteDescription";
    414       break;
    415     case ACTION_CREATE_OFFER:
    416       update_type = "createOffer";
    417       break;
    418     case ACTION_CREATE_ANSWER:
    419       update_type = "createAnswer";
    420       break;
    421     default:
    422       NOTREACHED();
    423       break;
    424   }
    425   update_type += callback_type;
    426 
    427   SendPeerConnectionUpdate(pc_handler, update_type, value);
    428 }
    429 
    430 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
    431     RTCPeerConnectionHandler* pc_handler) {
    432   SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string());
    433 }
    434 
    435 void PeerConnectionTracker::TrackCreateDTMFSender(
    436     RTCPeerConnectionHandler* pc_handler,
    437     const blink::WebMediaStreamTrack& track) {
    438   SendPeerConnectionUpdate(pc_handler, "createDTMFSender",
    439                            base::UTF16ToUTF8(track.id()));
    440 }
    441 
    442 void PeerConnectionTracker::TrackGetUserMedia(
    443     const blink::WebUserMediaRequest& user_media_request) {
    444   RTCMediaConstraints audio_constraints(user_media_request.audioConstraints());
    445   RTCMediaConstraints video_constraints(user_media_request.videoConstraints());
    446 
    447   RenderThreadImpl::current()->Send(new PeerConnectionTrackerHost_GetUserMedia(
    448       user_media_request.securityOrigin().toString().utf8(),
    449       user_media_request.audio(),
    450       user_media_request.video(),
    451       SerializeMediaConstraints(audio_constraints),
    452       SerializeMediaConstraints(video_constraints)));
    453 }
    454 
    455 int PeerConnectionTracker::GetNextLocalID() {
    456   return next_lid_++;
    457 }
    458 
    459 void PeerConnectionTracker::SendPeerConnectionUpdate(
    460     RTCPeerConnectionHandler* pc_handler,
    461     const std::string& type,
    462     const std::string& value) {
    463   if (peer_connection_id_map_.find(pc_handler) == peer_connection_id_map_.end())
    464     return;
    465 
    466   RenderThreadImpl::current()->Send(
    467       new PeerConnectionTrackerHost_UpdatePeerConnection(
    468           peer_connection_id_map_[pc_handler], type, value));
    469 }
    470 
    471 }  // namespace content
    472