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