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