From 931b52184bf37f298f9c967883a3b71c912f834b Mon Sep 17 00:00:00 2001 From: dknn Date: Sun, 3 Jun 2012 15:11:35 +0200 Subject: Add parsing add related tests for RTP description diff --git a/Swiften/Elements/JingleRTPDescription.h b/Swiften/Elements/JingleRTPDescription.h index 5337aa8..26b5a24 100644 --- a/Swiften/Elements/JingleRTPDescription.h +++ b/Swiften/Elements/JingleRTPDescription.h @@ -24,12 +24,12 @@ namespace Swift { }; public: - JingleRTPDescription(MediaType mediaType = Unknown, std::string bandwidthType = "", + JingleRTPDescription(MediaType media = Unknown, std::string bandwidthType = "", std::string bandwidthValue = "", boost::uint32_t ssrc = 0) : - mediaType(mediaType), bandwidthType(bandwidthType), bandwidthValue(bandwidthValue), ssrc(ssrc) {} + media(media), bandwidthType(bandwidthType), bandwidthValue(bandwidthValue), ssrc(ssrc) {} - void setMediaType(MediaType mediaType) { this->mediaType = mediaType; } - MediaType getMediaType() const { return mediaType; } + void setMedia(MediaType media) { this->media = media; } + MediaType getMedia() const { return media; } void setBandwidth(const std::string& type, const std::string& value) { bandwidthType = type; @@ -47,7 +47,7 @@ namespace Swift { const std::vector& getPayloadTypes() const { return payloadTypes; } private: - MediaType mediaType; + MediaType media; std::string bandwidthType; std::string bandwidthValue; boost::uint32_t ssrc; diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index a40e8f6..e6f3f60 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -67,6 +67,8 @@ #include #include #include +#include +#include using namespace boost; @@ -128,6 +130,8 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared >("wb", "http://swift.im/whiteboard")); factories_.push_back(boost::make_shared()); factories_.push_back(boost::make_shared()); + factories_.push_back(boost::make_shared(this)); + factories_.push_back(boost::make_shared >("payload-type")); foreach(shared_ptr factory, factories_) { addFactory(factory.get()); diff --git a/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParser.cpp b/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParser.cpp new file mode 100644 index 0000000..7429b39 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParser.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012 Yoann Blein + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "JingleRTPDescriptionParser.h" + +#include +#include + +#include + +namespace Swift { + +JingleRTPDescriptionParser::JingleRTPDescriptionParser(PayloadParserFactoryCollection* factories) : + factories(factories), level(0), parsingBandwidth(false) { + +} + +void JingleRTPDescriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + const std::string& media = attributes.getAttributeValue("media").get_value_or(""); + getPayloadInternal()->setMedia(mediaTypeFromString(media)); + } + + if (level == 1) { + if (element == "bandwidth") { + parsingBandwidth = true; + bandwidthType = attributes.getAttributeValue("type").get_value_or(""); + } else { + PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } + } + } + + if (level >= 1 && currentPayloadParser && !parsingBandwidth) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + + ++level; +} + +void JingleRTPDescriptionParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (element == "bandwidth") { + parsingBandwidth = false; + getPayloadInternal()->setBandwidth(bandwidthType, bandwidthValue); + } else if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + if (level == 1) { + RTPPayloadType::ref payloadType = boost::dynamic_pointer_cast(currentPayloadParser->getPayload()); + if (payloadType) { + getPayloadInternal()->addPayloadType(*payloadType); + } + } + } +} + +void JingleRTPDescriptionParser::handleCharacterData(const std::string& data) { + if (level == 2 && parsingBandwidth) { + bandwidthValue += data; + } +} + +JingleRTPDescription::MediaType JingleRTPDescriptionParser::mediaTypeFromString(const std::string& media) const { + if (media == "audio") { + return JingleRTPDescription::Audio; + } else if (media == "video") { + return JingleRTPDescription::Video; + } else { + return JingleRTPDescription::Unknown; + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParser.h b/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParser.h new file mode 100644 index 0000000..d250754 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParser.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 Yoann Blein + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include +#include + +namespace Swift { + +class PayloadParserFactoryCollection; + +class JingleRTPDescriptionParser : public GenericPayloadParser { + public: + JingleRTPDescriptionParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string& ns); + virtual void handleCharacterData(const std::string& data); + + private: + JingleRTPDescription::MediaType mediaTypeFromString(const std::string& media) const; + + private: + PayloadParserFactoryCollection* factories; + int level; + //CurrentParseElement currentElement; + boost::shared_ptr currentPayloadParser; + bool parsingBandwidth; + std::string bandwidthType; + std::string bandwidthValue; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParserFactory.h b/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParserFactory.h new file mode 100644 index 0000000..90d32eb --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleRTPDescriptionParserFactory.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012 Yoann Blein + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + + class PayloadParserFactoryCollection; + + class JingleRTPDescriptionParserFactory : public PayloadParserFactory { + public: + JingleRTPDescriptionParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return element == "description" && ns == "urn:xmpp:jingle:apps:rtp:1"; + } + + virtual PayloadParser* createPayloadParser() { + return new JingleRTPDescriptionParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; + + }; +} + + diff --git a/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.cpp b/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.cpp index 56fe109..f9d9bb3 100644 --- a/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.cpp +++ b/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.cpp @@ -8,9 +8,7 @@ #include #include - -//#include -//#include +#include namespace Swift { @@ -20,7 +18,7 @@ RTPPayloadTypeParser::RTPPayloadTypeParser() : level(0) { void RTPPayloadTypeParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { if (level == 0) { - // channel + // channels try { getPayloadInternal()->setChannels(boost::lexical_cast(attributes.getAttributeValue("channels").get_value_or("1"))); } catch (boost::bad_lexical_cast &) { @@ -34,9 +32,9 @@ void RTPPayloadTypeParser::handleStartElement(const std::string& element, const } // ID try { - getPayloadInternal()->setID(boost::lexical_cast(attributes.getAttributeValue("id").get_value_or("0"))); + getPayloadInternal()->setID(boost::numeric_cast(boost::lexical_cast(attributes.getAttributeValue("id").get_value_or("0")))); } catch (boost::bad_lexical_cast &) { - getPayloadInternal()->setID(0); + getPayloadInternal()->setID(151); } // maxptime try { @@ -52,14 +50,14 @@ void RTPPayloadTypeParser::handleStartElement(const std::string& element, const } catch (boost::bad_lexical_cast &) { getPayloadInternal()->setPTime(0); } - } else if (level == 1) { + } else if (level == 1 && element == "parameter") { getPayloadInternal()->addParameter(attributes.getAttributeValue("name").get_value_or(""), attributes.getAttributeValue("value").get_value_or("")); } ++level; } -void RTPPayloadTypeParser::handleEndElement(const std::string& element, const std::string&) { +void RTPPayloadTypeParser::handleEndElement(const std::string&, const std::string&) { --level; } diff --git a/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.h b/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.h index 8dee938..f632aca 100644 --- a/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.h +++ b/Swiften/Parser/PayloadParsers/RTPPayloadTypeParser.h @@ -16,7 +16,7 @@ namespace Swift { RTPPayloadTypeParser(); virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); - virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleEndElement(const std::string&, const std::string&); virtual void handleCharacterData(const std::string&) {}; private: diff --git a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp index 8719a5d..18f38b2 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp @@ -15,6 +15,8 @@ #include #include #include +//#include +#include #include #include @@ -41,6 +43,10 @@ class JingleParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_Xep0260_Example1); CPPUNIT_TEST(testParse_Xep0260_Example3); + + CPPUNIT_TEST(testParse_Xep0167_Example1); + CPPUNIT_TEST(testParse_Xep0167_Example48); + CPPUNIT_TEST_SUITE_END(); public: @@ -704,6 +710,115 @@ class JingleParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(8257606, candidate.priority); CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::Candidate::DirectType, candidate.type); } + + // http://xmpp.org/extensions/xep-0167.html#example-1 + void testParse_Xep0167_Example1() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "" + "" + "" + "" + "" + "" + "" + //"" + "" + "" + )); + + JinglePayload::ref jingle = parser.getPayload(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInitiate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload(); + CPPUNIT_ASSERT(content); + CPPUNIT_ASSERT_EQUAL(std::string("voice"), content->getName()); + + JingleRTPDescription::ref desc = content->getDescription(); + CPPUNIT_ASSERT(desc); + CPPUNIT_ASSERT_EQUAL(JingleRTPDescription::Audio, desc->getMedia()); + + CPPUNIT_ASSERT_EQUAL(static_cast(3), desc->getPayloadTypes().size()); + + const RTPPayloadType& payloadType1 = desc->getPayloadTypes()[0]; + CPPUNIT_ASSERT_EQUAL(static_cast(16000), payloadType1.getClockrate()); + CPPUNIT_ASSERT_EQUAL(static_cast(96), payloadType1.getID()); + CPPUNIT_ASSERT_EQUAL(std::string("speex"), payloadType1.getName()); + + const RTPPayloadType& payloadType2 = desc->getPayloadTypes()[1]; + CPPUNIT_ASSERT_EQUAL(static_cast(18), payloadType2.getID()); + CPPUNIT_ASSERT_EQUAL(std::string("G729"), payloadType2.getName()); + + const RTPPayloadType& payloadType3 = desc->getPayloadTypes()[2]; + CPPUNIT_ASSERT_EQUAL(static_cast(2), payloadType3.getChannels()); + CPPUNIT_ASSERT_EQUAL(static_cast(16000), payloadType3.getClockrate()); + CPPUNIT_ASSERT_EQUAL(static_cast(103), payloadType3.getID()); + CPPUNIT_ASSERT_EQUAL(std::string("L16"), payloadType3.getName()); + } + + // http://xmpp.org/extensions/xep-0167.html#example-48 + void testParse_Xep0167_Example48() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "128" + "" + //"" + "" + "" + )); + + JinglePayload::ref jingle = parser.getPayload(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::ContentAccept, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload(); + CPPUNIT_ASSERT(content); + CPPUNIT_ASSERT_EQUAL(std::string("webcam"), content->getName()); + + JingleRTPDescription::ref desc = content->getDescription(); + CPPUNIT_ASSERT(desc); + CPPUNIT_ASSERT_EQUAL(JingleRTPDescription::Video, desc->getMedia()); + + CPPUNIT_ASSERT_EQUAL(static_cast(1), desc->getPayloadTypes().size()); + + const RTPPayloadType& payloadType = desc->getPayloadTypes()[0]; + CPPUNIT_ASSERT_EQUAL(static_cast(90000), payloadType.getClockrate()); + CPPUNIT_ASSERT_EQUAL(static_cast(98), payloadType.getID()); + CPPUNIT_ASSERT_EQUAL(std::string("theora"), payloadType.getName()); + + RTPPayloadType::ParameterMap params = payloadType.getParameters(); // Explicit copy for easy testing + CPPUNIT_ASSERT_EQUAL(params["configuration"], std::string("somebase16string")); + CPPUNIT_ASSERT_EQUAL(params["delivery-method"], std::string("inline")); + CPPUNIT_ASSERT_EQUAL(params["height"], std::string("600")); + CPPUNIT_ASSERT_EQUAL(params["sampling"], std::string("YCbCr-4:2:2")); + CPPUNIT_ASSERT_EQUAL(params["width"], std::string("800")); + + std::string type, value; + desc->getBandwidth(type, value); + CPPUNIT_ASSERT_EQUAL(std::string("AS"), type); + CPPUNIT_ASSERT_EQUAL(std::string("128"), value); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(JingleParserTest); diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 64e9eb9..1ce84b9 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -73,6 +73,8 @@ sources = [ "PayloadParsers/DeliveryReceiptParser.cpp", "PayloadParsers/DeliveryReceiptRequestParser.cpp", "PayloadParsers/WhiteboardParser.cpp", + "PayloadParsers/RTPPayloadTypeParser.cpp", + "PayloadParsers/JingleRTPDescriptionParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", "SerializingParser.cpp", diff --git a/Swiften/Serializer/PayloadSerializers/JingleRTPDescriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleRTPDescriptionSerializer.cpp index 475142b..c0dfba1 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleRTPDescriptionSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleRTPDescriptionSerializer.cpp @@ -24,7 +24,7 @@ JingleRTPDescriptionSerializer::JingleRTPDescriptionSerializer() { std::string JingleRTPDescriptionSerializer::serializePayload(boost::shared_ptr payload) const { XMLElement description("description", "urn:xmpp:jingle:apps:rtp:1"); - description.setAttribute("media", mediaTypeToString(payload->getMediaType())); + description.setAttribute("media", mediaTypeToString(payload->getMedia())); if (payload->getSSRC()) { description.setAttribute("ssrc", boost::lexical_cast(payload->getSSRC())); } diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp index bce9259..a89c91c 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp @@ -623,11 +623,11 @@ class JingleSerializersTest : public CppUnit::TestFixture { "" "" "" + "" + "" "" - //"" - //"" - //"" "" + "" "" "128" "" @@ -642,8 +642,11 @@ class JingleSerializersTest : public CppUnit::TestFixture { JingleRTPDescription::ref desc = boost::make_shared(JingleRTPDescription::Video); RTPPayloadType payloadType(98, "theora", 90000); + payloadType.addParameter("configuration", "somebase16string"); + payloadType.addParameter("delivery-method", "inline"); payloadType.addParameter("height", "600"); payloadType.addParameter("sampling", "YCbCr-4:2:2"); + payloadType.addParameter("width", "800"); desc->addPayloadType(payloadType); desc->setBandwidth("AS", "128"); -- cgit v0.10.2-6-g49f6