* Add Deserize for PeerConnectionMessage

BUG=
TEST=

Review URL: http://webrtc-codereview.appspot.com/189001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@671 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
wu@webrtc.org
2011-09-30 18:08:51 +00:00
parent e90265bd1a
commit c93e36346b
5 changed files with 259 additions and 96 deletions

View File

@ -36,14 +36,19 @@ namespace webrtc {
scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::Create( scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::Create(
PeerConnectionMessageType type, PeerConnectionMessageType type,
const cricket::SessionDescription* desc, cricket::SessionDescription* desc,
const std::vector<cricket::Candidate>& candidates) { const std::vector<cricket::Candidate>& candidates) {
return new RefCountImpl<PeerConnectionMessage> (type, desc, candidates); return new RefCountImpl<PeerConnectionMessage> (type, desc, candidates);
} }
scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::Create( scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::Create(
std::string message) { const std::string& message) {
return new RefCountImpl<PeerConnectionMessage> (message); scoped_refptr<PeerConnectionMessage>pc_message(new
RefCountImpl<PeerConnectionMessage> ());
if (pc_message->Deserialize(message))
return pc_message;
else
return NULL;
} }
scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::CreateErrorMessage( scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::CreateErrorMessage(
@ -53,7 +58,7 @@ scoped_refptr<PeerConnectionMessage> PeerConnectionMessage::CreateErrorMessage(
PeerConnectionMessage::PeerConnectionMessage( PeerConnectionMessage::PeerConnectionMessage(
PeerConnectionMessageType type, PeerConnectionMessageType type,
const cricket::SessionDescription* desc, cricket::SessionDescription* desc,
const std::vector<cricket::Candidate>& candidates) const std::vector<cricket::Candidate>& candidates)
: type_(type), : type_(type),
error_code_(kNoError), error_code_(kNoError),
@ -61,8 +66,10 @@ PeerConnectionMessage::PeerConnectionMessage(
candidates_(candidates) { candidates_(candidates) {
} }
PeerConnectionMessage::PeerConnectionMessage(std::string message) { PeerConnectionMessage::PeerConnectionMessage()
// TODO(ronghuawu): implement : type_(kOffer),
error_code_(kNoError),
desc_(new cricket::SessionDescription()) {
} }
PeerConnectionMessage::PeerConnectionMessage(ErrorCode error) PeerConnectionMessage::PeerConnectionMessage(ErrorCode error)
@ -72,7 +79,13 @@ PeerConnectionMessage::PeerConnectionMessage(ErrorCode error)
} }
bool PeerConnectionMessage::Serialize(std::string* message) { bool PeerConnectionMessage::Serialize(std::string* message) {
return JsonSerialize(desc_.get(), candidates_, message); return JsonSerialize(type_, error_code_,
desc_.get(), candidates_, message);
}
bool PeerConnectionMessage::Deserialize(std::string message) {
return JsonDeserialize(&type_, &error_code_, desc_.get(),
&candidates_, message);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -65,10 +65,11 @@ class PeerConnectionMessage : public RefCount {
static scoped_refptr<PeerConnectionMessage> Create( static scoped_refptr<PeerConnectionMessage> Create(
PeerConnectionMessageType type, PeerConnectionMessageType type,
const cricket::SessionDescription* desc, cricket::SessionDescription* desc,
const std::vector<cricket::Candidate>& candidates); const std::vector<cricket::Candidate>& candidates);
static scoped_refptr<PeerConnectionMessage> Create(std::string message); static scoped_refptr<PeerConnectionMessage> Create(
const std::string& message);
static scoped_refptr<PeerConnectionMessage> CreateErrorMessage( static scoped_refptr<PeerConnectionMessage> CreateErrorMessage(
ErrorCode error); ErrorCode error);
@ -81,16 +82,19 @@ class PeerConnectionMessage : public RefCount {
protected: protected:
PeerConnectionMessage(PeerConnectionMessageType type, PeerConnectionMessage(PeerConnectionMessageType type,
const cricket::SessionDescription* desc, cricket::SessionDescription* desc,
const std::vector<cricket::Candidate>& candidates); const std::vector<cricket::Candidate>& candidates);
explicit PeerConnectionMessage(std::string message); PeerConnectionMessage();
explicit PeerConnectionMessage(ErrorCode error); explicit PeerConnectionMessage(ErrorCode error);
bool Deserialize(std::string message);
private: private:
PeerConnectionMessageType type_; PeerConnectionMessageType type_;
ErrorCode error_code_; ErrorCode error_code_;
talk_base::scoped_ptr<const cricket::SessionDescription> desc_; talk_base::scoped_ptr<cricket::SessionDescription> desc_;
std::vector<cricket::Candidate> candidates_; std::vector<cricket::Candidate> candidates_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -80,18 +80,91 @@ class PeerConnectionMessageTest: public testing::Test {
}; };
TEST_F(PeerConnectionMessageTest, Serialize) { TEST_F(PeerConnectionMessageTest, Serialize) {
talk_base::scoped_ptr<cricket::SessionDescription> offer(
session_description_factory_->CreateOffer(options_));
std::vector<cricket::Candidate> candidates; std::vector<cricket::Candidate> candidates;
// TODO(ronghuawu): Populate the test candidates. // TODO(ronghuawu): Populate the test candidates.
std::string message; std::string message;
scoped_refptr<PeerConnectionMessage> offer_message = scoped_refptr<PeerConnectionMessage> pc_message;
PeerConnectionMessage::Create(PeerConnectionMessage::kOffer,
offer.release(), // Offer
candidates); talk_base::scoped_ptr<cricket::SessionDescription> offer(
EXPECT_TRUE(offer_message->Serialize(&message)); session_description_factory_->CreateOffer(options_));
LOG(LS_ERROR) << message; pc_message = PeerConnectionMessage::Create(PeerConnectionMessage::kOffer,
offer.get(), candidates);
EXPECT_TRUE(pc_message->Serialize(&message));
pc_message.release();
LOG(LS_INFO) << message;
// Answer
talk_base::scoped_ptr<cricket::SessionDescription> answer(
session_description_factory_->CreateAnswer(offer.get(), options_));
pc_message = PeerConnectionMessage::Create(PeerConnectionMessage::kAnswer,
answer.get(), candidates);
EXPECT_TRUE(pc_message->Serialize(&message));
pc_message.release();
LOG(LS_INFO) << message;
// Error
pc_message = PeerConnectionMessage::CreateErrorMessage(
PeerConnectionMessage::kParseError);
EXPECT_TRUE(pc_message->Serialize(&message));
pc_message.release();
LOG(LS_INFO) << message;
// TODO(ronghuawu): Verify the serialized message. // TODO(ronghuawu): Verify the serialized message.
} }
TEST_F(PeerConnectionMessageTest, Deserialize) {
std::vector<cricket::Candidate> candidates;
// TODO(ronghuawu): Populate the test candidates.
std::string message_ref;
std::string message_result;
scoped_refptr<PeerConnectionMessage> pc_message;
// Offer
talk_base::scoped_ptr<cricket::SessionDescription> offer(
session_description_factory_->CreateOffer(options_));
pc_message = PeerConnectionMessage::Create(PeerConnectionMessage::kOffer,
offer.get(), candidates);
EXPECT_TRUE(pc_message->Serialize(&message_ref));
pc_message.release();
LOG(LS_INFO) << "The reference message: " << message_ref;
// Deserialize Offer
pc_message = PeerConnectionMessage::Create(message_ref);
EXPECT_TRUE(pc_message->Serialize(&message_result));
pc_message.release();
LOG(LS_INFO) << "The result message: " << message_result;
EXPECT_EQ(message_ref, message_result);
// Answer
talk_base::scoped_ptr<cricket::SessionDescription> answer(
session_description_factory_->CreateAnswer(offer.get(), options_));
pc_message = PeerConnectionMessage::Create(PeerConnectionMessage::kAnswer,
answer.get(), candidates);
EXPECT_TRUE(pc_message->Serialize(&message_ref));
pc_message.release();
LOG(LS_INFO) << "The reference message: " << message_ref;
// Deserialize Answer
pc_message = PeerConnectionMessage::Create(message_ref);
EXPECT_TRUE(pc_message->Serialize(&message_result));
pc_message.release();
LOG(LS_INFO) << "The result message: " << message_result;
EXPECT_EQ(message_ref, message_result);
// Error
pc_message = PeerConnectionMessage::CreateErrorMessage(
PeerConnectionMessage::kParseError);
EXPECT_TRUE(pc_message->Serialize(&message_ref));
pc_message.release();
LOG(LS_INFO) << "The reference message: " << message_ref;
// Deserialize Error
pc_message = PeerConnectionMessage::Create(message_ref);
EXPECT_TRUE(pc_message->Serialize(&message_result));
pc_message.release();
LOG(LS_INFO) << "The result message: " << message_result;
EXPECT_EQ(message_ref, message_result);
}

View File

@ -34,11 +34,17 @@
#include "talk/base/logging.h" #include "talk/base/logging.h"
#include "talk/base/stringutils.h" #include "talk/base/stringutils.h"
#include "talk/session/phone/codec.h" #include "talk/session/phone/codec.h"
#include "talk/session/phone/mediasession.h"
#include "talk/session/phone/mediasessionclient.h" #include "talk/session/phone/mediasessionclient.h"
namespace webrtc { namespace webrtc {
static const int kIceComponent = 1; static const int kIceComponent = 1;
static const int kIceFoundation = 1; static const int kIceFoundation = 1;
static const char* kMessageType[] = {
"OFFER",
"ANSWER",
"ERROR",
};
static std::vector<Json::Value> ReadValues(const Json::Value& value, static std::vector<Json::Value> ReadValues(const Json::Value& value,
const std::string& key); const std::string& key);
@ -66,17 +72,19 @@ static std::string Serialize(const Json::Value& value);
static bool Deserialize(const std::string& message, Json::Value& value); static bool Deserialize(const std::string& message, Json::Value& value);
static bool ParseRtcpMux(const Json::Value& value); bool ParseContent(const Json::Value& jmessage,
cricket::SessionDescription* sdp,
std::vector<cricket::Candidate>* candidates);
static bool ParseAudioCodec(const Json::Value& value, static bool ParseAudioCodec(const Json::Value& value,
cricket::AudioContentDescription* content); cricket::AudioContentDescription* content);
static bool ParseVideoCodec(const Json::Value& value, static bool ParseVideoCodec(const Json::Value& value,
cricket::VideoContentDescription* content); cricket::VideoContentDescription* content);
static bool ParseIceCandidates(const Json::Value& value, static bool ParseCandidates(const Json::Value& content,
std::vector<cricket::Candidate>* candidates); std::vector<cricket::Candidate>* 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 bool ParseTrack(const Json::Value& content,
static double ReadDouble(const Json::Value& value, const std::string& key); cricket::MediaContentDescription* content_desc);
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, bool value);
static void Append(Json::Value* object, const std::string& key, static void Append(Json::Value* object, const std::string& key,
@ -92,13 +100,24 @@ static void Append(Json::Value* object,
const std::vector<Json::Value>& values); const std::vector<Json::Value>& values);
bool JsonSerialize( bool JsonSerialize(
const webrtc::PeerConnectionMessage::PeerConnectionMessageType type,
int error_code,
const cricket::SessionDescription* sdp, const cricket::SessionDescription* sdp,
const std::vector<cricket::Candidate>& candidates, const std::vector<cricket::Candidate>& candidates,
std::string* signaling_message) { std::string* signaling_message) {
Json::Value media;
// TODO(ronghuawu): Replace magic strings.
Append(&media, "SDP", kMessageType[type]);
if (type == webrtc::PeerConnectionMessage::kError) {
Append(&media, "error_code", error_code);
*signaling_message = Serialize(media);
return true;
}
const cricket::ContentInfo* audio_content = GetFirstAudioContent(sdp); const cricket::ContentInfo* audio_content = GetFirstAudioContent(sdp);
const cricket::ContentInfo* video_content = GetFirstVideoContent(sdp); const cricket::ContentInfo* video_content = GetFirstVideoContent(sdp);
Json::Value media;
std::vector<Json::Value> together; std::vector<Json::Value> together;
together.push_back("audio"); together.push_back("audio");
together.push_back("video"); together.push_back("video");
@ -266,6 +285,7 @@ bool BuildTrack(const cricket::SessionDescription* sdp,
Json::Value track; Json::Value track;
Append(&track, "ssrc", it->ssrc); Append(&track, "ssrc", it->ssrc);
Append(&track, "cname", it->cname); Append(&track, "cname", it->cname);
Append(&track, "label", it->description);
tracks->push_back(track); tracks->push_back(track);
} }
return true; return true;
@ -281,66 +301,103 @@ bool Deserialize(const std::string& message, Json::Value* value) {
return reader.parse(message, *value); return reader.parse(message, *value);
} }
bool JsonDeserialize(const std::string& signaling_message, bool JsonDeserialize(
cricket::SessionDescription** sdp, webrtc::PeerConnectionMessage::PeerConnectionMessageType* type,
std::vector<cricket::Candidate>* candidates) { webrtc::PeerConnectionMessage::ErrorCode* error_code,
ASSERT(!(*sdp)); // expect this to be NULL cricket::SessionDescription* sdp,
std::vector<cricket::Candidate>* candidates,
const std::string& signaling_message) {
ASSERT(type);
ASSERT(error_code);
ASSERT(sdp);
ASSERT(candidates);
if (type == NULL || error_code == NULL || sdp == NULL || candidates == NULL)
return false;
// first deserialize message // first deserialize message
Json::Value value; Json::Value jmessage;
if (!Deserialize(signaling_message, &value)) { if (!Deserialize(signaling_message, &jmessage)) {
return false; return false;
} }
// get media objects // Get the message type
std::vector<Json::Value> mlines = ReadValues(value, "media"); std::string message_type;
if (mlines.empty()) { bool valid_message_type = false;
// no m-lines found if (!GetStringFromJsonObject(jmessage, "SDP", &message_type))
return false; return false;
for (int i = 0; i < ARRAY_SIZE(kMessageType); i++) {
if (message_type.compare(kMessageType[i]) == 0) {
*type = static_cast<
webrtc::PeerConnectionMessage::PeerConnectionMessageType>(i);
valid_message_type = true;
break;
}
}
if (!valid_message_type)
return false;
if (*type == webrtc::PeerConnectionMessage::kError) {
int code;
if (!GetIntFromJsonObject(jmessage, "error_code", &code))
return false;
*error_code = static_cast<webrtc::PeerConnectionMessage::ErrorCode>(code);
return true;
} }
*sdp = new cricket::SessionDescription(); return ParseContent(jmessage, sdp, candidates);
}
// get codec information bool ParseContent(const Json::Value& jmessage,
for (size_t i = 0; i < mlines.size(); ++i) { cricket::SessionDescription* sdp,
if (mlines[i]["label"].asInt() == 1) { std::vector<cricket::Candidate>* candidates) {
// Get content
std::vector<Json::Value> contents = ReadValues(jmessage, "content");
if (contents.size() == 0)
return false;
for (size_t i = 0; i < contents.size(); ++i) {
Json::Value content = contents[i];
// TODO(ronghuawu): crypto
// candidates
if (!ParseCandidates(content, candidates))
return false;
// rtcp_mux
bool rtcp_mux;
if (!GetBoolFromJsonObject(content, "rtcp_mux", &rtcp_mux))
rtcp_mux = false;
// rtpmap
if (content["media"].asString().compare("audio") == 0) {
cricket::AudioContentDescription* audio_content = cricket::AudioContentDescription* audio_content =
new cricket::AudioContentDescription(); new cricket::AudioContentDescription();
ParseAudioCodec(mlines[i], audio_content); if (!ParseAudioCodec(content, audio_content))
audio_content->set_rtcp_mux(ParseRtcpMux(mlines[i])); return false;
audio_content->set_rtcp_mux(rtcp_mux);
audio_content->SortCodecs(); audio_content->SortCodecs();
(*sdp)->AddContent(cricket::CN_AUDIO, // tracks
cricket::NS_JINGLE_RTP, audio_content); if (!ParseTrack(content, audio_content))
ParseIceCandidates(mlines[i], candidates); return false;
} else { (sdp)->AddContent(cricket::CN_AUDIO,
cricket::NS_JINGLE_RTP, audio_content);
} else if (content["media"].asString().compare("video") == 0) {
cricket::VideoContentDescription* video_content = cricket::VideoContentDescription* video_content =
new cricket::VideoContentDescription(); new cricket::VideoContentDescription();
ParseVideoCodec(mlines[i], video_content); if (!ParseVideoCodec(content, video_content))
return false;
video_content->set_rtcp_mux(ParseRtcpMux(mlines[i])); video_content->set_rtcp_mux(rtcp_mux);
video_content->SortCodecs(); video_content->SortCodecs();
(*sdp)->AddContent(cricket::CN_VIDEO, if (!ParseTrack(content, video_content))
cricket::NS_JINGLE_RTP, video_content); return false;
ParseIceCandidates(mlines[i], candidates); (sdp)->AddContent(cricket::CN_VIDEO,
cricket::NS_JINGLE_RTP, video_content);
} }
} }
return true; 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, bool ParseAudioCodec(const Json::Value& value,
cricket::AudioContentDescription* content) { cricket::AudioContentDescription* content) {
std::vector<Json::Value> rtpmap(ReadValues(value, "rtpmap")); std::vector<Json::Value> rtpmap(ReadValues(value, "rtpmap"));
// When there's no codecs in common, rtpmap can be empty.
if (rtpmap.empty()) if (rtpmap.empty())
return false; return true;
std::vector<Json::Value>::const_iterator iter = std::vector<Json::Value>::const_iterator iter =
rtpmap.begin(); rtpmap.begin();
@ -351,11 +408,13 @@ bool ParseAudioCodec(const Json::Value& value,
std::string pltype(iter->begin().memberName()); std::string pltype(iter->begin().memberName());
talk_base::FromString(pltype, &codec.id); talk_base::FromString(pltype, &codec.id);
Json::Value codec_info((*iter)[pltype]); Json::Value codec_info((*iter)[pltype]);
std::string codec_name(ReadString(codec_info, "codec")); std::string codec_name;
if (!GetStringFromJsonObject(codec_info, "codec", &codec_name))
continue;
std::vector<std::string> tokens; std::vector<std::string> tokens;
talk_base::split(codec_name, '/', &tokens); talk_base::split(codec_name, '/', &tokens);
codec.name = tokens[1]; codec.name = tokens[1];
codec.clockrate = ReadUInt(codec_info, "clockrate"); GetIntFromJsonObject(codec_info, "clockrate", &codec.clockrate);
content->AddCodec(codec); content->AddCodec(codec);
} }
@ -365,8 +424,9 @@ bool ParseAudioCodec(const Json::Value& value,
bool ParseVideoCodec(const Json::Value& value, bool ParseVideoCodec(const Json::Value& value,
cricket::VideoContentDescription* content) { cricket::VideoContentDescription* content) {
std::vector<Json::Value> rtpmap(ReadValues(value, "rtpmap")); std::vector<Json::Value> rtpmap(ReadValues(value, "rtpmap"));
// When there's no codecs in common, rtpmap can be empty.
if (rtpmap.empty()) if (rtpmap.empty())
return false; return true;
std::vector<Json::Value>::const_iterator iter = std::vector<Json::Value>::const_iterator iter =
rtpmap.begin(); rtpmap.begin();
@ -385,14 +445,9 @@ bool ParseVideoCodec(const Json::Value& value,
return true; return true;
} }
bool ParseIceCandidates(const Json::Value& value, bool ParseCandidates(const Json::Value& content,
std::vector<cricket::Candidate>* candidates) { std::vector<cricket::Candidate>* candidates) {
Json::Value attributes(ReadValue(value, "attributes")); std::vector<Json::Value> jcandidates(ReadValues(content, "candidate"));
std::string ice_pwd(ReadString(attributes, "ice-pwd"));
std::string ice_ufrag(ReadString(attributes, "ice-ufrag"));
std::vector<Json::Value> jcandidates(ReadValues(attributes, "candidate"));
std::vector<Json::Value>::const_iterator iter = std::vector<Json::Value>::const_iterator iter =
jcandidates.begin(); jcandidates.begin();
std::vector<Json::Value>::const_iterator iter_end = std::vector<Json::Value>::const_iterator iter_end =
@ -453,6 +508,34 @@ bool ParseIceCandidates(const Json::Value& value,
return true; return true;
} }
bool ParseTrack(const Json::Value& content,
cricket::MediaContentDescription* content_desc) {
ASSERT(content_desc);
if (!content_desc)
return false;
std::vector<Json::Value> tracks(ReadValues(content, "track"));
std::vector<Json::Value>::const_iterator iter =
tracks.begin();
std::vector<Json::Value>::const_iterator iter_end =
tracks.end();
cricket::Sources sources;
for (; iter != iter_end; ++iter) {
uint32 ssrc;
std::string label;
std::string cname;
if (!GetUIntFromJsonObject(*iter, "ssrc", &ssrc))
return false;
// label is optional, it will be empty string if doesn't exist
GetStringFromJsonObject(*iter, "label", &label);
if (!GetStringFromJsonObject(*iter, "cname", &cname))
return false;
sources.push_back(cricket::SourceParam(ssrc, label, cname));
}
content_desc->set_sources(sources);
return true;
}
std::vector<Json::Value> ReadValues( std::vector<Json::Value> ReadValues(
const Json::Value& value, const std::string& key) { const Json::Value& value, const std::string& key) {
std::vector<Json::Value> objects; std::vector<Json::Value> objects;
@ -462,22 +545,6 @@ std::vector<Json::Value> ReadValues(
return objects; 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) { void Append(Json::Value* object, const std::string& key, bool value) {
(*object)[key] = Json::Value(value); (*object)[key] = Json::Value(value);
} }

View File

@ -35,6 +35,7 @@
#else #else
#include "third_party/jsoncpp/json.h" #include "third_party/jsoncpp/json.h"
#endif #endif
#include "talk/app/webrtc_dev/peerconnectionmessage.h"
#include "talk/p2p/base/candidate.h" #include "talk/p2p/base/candidate.h"
namespace cricket { namespace cricket {
@ -44,13 +45,18 @@ class SessionDescription;
namespace webrtc { namespace webrtc {
bool JsonSerialize( bool JsonSerialize(
const webrtc::PeerConnectionMessage::PeerConnectionMessageType type,
int error_code,
const cricket::SessionDescription* sdp, const cricket::SessionDescription* sdp,
const std::vector<cricket::Candidate>& candidates, const std::vector<cricket::Candidate>& candidates,
std::string* signaling_message); std::string* signaling_message);
bool JsonDeserialize(const std::string& signaling_message, bool JsonDeserialize(
cricket::SessionDescription** sdp, webrtc::PeerConnectionMessage::PeerConnectionMessageType* type,
std::vector<cricket::Candidate>* candidates); webrtc::PeerConnectionMessage::ErrorCode* error_code,
cricket::SessionDescription* sdp,
std::vector<cricket::Candidate>* candidates,
const std::string& signaling_message);
} }
#endif // TALK_APP_WEBRTC_WEBRTCJSON_H_ #endif // TALK_APP_WEBRTC_WEBRTCJSON_H_