Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #ifndef TALK_APP_WEBRTC_WEBRTCSESSION_H_
     29 #define TALK_APP_WEBRTC_WEBRTCSESSION_H_
     30 
     31 #include <string>
     32 #include <vector>
     33 
     34 #include "talk/app/webrtc/datachannel.h"
     35 #include "talk/app/webrtc/dtmfsender.h"
     36 #include "talk/app/webrtc/mediacontroller.h"
     37 #include "talk/app/webrtc/mediastreamprovider.h"
     38 #include "talk/app/webrtc/peerconnectioninterface.h"
     39 #include "talk/app/webrtc/statstypes.h"
     40 #include "talk/media/base/mediachannel.h"
     41 #include "talk/session/media/mediasession.h"
     42 #include "webrtc/base/sigslot.h"
     43 #include "webrtc/base/sslidentity.h"
     44 #include "webrtc/base/thread.h"
     45 #include "webrtc/p2p/base/transportcontroller.h"
     46 
     47 namespace cricket {
     48 
     49 class ChannelManager;
     50 class DataChannel;
     51 class StatsReport;
     52 class VideoCapturer;
     53 class VideoChannel;
     54 class VoiceChannel;
     55 
     56 }  // namespace cricket
     57 
     58 namespace webrtc {
     59 
     60 class IceRestartAnswerLatch;
     61 class JsepIceCandidate;
     62 class MediaStreamSignaling;
     63 class WebRtcSessionDescriptionFactory;
     64 
     65 extern const char kBundleWithoutRtcpMux[];
     66 extern const char kCreateChannelFailed[];
     67 extern const char kInvalidCandidates[];
     68 extern const char kInvalidSdp[];
     69 extern const char kMlineMismatch[];
     70 extern const char kPushDownTDFailed[];
     71 extern const char kSdpWithoutDtlsFingerprint[];
     72 extern const char kSdpWithoutSdesCrypto[];
     73 extern const char kSdpWithoutIceUfragPwd[];
     74 extern const char kSdpWithoutSdesAndDtlsDisabled[];
     75 extern const char kSessionError[];
     76 extern const char kSessionErrorDesc[];
     77 extern const char kDtlsSetupFailureRtp[];
     78 extern const char kDtlsSetupFailureRtcp[];
     79 extern const char kEnableBundleFailed[];
     80 
     81 // Maximum number of received video streams that will be processed by webrtc
     82 // even if they are not signalled beforehand.
     83 extern const int kMaxUnsignalledRecvStreams;
     84 
     85 // ICE state callback interface.
     86 class IceObserver {
     87  public:
     88   IceObserver() {}
     89   // Called any time the IceConnectionState changes
     90   // TODO(honghaiz): Change the name to OnIceConnectionStateChange so as to
     91   // conform to the w3c standard.
     92   virtual void OnIceConnectionChange(
     93       PeerConnectionInterface::IceConnectionState new_state) {}
     94   // Called any time the IceGatheringState changes
     95   virtual void OnIceGatheringChange(
     96       PeerConnectionInterface::IceGatheringState new_state) {}
     97   // New Ice candidate have been found.
     98   virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0;
     99   // All Ice candidates have been found.
    100   // TODO(bemasc): Remove this once callers transition to OnIceGatheringChange.
    101   // (via PeerConnectionObserver)
    102   virtual void OnIceComplete() {}
    103 
    104   // Called whenever the state changes between receiving and not receiving.
    105   virtual void OnIceConnectionReceivingChange(bool receiving) {}
    106 
    107  protected:
    108   ~IceObserver() {}
    109 
    110  private:
    111   RTC_DISALLOW_COPY_AND_ASSIGN(IceObserver);
    112 };
    113 
    114 // Statistics for all the transports of the session.
    115 typedef std::map<std::string, cricket::TransportStats> TransportStatsMap;
    116 typedef std::map<std::string, std::string> ProxyTransportMap;
    117 
    118 // TODO(pthatcher): Think of a better name for this.  We already have
    119 // a TransportStats in transport.h.  Perhaps TransportsStats?
    120 struct SessionStats {
    121   ProxyTransportMap proxy_to_transport;
    122   TransportStatsMap transport_stats;
    123 };
    124 
    125 // A WebRtcSession manages general session state. This includes negotiation
    126 // of both the application-level and network-level protocols:  the former
    127 // defines what will be sent and the latter defines how it will be sent.  Each
    128 // network-level protocol is represented by a Transport object.  Each Transport
    129 // participates in the network-level negotiation.  The individual streams of
    130 // packets are represented by TransportChannels.  The application-level protocol
    131 // is represented by SessionDecription objects.
    132 class WebRtcSession : public AudioProviderInterface,
    133                       public VideoProviderInterface,
    134                       public DtmfProviderInterface,
    135                       public DataChannelProviderInterface,
    136                       public sigslot::has_slots<> {
    137  public:
    138   enum State {
    139     STATE_INIT = 0,
    140     STATE_SENTOFFER,         // Sent offer, waiting for answer.
    141     STATE_RECEIVEDOFFER,     // Received an offer. Need to send answer.
    142     STATE_SENTPRANSWER,      // Sent provisional answer. Need to send answer.
    143     STATE_RECEIVEDPRANSWER,  // Received provisional answer, waiting for answer.
    144     STATE_INPROGRESS,        // Offer/answer exchange completed.
    145     STATE_CLOSED,            // Close() was called.
    146   };
    147 
    148   enum Error {
    149     ERROR_NONE = 0,       // no error
    150     ERROR_CONTENT = 1,    // channel errors in SetLocalContent/SetRemoteContent
    151     ERROR_TRANSPORT = 2,  // transport error of some kind
    152   };
    153 
    154   WebRtcSession(webrtc::MediaControllerInterface* media_controller,
    155                 rtc::Thread* signaling_thread,
    156                 rtc::Thread* worker_thread,
    157                 cricket::PortAllocator* port_allocator);
    158   virtual ~WebRtcSession();
    159 
    160   // These are const to allow them to be called from const methods.
    161   rtc::Thread* signaling_thread() const { return signaling_thread_; }
    162   rtc::Thread* worker_thread() const { return worker_thread_; }
    163   cricket::PortAllocator* port_allocator() const { return port_allocator_; }
    164 
    165   // The ID of this session.
    166   const std::string& id() const { return sid_; }
    167 
    168   bool Initialize(
    169       const PeerConnectionFactoryInterface::Options& options,
    170       const MediaConstraintsInterface* constraints,
    171       rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
    172       const PeerConnectionInterface::RTCConfiguration& rtc_configuration);
    173   // Deletes the voice, video and data channel and changes the session state
    174   // to STATE_CLOSED.
    175   void Close();
    176 
    177   // Returns true if we were the initial offerer.
    178   bool initial_offerer() const { return initial_offerer_; }
    179 
    180   // Returns the current state of the session. See the enum above for details.
    181   // Each time the state changes, we will fire this signal.
    182   State state() const { return state_; }
    183   sigslot::signal2<WebRtcSession*, State> SignalState;
    184 
    185   // Returns the last error in the session. See the enum above for details.
    186   Error error() const { return error_; }
    187   const std::string& error_desc() const { return error_desc_; }
    188 
    189   void RegisterIceObserver(IceObserver* observer) {
    190     ice_observer_ = observer;
    191   }
    192 
    193   virtual cricket::VoiceChannel* voice_channel() {
    194     return voice_channel_.get();
    195   }
    196   virtual cricket::VideoChannel* video_channel() {
    197     return video_channel_.get();
    198   }
    199   virtual cricket::DataChannel* data_channel() {
    200     return data_channel_.get();
    201   }
    202 
    203   void SetSdesPolicy(cricket::SecurePolicy secure_policy);
    204   cricket::SecurePolicy SdesPolicy() const;
    205 
    206   // Get current ssl role from transport.
    207   bool GetSslRole(const std::string& transport_name, rtc::SSLRole* role);
    208 
    209   // Get current SSL role for this channel's transport.
    210   // If |transport| is null, returns false.
    211   bool GetSslRole(const cricket::BaseChannel* channel, rtc::SSLRole* role);
    212 
    213   void CreateOffer(
    214       CreateSessionDescriptionObserver* observer,
    215       const PeerConnectionInterface::RTCOfferAnswerOptions& options,
    216       const cricket::MediaSessionOptions& session_options);
    217   void CreateAnswer(CreateSessionDescriptionObserver* observer,
    218                     const MediaConstraintsInterface* constraints,
    219                     const cricket::MediaSessionOptions& session_options);
    220   // The ownership of |desc| will be transferred after this call.
    221   bool SetLocalDescription(SessionDescriptionInterface* desc,
    222                            std::string* err_desc);
    223   // The ownership of |desc| will be transferred after this call.
    224   bool SetRemoteDescription(SessionDescriptionInterface* desc,
    225                             std::string* err_desc);
    226   bool ProcessIceMessage(const IceCandidateInterface* ice_candidate);
    227 
    228   bool SetIceTransports(PeerConnectionInterface::IceTransportsType type);
    229 
    230   cricket::IceConfig ParseIceConfig(
    231       const PeerConnectionInterface::RTCConfiguration& config) const;
    232 
    233   void SetIceConfig(const cricket::IceConfig& ice_config);
    234 
    235   // Start gathering candidates for any new transports, or transports doing an
    236   // ICE restart.
    237   void MaybeStartGathering();
    238 
    239   const SessionDescriptionInterface* local_description() const {
    240     return local_desc_.get();
    241   }
    242   const SessionDescriptionInterface* remote_description() const {
    243     return remote_desc_.get();
    244   }
    245 
    246   // Get the id used as a media stream track's "id" field from ssrc.
    247   virtual bool GetLocalTrackIdBySsrc(uint32_t ssrc, std::string* track_id);
    248   virtual bool GetRemoteTrackIdBySsrc(uint32_t ssrc, std::string* track_id);
    249 
    250   // AudioMediaProviderInterface implementation.
    251   void SetAudioPlayout(uint32_t ssrc, bool enable) override;
    252   void SetAudioSend(uint32_t ssrc,
    253                     bool enable,
    254                     const cricket::AudioOptions& options,
    255                     cricket::AudioRenderer* renderer) override;
    256   void SetAudioPlayoutVolume(uint32_t ssrc, double volume) override;
    257   void SetRawAudioSink(uint32_t ssrc,
    258                        rtc::scoped_ptr<AudioSinkInterface> sink) override;
    259 
    260   // Implements VideoMediaProviderInterface.
    261   bool SetCaptureDevice(uint32_t ssrc, cricket::VideoCapturer* camera) override;
    262   void SetVideoPlayout(uint32_t ssrc,
    263                        bool enable,
    264                        cricket::VideoRenderer* renderer) override;
    265   void SetVideoSend(uint32_t ssrc,
    266                     bool enable,
    267                     const cricket::VideoOptions* options) override;
    268 
    269   // Implements DtmfProviderInterface.
    270   virtual bool CanInsertDtmf(const std::string& track_id);
    271   virtual bool InsertDtmf(const std::string& track_id,
    272                           int code, int duration);
    273   virtual sigslot::signal0<>* GetOnDestroyedSignal();
    274 
    275   // Implements DataChannelProviderInterface.
    276   bool SendData(const cricket::SendDataParams& params,
    277                 const rtc::Buffer& payload,
    278                 cricket::SendDataResult* result) override;
    279   bool ConnectDataChannel(DataChannel* webrtc_data_channel) override;
    280   void DisconnectDataChannel(DataChannel* webrtc_data_channel) override;
    281   void AddSctpDataStream(int sid) override;
    282   void RemoveSctpDataStream(int sid) override;
    283   bool ReadyToSendData() const override;
    284 
    285   // Returns stats for all channels of all transports.
    286   // This avoids exposing the internal structures used to track them.
    287   virtual bool GetTransportStats(SessionStats* stats);
    288 
    289   // Get stats for a specific channel
    290   bool GetChannelTransportStats(cricket::BaseChannel* ch, SessionStats* stats);
    291 
    292   // virtual so it can be mocked in unit tests
    293   virtual bool GetLocalCertificate(
    294       const std::string& transport_name,
    295       rtc::scoped_refptr<rtc::RTCCertificate>* certificate);
    296 
    297   // Caller owns returned certificate
    298   virtual bool GetRemoteSSLCertificate(const std::string& transport_name,
    299                                        rtc::SSLCertificate** cert);
    300 
    301   cricket::DataChannelType data_channel_type() const;
    302 
    303   bool IceRestartPending() const;
    304 
    305   void ResetIceRestartLatch();
    306 
    307   // Called when an RTCCertificate is generated or retrieved by
    308   // WebRTCSessionDescriptionFactory. Should happen before setLocalDescription.
    309   void OnCertificateReady(
    310       const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
    311   void OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp);
    312 
    313   // For unit test.
    314   bool waiting_for_certificate_for_testing() const;
    315   const rtc::scoped_refptr<rtc::RTCCertificate>& certificate_for_testing();
    316 
    317   void set_metrics_observer(
    318       webrtc::MetricsObserverInterface* metrics_observer) {
    319     metrics_observer_ = metrics_observer;
    320   }
    321 
    322   // Called when voice_channel_, video_channel_ and data_channel_ are created
    323   // and destroyed. As a result of, for example, setting a new description.
    324   sigslot::signal0<> SignalVoiceChannelCreated;
    325   sigslot::signal0<> SignalVoiceChannelDestroyed;
    326   sigslot::signal0<> SignalVideoChannelCreated;
    327   sigslot::signal0<> SignalVideoChannelDestroyed;
    328   sigslot::signal0<> SignalDataChannelCreated;
    329   sigslot::signal0<> SignalDataChannelDestroyed;
    330 
    331   // Called when a valid data channel OPEN message is received.
    332   // std::string represents the data channel label.
    333   sigslot::signal2<const std::string&, const InternalDataChannelInit&>
    334       SignalDataChannelOpenMessage;
    335 
    336  private:
    337   // Indicates the type of SessionDescription in a call to SetLocalDescription
    338   // and SetRemoteDescription.
    339   enum Action {
    340     kOffer,
    341     kPrAnswer,
    342     kAnswer,
    343   };
    344 
    345   // Log session state.
    346   void LogState(State old_state, State new_state);
    347 
    348   // Updates the state, signaling if necessary.
    349   virtual void SetState(State state);
    350 
    351   // Updates the error state, signaling if necessary.
    352   // TODO(ronghuawu): remove the SetError method that doesn't take |error_desc|.
    353   virtual void SetError(Error error, const std::string& error_desc);
    354 
    355   bool UpdateSessionState(Action action, cricket::ContentSource source,
    356                           std::string* err_desc);
    357   static Action GetAction(const std::string& type);
    358   // Push the media parts of the local or remote session description
    359   // down to all of the channels.
    360   bool PushdownMediaDescription(cricket::ContentAction action,
    361                                 cricket::ContentSource source,
    362                                 std::string* error_desc);
    363 
    364   bool PushdownTransportDescription(cricket::ContentSource source,
    365                                     cricket::ContentAction action,
    366                                     std::string* error_desc);
    367 
    368   // Helper methods to push local and remote transport descriptions.
    369   bool PushdownLocalTransportDescription(
    370       const cricket::SessionDescription* sdesc,
    371       cricket::ContentAction action,
    372       std::string* error_desc);
    373   bool PushdownRemoteTransportDescription(
    374       const cricket::SessionDescription* sdesc,
    375       cricket::ContentAction action,
    376       std::string* error_desc);
    377 
    378   // Returns true and the TransportInfo of the given |content_name|
    379   // from |description|. Returns false if it's not available.
    380   static bool GetTransportDescription(
    381       const cricket::SessionDescription* description,
    382       const std::string& content_name,
    383       cricket::TransportDescription* info);
    384 
    385   cricket::BaseChannel* GetChannel(const std::string& content_name);
    386   // Cause all the BaseChannels in the bundle group to have the same
    387   // transport channel.
    388   bool EnableBundle(const cricket::ContentGroup& bundle);
    389 
    390   // Enables media channels to allow sending of media.
    391   void EnableChannels();
    392   // Returns the media index for a local ice candidate given the content name.
    393   // Returns false if the local session description does not have a media
    394   // content called  |content_name|.
    395   bool GetLocalCandidateMediaIndex(const std::string& content_name,
    396                                    int* sdp_mline_index);
    397   // Uses all remote candidates in |remote_desc| in this session.
    398   bool UseCandidatesInSessionDescription(
    399       const SessionDescriptionInterface* remote_desc);
    400   // Uses |candidate| in this session.
    401   bool UseCandidate(const IceCandidateInterface* candidate);
    402   // Deletes the corresponding channel of contents that don't exist in |desc|.
    403   // |desc| can be null. This means that all channels are deleted.
    404   void RemoveUnusedChannels(const cricket::SessionDescription* desc);
    405 
    406   // Allocates media channels based on the |desc|. If |desc| doesn't have
    407   // the BUNDLE option, this method will disable BUNDLE in PortAllocator.
    408   // This method will also delete any existing media channels before creating.
    409   bool CreateChannels(const cricket::SessionDescription* desc);
    410 
    411   // Helper methods to create media channels.
    412   bool CreateVoiceChannel(const cricket::ContentInfo* content);
    413   bool CreateVideoChannel(const cricket::ContentInfo* content);
    414   bool CreateDataChannel(const cricket::ContentInfo* content);
    415 
    416   // Listens to SCTP CONTROL messages on unused SIDs and process them as OPEN
    417   // messages.
    418   void OnDataChannelMessageReceived(cricket::DataChannel* channel,
    419                                     const cricket::ReceiveDataParams& params,
    420                                     const rtc::Buffer& payload);
    421 
    422   std::string BadStateErrMsg(State state);
    423   void SetIceConnectionState(PeerConnectionInterface::IceConnectionState state);
    424   void SetIceConnectionReceiving(bool receiving);
    425 
    426   bool ValidateBundleSettings(const cricket::SessionDescription* desc);
    427   bool HasRtcpMuxEnabled(const cricket::ContentInfo* content);
    428   // Below methods are helper methods which verifies SDP.
    429   bool ValidateSessionDescription(const SessionDescriptionInterface* sdesc,
    430                                   cricket::ContentSource source,
    431                                   std::string* err_desc);
    432 
    433   // Check if a call to SetLocalDescription is acceptable with |action|.
    434   bool ExpectSetLocalDescription(Action action);
    435   // Check if a call to SetRemoteDescription is acceptable with |action|.
    436   bool ExpectSetRemoteDescription(Action action);
    437   // Verifies a=setup attribute as per RFC 5763.
    438   bool ValidateDtlsSetupAttribute(const cricket::SessionDescription* desc,
    439                                   Action action);
    440 
    441   // Returns true if we are ready to push down the remote candidate.
    442   // |remote_desc| is the new remote description, or NULL if the current remote
    443   // description should be used. Output |valid| is true if the candidate media
    444   // index is valid.
    445   bool ReadyToUseRemoteCandidate(const IceCandidateInterface* candidate,
    446                                  const SessionDescriptionInterface* remote_desc,
    447                                  bool* valid);
    448 
    449   void OnTransportControllerConnectionState(cricket::IceConnectionState state);
    450   void OnTransportControllerReceiving(bool receiving);
    451   void OnTransportControllerGatheringState(cricket::IceGatheringState state);
    452   void OnTransportControllerCandidatesGathered(
    453       const std::string& transport_name,
    454       const cricket::Candidates& candidates);
    455 
    456   std::string GetSessionErrorMsg();
    457 
    458   // Invoked when TransportController connection completion is signaled.
    459   // Reports stats for all transports in use.
    460   void ReportTransportStats();
    461 
    462   // Gather the usage of IPv4/IPv6 as best connection.
    463   void ReportBestConnectionState(const cricket::TransportStats& stats);
    464 
    465   void ReportNegotiatedCiphers(const cricket::TransportStats& stats);
    466 
    467   void OnSentPacket_w(cricket::TransportChannel* channel,
    468                       const rtc::SentPacket& sent_packet);
    469 
    470   rtc::Thread* const signaling_thread_;
    471   rtc::Thread* const worker_thread_;
    472   cricket::PortAllocator* const port_allocator_;
    473 
    474   State state_ = STATE_INIT;
    475   Error error_ = ERROR_NONE;
    476   std::string error_desc_;
    477 
    478   const std::string sid_;
    479   bool initial_offerer_ = false;
    480 
    481   rtc::scoped_ptr<cricket::TransportController> transport_controller_;
    482   MediaControllerInterface* media_controller_;
    483   rtc::scoped_ptr<cricket::VoiceChannel> voice_channel_;
    484   rtc::scoped_ptr<cricket::VideoChannel> video_channel_;
    485   rtc::scoped_ptr<cricket::DataChannel> data_channel_;
    486   cricket::ChannelManager* channel_manager_;
    487   IceObserver* ice_observer_;
    488   PeerConnectionInterface::IceConnectionState ice_connection_state_;
    489   bool ice_connection_receiving_;
    490   rtc::scoped_ptr<SessionDescriptionInterface> local_desc_;
    491   rtc::scoped_ptr<SessionDescriptionInterface> remote_desc_;
    492   // If the remote peer is using a older version of implementation.
    493   bool older_version_remote_peer_;
    494   bool dtls_enabled_;
    495   // Specifies which kind of data channel is allowed. This is controlled
    496   // by the chrome command-line flag and constraints:
    497   // 1. If chrome command-line switch 'enable-sctp-data-channels' is enabled,
    498   // constraint kEnableDtlsSrtp is true, and constaint kEnableRtpDataChannels is
    499   // not set or false, SCTP is allowed (DCT_SCTP);
    500   // 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP);
    501   // 3. If both 1&2 are false, data channel is not allowed (DCT_NONE).
    502   cricket::DataChannelType data_channel_type_;
    503   rtc::scoped_ptr<IceRestartAnswerLatch> ice_restart_latch_;
    504 
    505   rtc::scoped_ptr<WebRtcSessionDescriptionFactory>
    506       webrtc_session_desc_factory_;
    507 
    508   // Member variables for caching global options.
    509   cricket::AudioOptions audio_options_;
    510   cricket::VideoOptions video_options_;
    511   MetricsObserverInterface* metrics_observer_;
    512 
    513   // Declares the bundle policy for the WebRTCSession.
    514   PeerConnectionInterface::BundlePolicy bundle_policy_;
    515 
    516   // Declares the RTCP mux policy for the WebRTCSession.
    517   PeerConnectionInterface::RtcpMuxPolicy rtcp_mux_policy_;
    518 
    519   RTC_DISALLOW_COPY_AND_ASSIGN(WebRtcSession);
    520 };
    521 }  // namespace webrtc
    522 
    523 #endif  // TALK_APP_WEBRTC_WEBRTCSESSION_H_
    524