From 78083bf75013dafd1e2dc1e2daca3f00d88db279 Mon Sep 17 00:00:00 2001 From: "wu@webrtc.org" Date: Thu, 29 Sep 2011 19:11:52 +0000 Subject: [PATCH] * Add Serialize functions to PeerConnectionMessage. * Separated file for PeerConnectionMessage. * Update to the latest and fix compiling errors Review URL: http://webrtc-codereview.appspot.com/182002 git-svn-id: http://webrtc.googlecode.com/svn/trunk@668 4adac7df-926f-26a2-2b94-8c16560cd09d --- third_party_mods/libjingle/libjingle.gyp | 10 +- .../app/webrtc_dev/peerconnectionmessage.cc | 78 +++ .../app/webrtc_dev/peerconnectionmessage.h | 98 ++++ .../peerconnectionmessage_unittest.cc | 97 ++++ .../app/webrtc_dev/peerconnectionsignaling.cc | 29 - .../app/webrtc_dev/peerconnectionsignaling.h | 49 +- .../source/talk/app/webrtc_dev/webrtcjson.cc | 516 ++++++++++++++++++ .../source/talk/app/webrtc_dev/webrtcjson.h | 56 ++ .../talk/app/webrtc_dev/webrtcsession.cc | 3 +- .../talk/app/webrtc_dev/webrtcsession.h | 1 + 10 files changed, 856 insertions(+), 81 deletions(-) create mode 100644 third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.cc create mode 100644 third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.h create mode 100644 third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage_unittest.cc create mode 100644 third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.cc create mode 100644 third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.h diff --git a/third_party_mods/libjingle/libjingle.gyp b/third_party_mods/libjingle/libjingle.gyp index 574bb6ce7b..84750e2199 100644 --- a/third_party_mods/libjingle/libjingle.gyp +++ b/third_party_mods/libjingle/libjingle.gyp @@ -632,7 +632,6 @@ 'sources+': [ '<(libjingle_mods)/source/talk/session/phone/mediasession.cc', ] - }], # peer_connection_dev ], # conditions }, @@ -694,6 +693,8 @@ '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionimpl.h', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionmanagerimpl.cc', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionmanagerimpl.h', + '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionmessage.cc', + '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionmessage.h', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionsignaling.cc', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionsignaling.h', '<(libjingle_mods)/source/talk/app/webrtc_dev/ref_count.h', @@ -703,8 +704,10 @@ '<(libjingle_mods)/source/talk/app/webrtc_dev/videotrackimpl.h', '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtc_devicemanager.h', '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtc_devicemanager.cc', - '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcsession.h', + '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcjson.cc', + '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcjson.h', '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcsession.cc', + '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcsession.h', ], }], # peer_connection_dev ], # conditions @@ -763,8 +766,9 @@ '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnection_unittests.cc', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionimpl_unittest.cc', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionmanager_unittest.cc', + '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionmessage_unittest.cc', '<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnectionsignaling_unittest.cc', - '<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcsession_unittest.cc', + #'<(libjingle_mods)/source/talk/app/webrtc_dev/webrtcsession_unittest.cc', ], }, { # peer_connection_dev != 1 'type': 'none', diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.cc new file mode 100644 index 0000000000..f7680a7b20 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.cc @@ -0,0 +1,78 @@ +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/app/webrtc_dev/peerconnectionmessage.h" + +#include +#include + +#include "talk/app/webrtc_dev/webrtcjson.h" + +namespace webrtc { + +scoped_refptr PeerConnectionMessage::Create( + PeerConnectionMessageType type, + const cricket::SessionDescription* desc, + const std::vector& candidates) { + return new RefCountImpl (type, desc, candidates); +} + +scoped_refptr PeerConnectionMessage::Create( + std::string message) { + return new RefCountImpl (message); +} + +scoped_refptr PeerConnectionMessage::CreateErrorMessage( + ErrorCode error) { + return new RefCountImpl (error); +} + +PeerConnectionMessage::PeerConnectionMessage( + PeerConnectionMessageType type, + const cricket::SessionDescription* desc, + const std::vector& candidates) + : type_(type), + error_code_(kNoError), + desc_(desc), + candidates_(candidates) { +} + +PeerConnectionMessage::PeerConnectionMessage(std::string message) { + // TODO(ronghuawu): implement +} + +PeerConnectionMessage::PeerConnectionMessage(ErrorCode error) + : type_(kError), + desc_(NULL), + error_code_(error) { +} + +bool PeerConnectionMessage::Serialize(std::string* message) { + return JsonSerialize(desc_.get(), candidates_, message); +} + +} // namespace webrtc diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.h b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.h new file mode 100644 index 0000000000..a4872308fb --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage.h @@ -0,0 +1,98 @@ +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file contains classes used for handling signaling between +// two PeerConnections. + +#ifndef TALK_APP_WEBRTC_DEV_PEERCONNECTIONMESSAGE_H_ +#define TALK_APP_WEBRTC_DEV_PEERCONNECTIONMESSAGE_H_ + +#include +#include + +#include "talk/app/webrtc_dev/ref_count.h" +#include "talk/app/webrtc_dev/scoped_refptr.h" +#include "talk/base/basictypes.h" +#include "talk/base/scoped_ptr.h" +#include "talk/session/phone/mediasession.h" +#include "talk/p2p/base/sessiondescription.h" + +namespace webrtc { + +// PeerConnectionMessage represent an SDP offer or an answer. +// Instances of this class can be serialized / deserialized and are used for +// signaling between PeerConnection objects. +// Each instance has a type, a sequence number and a session description. +class PeerConnectionMessage : public RefCount { + public: + enum PeerConnectionMessageType { + kOffer, + kAnswer, + kError + }; + + enum ErrorCode { + kNoError = 0, + kWrongState = 10, // Offer received when Answer was expected. + kParseError = 20, // Can't parse / process offer. + kOfferNotAcceptable = 30, // The offer have been rejected. + kMessageNotDeliverable = 40 // The signaling channel is broken. + }; + + static scoped_refptr Create( + PeerConnectionMessageType type, + const cricket::SessionDescription* desc, + const std::vector& candidates); + + static scoped_refptr Create(std::string message); + + static scoped_refptr CreateErrorMessage( + ErrorCode error); + + PeerConnectionMessageType type() {return type_;} + ErrorCode error() {return error_code_;} + const cricket::SessionDescription* desc() {return desc_.get();} + + bool Serialize(std::string* message); + + protected: + PeerConnectionMessage(PeerConnectionMessageType type, + const cricket::SessionDescription* desc, + const std::vector& candidates); + explicit PeerConnectionMessage(std::string message); + explicit PeerConnectionMessage(ErrorCode error); + + private: + PeerConnectionMessageType type_; + ErrorCode error_code_; + talk_base::scoped_ptr desc_; + std::vector candidates_; +}; + +} // namespace webrtc + +#endif // TALK_APP_WEBRTC_DEV_PEERCONNECTIONMESSAGE_H_ diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage_unittest.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage_unittest.cc new file mode 100644 index 0000000000..a223a60d8a --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionmessage_unittest.cc @@ -0,0 +1,97 @@ +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "gtest/gtest.h" +#include "talk/app/webrtc_dev/peerconnectionmessage.h" +#include "talk/base/logging.h" +#include "talk/base/scoped_ptr.h" +#include "talk/session/phone/channelmanager.h" + +using webrtc::PeerConnectionMessage; + +static const char kStreamLabel1[] = "local_stream_1"; +static const char kAudioTrackLabel1[] = "local_audio_1"; +static const char kVideoTrackLabel1[] = "local_video_1"; +static const char kVideoTrackLabel2[] = "local_video_2"; + +static const char kStreamLabel2[] = "local_stream_2"; +static const char kAudioTrackLabel2[] = "local_audio_2"; +static const char kVideoTrackLabel3[] = "local_video_3"; + +class PeerConnectionMessageTest: public testing::Test { + public: + PeerConnectionMessageTest() + : ssrc_counter_(0) { + channel_manager_.reset(new cricket::ChannelManager( + talk_base::Thread::Current())); + EXPECT_TRUE(channel_manager_->Init()); + session_description_factory_.reset( + new cricket::MediaSessionDescriptionFactory(channel_manager_.get())); + options_.audio_sources.push_back(cricket::SourceParam(++ssrc_counter_, + kAudioTrackLabel1, kStreamLabel1)); + options_.video_sources.push_back(cricket::SourceParam(++ssrc_counter_, + kVideoTrackLabel1, kStreamLabel1)); + options_.video_sources.push_back(cricket::SourceParam(++ssrc_counter_, + kVideoTrackLabel2, kStreamLabel1)); + + // kStreamLabel2 with 1 audio track and 1 video track + options_.audio_sources.push_back(cricket::SourceParam(++ssrc_counter_, + kAudioTrackLabel2, kStreamLabel2)); + options_.video_sources.push_back(cricket::SourceParam(++ssrc_counter_, + kVideoTrackLabel3, kStreamLabel2)); + + options_.is_video = true; + } + + protected: + talk_base::scoped_ptr channel_manager_; + talk_base::scoped_ptr + session_description_factory_; + cricket::MediaSessionOptions options_; + + private: + int ssrc_counter_; +}; + +TEST_F(PeerConnectionMessageTest, Serialize) { + talk_base::scoped_ptr offer( + session_description_factory_->CreateOffer(options_)); + + std::vector candidates; + // TODO(ronghuawu): Populate the test candidates. + + std::string message; + scoped_refptr offer_message = + PeerConnectionMessage::Create(PeerConnectionMessage::kOffer, + offer.release(), + candidates); + EXPECT_TRUE(offer_message->Serialize(&message)); + LOG(LS_ERROR) << message; + // TODO(ronghuawu): Verify the serialized message. +} diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.cc index 87023e8f88..55cb5b5a44 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.cc +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.cc @@ -73,35 +73,6 @@ static bool VerifyAnswer(const cricket::SessionDescription* answer_desc) { return false; } - -scoped_refptr PeerConnectionMessage::Create( - PeerConnectionMessageType type, - const cricket::SessionDescription* desc, - const cricket::Candidates& candidates) { - return new RefCountImpl (type, desc, candidates); -} - -scoped_refptr PeerConnectionMessage::CreateErrorMessage( - ErrorCode error) { - return new RefCountImpl (error); -} - -PeerConnectionMessage::PeerConnectionMessage( - PeerConnectionMessageType type, - const cricket::SessionDescription* desc, - const cricket::Candidates& candidates) - : type_(type), - error_code_(kNoError), - desc_(desc), - candidates_(candidates) { -} - -PeerConnectionMessage::PeerConnectionMessage(ErrorCode error) - : type_(kError), - error_code_(error), - desc_(NULL) { -} - PeerConnectionSignaling::PeerConnectionSignaling( cricket::ChannelManager* channel_manager, talk_base::Thread* signaling_thread) diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.h b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.h index cbaa82fff7..23d07fa3b2 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.h +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnectionsignaling.h @@ -39,6 +39,7 @@ #include "talk/app/webrtc_dev/mediastreamimpl.h" #include "talk/app/webrtc_dev/peerconnection.h" +#include "talk/app/webrtc_dev/peerconnectionmessage.h" #include "talk/app/webrtc_dev/ref_count.h" #include "talk/app/webrtc_dev/scoped_refptr.h" #include "talk/base/basictypes.h" @@ -56,54 +57,6 @@ typedef std::vector Candidates; namespace webrtc { -// PeerConnectionMessage represent an SDP offer or an answer. -// Instances of this class can be serialized / deserialized and are used for -// signaling between PeerConnection objects. -// Each instance has a type, a sequence number and a session description. -class PeerConnectionMessage : public RefCount { - public: - enum PeerConnectionMessageType { - kOffer, - kAnswer, - kError - }; - - enum ErrorCode { - kNoError = 0, - kWrongState = 10, // Offer received when Answer was expected. - kParseError = 20, // Can't parse / process offer. - kOfferNotAcceptable = 30, // The offer have been rejected. - kMessageNotDeliverable = 40 // The signaling channel is broken. - }; - - static scoped_refptr Create( - PeerConnectionMessageType type, - const cricket::SessionDescription* desc, - const cricket::Candidates& candidates); - - static scoped_refptr CreateErrorMessage( - ErrorCode error); - - PeerConnectionMessageType type() {return type_;} - ErrorCode error() {return error_code_;} - const cricket::SessionDescription* desc() {return desc_.get();} - const cricket::Candidates& candidates() {return candidates_;} - - // TODO(perkj): Add functions for serializing and deserializing this class. - - protected: - PeerConnectionMessage(PeerConnectionMessageType type, - const cricket::SessionDescription* desc, - const cricket::Candidates& candidates); - explicit PeerConnectionMessage(ErrorCode error); - - private: - PeerConnectionMessageType type_; - ErrorCode error_code_; - talk_base::scoped_ptr desc_; - cricket::Candidates candidates_; -}; - // PeerConnectionSignaling is a class responsible for handling signaling // between PeerConnection objects. // It creates remote MediaStream objects when the remote peer signals it wants diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.cc new file mode 100644 index 0000000000..73984095b9 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.cc @@ -0,0 +1,516 @@ +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/app/webrtc_dev/webrtcjson.h" + +#include +#include + +#include "talk/base/json.h" +#include "talk/base/logging.h" +#include "talk/base/stringutils.h" +#include "talk/session/phone/codec.h" +#include "talk/session/phone/mediasessionclient.h" + +namespace webrtc { +static const int kIceComponent = 1; +static const int kIceFoundation = 1; + +static std::vector ReadValues(const Json::Value& value, + const std::string& key); + +static bool BuildContent( + const cricket::SessionDescription* sdp, + const cricket::ContentInfo& content_info, + const std::vector& candidates, + bool video, + Json::Value* content); + +static bool BuildCandidate(const std::vector& candidates, + bool video, + std::vector* jcandidates); + +static bool BuildRtpMapParams(const cricket::ContentInfo& audio_offer, + bool video, + std::vector* rtpmap); + +static bool BuildTrack(const cricket::SessionDescription* sdp, + bool video, + std::vector* track); + +static std::string Serialize(const Json::Value& value); + +static bool Deserialize(const std::string& message, Json::Value& value); + +static bool ParseRtcpMux(const Json::Value& value); +static bool ParseAudioCodec(const Json::Value& value, + cricket::AudioContentDescription* content); +static bool ParseVideoCodec(const Json::Value& value, + cricket::VideoContentDescription* content); +static bool ParseIceCandidates(const Json::Value& value, + std::vector* candidates); +static Json::Value ReadValue(const Json::Value& value, const std::string& key); +static std::string ReadString(const Json::Value& value, const std::string& key); +static double ReadDouble(const Json::Value& value, const std::string& key); +static uint32 ReadUInt(const Json::Value& value, const std::string& key); + +static void Append(Json::Value* object, const std::string& key, bool value); +static void Append(Json::Value* object, const std::string& key, + const char* value); +static void Append(Json::Value* object, const std::string& key, int value); +static void Append(Json::Value* object, const std::string& key, + const std::string& value); +static void Append(Json::Value* object, const std::string& key, uint32 value); +static void Append(Json::Value* object, const std::string& key, + const Json::Value& value); +static void Append(Json::Value* object, + const std::string& key, + const std::vector& values); + +bool JsonSerialize( + const cricket::SessionDescription* sdp, + const std::vector& candidates, + std::string* signaling_message) { + const cricket::ContentInfo* audio_content = GetFirstAudioContent(sdp); + const cricket::ContentInfo* video_content = GetFirstVideoContent(sdp); + + Json::Value media; + std::vector together; + together.push_back("audio"); + together.push_back("video"); + + std::vector contents; + + if (audio_content) { + Json::Value content; + BuildContent(sdp, *audio_content, candidates, false, &content); + contents.push_back(content); + } + + if (video_content) { + Json::Value content; + BuildContent(sdp, *video_content, candidates, true, &content); + contents.push_back(content); + } + + Append(&media, "content", contents); + Append(&media, "TOGETHER", together); + + // Now serialize. + *signaling_message = Serialize(media); + + return true; +} + +bool BuildContent( + const cricket::SessionDescription* sdp, + const cricket::ContentInfo& content_info, + const std::vector& candidates, + bool video, + Json::Value* content) { + std::string label("media"); + // TODO(ronghuawu): Use enum instead of bool video to prepare for other + // media types such as the data media stream. + if (video) { + Append(content, label, "video"); + } else { + Append(content, label, "audio"); + } + + const cricket::MediaContentDescription* media_info = + static_cast ( + content_info.description); + if (media_info->rtcp_mux()) { + Append(content, "rtcp_mux", true); + } + + // rtpmap + std::vector rtpmap; + BuildRtpMapParams(content_info, video, &rtpmap); + Append(content, "rtpmap", rtpmap); + + // crypto + Json::Value crypto; + // TODO(ronghuawu): BuildCrypto + Append(content, "crypto", crypto); + + // candidate + std::vector jcandidates; + BuildCandidate(candidates, video, &jcandidates); + Append(content, "candidate", jcandidates); + + // track + std::vector track; + BuildTrack(sdp, video, &track); + Append(content, "track", track); + + return true; +} + +bool BuildRtpMapParams(const cricket::ContentInfo& content_info, + bool video, + std::vector* rtpmap) { + if (!video) { + const cricket::AudioContentDescription* audio_offer = + static_cast( + content_info.description); + + std::vector::const_iterator iter = + audio_offer->codecs().begin(); + std::vector::const_iterator iter_end = + audio_offer->codecs().end(); + for (; iter != iter_end; ++iter) { + Json::Value codec; + std::string codec_str(std::string("audio/").append(iter->name)); + // adding clockrate + Append(&codec, "clockrate", iter->clockrate); + Append(&codec, "codec", codec_str); + Json::Value codec_id; + Append(&codec_id, talk_base::ToString(iter->id), codec); + rtpmap->push_back(codec_id); + } + } else { + const cricket::VideoContentDescription* video_offer = + static_cast( + content_info.description); + + std::vector::const_iterator iter = + video_offer->codecs().begin(); + std::vector::const_iterator iter_end = + video_offer->codecs().end(); + for (; iter != iter_end; ++iter) { + Json::Value codec; + std::string codec_str(std::string("video/").append(iter->name)); + Append(&codec, "codec", codec_str); + Json::Value codec_id; + Append(&codec_id, talk_base::ToString(iter->id), codec); + rtpmap->push_back(codec_id); + } + } + return true; +} + +bool BuildCandidate(const std::vector& candidates, + bool video, + std::vector* jcandidates) { + std::vector::const_iterator iter = + candidates.begin(); + std::vector::const_iterator iter_end = + candidates.end(); + for (; iter != iter_end; ++iter) { + if ((video && (!iter->name().compare("video_rtcp") || + (!iter->name().compare("video_rtp")))) || + (!video && (!iter->name().compare("rtp") || + (!iter->name().compare("rtcp"))))) { + Json::Value jcandidate; + Append(&jcandidate, "component", kIceComponent); + Append(&jcandidate, "foundation", kIceFoundation); + Append(&jcandidate, "generation", iter->generation()); + Append(&jcandidate, "proto", iter->protocol()); + Append(&jcandidate, "priority", iter->preference_str()); + Append(&jcandidate, "ip", iter->address().IPAsString()); + Append(&jcandidate, "port", iter->address().PortAsString()); + Append(&jcandidate, "type", iter->type()); + Append(&jcandidate, "name", iter->name()); + Append(&jcandidate, "network_name", iter->network_name()); + Append(&jcandidate, "username", iter->username()); + Append(&jcandidate, "password", iter->password()); + jcandidates->push_back(jcandidate); + } + } + return true; +} + +bool BuildTrack(const cricket::SessionDescription* sdp, + bool video, + std::vector* tracks) { + const cricket::ContentInfo* content; + if (video) + content = GetFirstVideoContent(sdp); + else + content = GetFirstAudioContent(sdp); + + if (!content) + return false; + + const cricket::MediaContentDescription* desc = + static_cast( + content->description); + for (cricket::Sources::const_iterator it = desc->sources().begin(); + it != desc->sources().end(); + ++it) { + Json::Value track; + Append(&track, "ssrc", it->ssrc); + Append(&track, "cname", it->cname); + tracks->push_back(track); + } + return true; +} + +std::string Serialize(const Json::Value& value) { + Json::StyledWriter writer; + return writer.write(value); +} + +bool Deserialize(const std::string& message, Json::Value* value) { + Json::Reader reader; + return reader.parse(message, *value); +} + +bool JsonDeserialize(const std::string& signaling_message, + cricket::SessionDescription** sdp, + std::vector* candidates) { + ASSERT(!(*sdp)); // expect this to be NULL + // first deserialize message + Json::Value value; + if (!Deserialize(signaling_message, &value)) { + return false; + } + + // get media objects + std::vector mlines = ReadValues(value, "media"); + if (mlines.empty()) { + // no m-lines found + return false; + } + + *sdp = new cricket::SessionDescription(); + + // get codec information + for (size_t i = 0; i < mlines.size(); ++i) { + if (mlines[i]["label"].asInt() == 1) { + cricket::AudioContentDescription* audio_content = + new cricket::AudioContentDescription(); + ParseAudioCodec(mlines[i], audio_content); + audio_content->set_rtcp_mux(ParseRtcpMux(mlines[i])); + audio_content->SortCodecs(); + (*sdp)->AddContent(cricket::CN_AUDIO, + cricket::NS_JINGLE_RTP, audio_content); + ParseIceCandidates(mlines[i], candidates); + } else { + cricket::VideoContentDescription* video_content = + new cricket::VideoContentDescription(); + ParseVideoCodec(mlines[i], video_content); + + video_content->set_rtcp_mux(ParseRtcpMux(mlines[i])); + video_content->SortCodecs(); + (*sdp)->AddContent(cricket::CN_VIDEO, + cricket::NS_JINGLE_RTP, video_content); + ParseIceCandidates(mlines[i], candidates); + } + } + return true; +} + +bool ParseRtcpMux(const Json::Value& value) { + Json::Value rtcp_mux(ReadValue(value, "rtcp_mux")); + if (!rtcp_mux.empty()) { + if (rtcp_mux.asBool()) { + return true; + } + } + return false; +} + +bool ParseAudioCodec(const Json::Value& value, + cricket::AudioContentDescription* content) { + std::vector rtpmap(ReadValues(value, "rtpmap")); + if (rtpmap.empty()) + return false; + + std::vector::const_iterator iter = + rtpmap.begin(); + std::vector::const_iterator iter_end = + rtpmap.end(); + for (; iter != iter_end; ++iter) { + cricket::AudioCodec codec; + std::string pltype(iter->begin().memberName()); + talk_base::FromString(pltype, &codec.id); + Json::Value codec_info((*iter)[pltype]); + std::string codec_name(ReadString(codec_info, "codec")); + std::vector tokens; + talk_base::split(codec_name, '/', &tokens); + codec.name = tokens[1]; + codec.clockrate = ReadUInt(codec_info, "clockrate"); + content->AddCodec(codec); + } + + return true; +} + +bool ParseVideoCodec(const Json::Value& value, + cricket::VideoContentDescription* content) { + std::vector rtpmap(ReadValues(value, "rtpmap")); + if (rtpmap.empty()) + return false; + + std::vector::const_iterator iter = + rtpmap.begin(); + std::vector::const_iterator iter_end = + rtpmap.end(); + for (; iter != iter_end; ++iter) { + cricket::VideoCodec codec; + std::string pltype(iter->begin().memberName()); + talk_base::FromString(pltype, &codec.id); + Json::Value codec_info((*iter)[pltype]); + std::vector tokens; + talk_base::split(codec_info["codec"].asString(), '/', &tokens); + codec.name = tokens[1]; + content->AddCodec(codec); + } + return true; +} + +bool ParseIceCandidates(const Json::Value& value, + std::vector* candidates) { + Json::Value attributes(ReadValue(value, "attributes")); + std::string ice_pwd(ReadString(attributes, "ice-pwd")); + std::string ice_ufrag(ReadString(attributes, "ice-ufrag")); + + std::vector jcandidates(ReadValues(attributes, "candidate")); + + std::vector::const_iterator iter = + jcandidates.begin(); + std::vector::const_iterator iter_end = + jcandidates.end(); + for (; iter != iter_end; ++iter) { + cricket::Candidate cand; + + unsigned int generation; + if (!GetUIntFromJsonObject(*iter, "generation", &generation)) + return false; + cand.set_generation_str(talk_base::ToString(generation)); + + std::string proto; + if (!GetStringFromJsonObject(*iter, "proto", &proto)) + return false; + cand.set_protocol(proto); + + std::string priority; + if (!GetStringFromJsonObject(*iter, "priority", &priority)) + return false; + cand.set_preference_str(priority); + + std::string str; + talk_base::SocketAddress addr; + if (!GetStringFromJsonObject(*iter, "ip", &str)) + return false; + addr.SetIP(str); + if (!GetStringFromJsonObject(*iter, "port", &str)) + return false; + int port; + if (!talk_base::FromString(str, &port)) + return false; + addr.SetPort(port); + cand.set_address(addr); + + if (!GetStringFromJsonObject(*iter, "type", &str)) + return false; + cand.set_type(str); + + if (!GetStringFromJsonObject(*iter, "name", &str)) + return false; + cand.set_name(str); + + if (!GetStringFromJsonObject(*iter, "network_name", &str)) + return false; + cand.set_network_name(str); + + if (!GetStringFromJsonObject(*iter, "username", &str)) + return false; + cand.set_username(str); + + if (!GetStringFromJsonObject(*iter, "password", &str)) + return false; + cand.set_password(str); + + candidates->push_back(cand); + } + return true; +} + +std::vector ReadValues( + const Json::Value& value, const std::string& key) { + std::vector objects; + for (Json::Value::ArrayIndex i = 0; i < value[key].size(); ++i) { + objects.push_back(value[key][i]); + } + return objects; +} + +Json::Value ReadValue(const Json::Value& value, const std::string& key) { + return value[key]; +} + +std::string ReadString(const Json::Value& value, const std::string& key) { + return value[key].asString(); +} + +uint32 ReadUInt(const Json::Value& value, const std::string& key) { + return value[key].asUInt(); +} + +double ReadDouble(const Json::Value& value, const std::string& key) { + return value[key].asDouble(); +} + +void Append(Json::Value* object, const std::string& key, bool value) { + (*object)[key] = Json::Value(value); +} + +void Append(Json::Value* object, const std::string& key, const char* value) { + (*object)[key] = Json::Value(value); +} + +void Append(Json::Value* object, const std::string& key, int value) { + (*object)[key] = Json::Value(value); +} + +void Append(Json::Value* object, const std::string& key, + const std::string& value) { + (*object)[key] = Json::Value(value); +} + +void Append(Json::Value* object, const std::string& key, uint32 value) { + (*object)[key] = Json::Value(value); +} + +void Append(Json::Value* object, const std::string& key, + const Json::Value& value) { + (*object)[key] = value; +} + +void Append(Json::Value* object, + const std::string & key, + const std::vector& values) { + for (std::vector::const_iterator iter = values.begin(); + iter != values.end(); ++iter) { + (*object)[key].append(*iter); + } +} + +} // namespace webrtc diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.h b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.h new file mode 100644 index 0000000000..d456fd5c2e --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcjson.h @@ -0,0 +1,56 @@ +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TALK_APP_WEBRTC_WEBRTCJSON_H_ +#define TALK_APP_WEBRTC_WEBRTCJSON_H_ + +#include + +#ifdef WEBRTC_RELATIVE_PATH +#include "json/json.h" +#else +#include "third_party/jsoncpp/json.h" +#endif +#include "talk/p2p/base/candidate.h" + +namespace cricket { +class SessionDescription; +} + +namespace webrtc { + +bool JsonSerialize( + const cricket::SessionDescription* sdp, + const std::vector& candidates, + std::string* signaling_message); + +bool JsonDeserialize(const std::string& signaling_message, + cricket::SessionDescription** sdp, + std::vector* candidates); +} + +#endif // TALK_APP_WEBRTC_WEBRTCJSON_H_ diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.cc index 3ce0fa3ad8..ec2f652537 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.cc +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.cc @@ -47,7 +47,8 @@ WebRtcSession::WebRtcSession(cricket::ChannelManager* channel_manager, talk_base::Thread* worker_thread, cricket::PortAllocator* port_allocator, PeerConnectionSignaling* pc_signaling) - : cricket::BaseSession(pc_signaling->signaling_thread(), worker_thread, + // TODO(ronghuawu): get the signaling thread from PeerConnectionSignaling + : cricket::BaseSession(worker_thread, worker_thread, port_allocator, talk_base::ToString(talk_base::CreateRandomId()), cricket::NS_JINGLE_RTP, true) { diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.h b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.h index 8e28a8344c..c6c347bfc0 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.h +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/webrtcsession.h @@ -43,6 +43,7 @@ namespace webrtc { class MediaStream; class PeerConnectionMessage; class PeerConnectionSignaling; +class StreamCollection; class WebRtcSession : public cricket::BaseSession { public: