When creating an answer, takes the codec preference from the offer.
This change is based on RFC3264:
"Although the answerer MAY list the formats in their desired order of preference, it is RECOMMENDED that unless there is a specific reason, the answerer list formats in the same relative order they were present in the offer."
BUG=2868
TEST=unit tests and manually with munge-sdp test
R=juberti@google.com
Review URL: https://webrtc-codereview.appspot.com/14589004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@6514 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/base/codec.cc b/talk/media/base/codec.cc
index bc7401a..c6f0ea5 100644
--- a/talk/media/base/codec.cc
+++ b/talk/media/base/codec.cc
@@ -38,6 +38,7 @@
namespace cricket {
static const int kMaxStaticPayloadId = 95;
+const int kMaxPayloadId = 127;
bool FeedbackParam::operator==(const FeedbackParam& other) const {
return _stricmp(other.id().c_str(), id().c_str()) == 0 &&
diff --git a/talk/media/base/codec.h b/talk/media/base/codec.h
index 863e289..8619620 100644
--- a/talk/media/base/codec.h
+++ b/talk/media/base/codec.h
@@ -39,6 +39,8 @@
typedef std::map<std::string, std::string> CodecParameterMap;
+extern const int kMaxPayloadId;
+
class FeedbackParam {
public:
FeedbackParam(const std::string& id, const std::string& param)
diff --git a/talk/session/media/mediasession.cc b/talk/session/media/mediasession.cc
index 006975f..a5b1eb0 100644
--- a/talk/session/media/mediasession.cc
+++ b/talk/session/media/mediasession.cc
@@ -775,6 +775,11 @@
negotiated.SetParam(kCodecParamAssociatedPayloadType, apt_value);
}
negotiated.id = theirs->id;
+ // RFC3264: Although the answerer MAY list the formats in their desired
+ // order of preference, it is RECOMMENDED that unless there is a
+ // specific reason, the answerer list formats in the same relative order
+ // they were present in the offer.
+ negotiated.preference = theirs->preference;
negotiated_codecs->push_back(negotiated);
}
}
diff --git a/talk/session/media/mediasession_unittest.cc b/talk/session/media/mediasession_unittest.cc
index cf492a6..b76cce4 100644
--- a/talk/session/media/mediasession_unittest.cc
+++ b/talk/session/media/mediasession_unittest.cc
@@ -31,6 +31,7 @@
#include "talk/base/gunit.h"
#include "talk/base/fakesslidentity.h"
#include "talk/base/messagedigest.h"
+#include "talk/base/ssladapter.h"
#include "talk/media/base/codec.h"
#include "talk/media/base/testutils.h"
#include "talk/p2p/base/constants.h"
@@ -97,13 +98,13 @@
static const AudioCodec kAudioCodecs2[] = {
AudioCodec(126, "speex", 16000, 22000, 1, 3),
- AudioCodec(127, "iLBC", 8000, 13300, 1, 2),
- AudioCodec(0, "PCMU", 8000, 64000, 1, 1),
+ AudioCodec(0, "PCMU", 8000, 64000, 1, 2),
+ AudioCodec(127, "iLBC", 8000, 13300, 1, 1),
};
static const AudioCodec kAudioCodecsAnswer[] = {
- AudioCodec(102, "iLBC", 8000, 13300, 1, 2),
- AudioCodec(0, "PCMU", 8000, 64000, 1, 1),
+ AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
+ AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
};
static const VideoCodec kVideoCodecs1[] = {
@@ -117,7 +118,7 @@
};
static const VideoCodec kVideoCodecsAnswer[] = {
- VideoCodec(97, "H264", 320, 200, 30, 2)
+ VideoCodec(97, "H264", 320, 200, 30, 1)
};
static const DataCodec kDataCodecs1[] = {
@@ -196,6 +197,14 @@
tdf2_.set_identity(&id2_);
}
+ static void SetUpTestCase() {
+ talk_base::InitializeSSL();
+ }
+
+ static void TearDownTestCase() {
+ talk_base::CleanupSSL();
+ }
+
// Create a video StreamParamsVec object with:
// - one video stream with 3 simulcast streams and FEC,
StreamParamsVec CreateComplexVideoStreamParamsVec() {
@@ -1379,10 +1388,12 @@
// The expected audio codecs are the common audio codecs from the first
// offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
// preference order.
+ // TODO(wu): |updated_offer| should not include the codec
+ // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
const AudioCodec kUpdatedAudioCodecOffer[] = {
- kAudioCodecs2[0],
kAudioCodecsAnswer[0],
kAudioCodecsAnswer[1],
+ kAudioCodecs2[0],
};
// The expected video codecs are the common video codecs from the first
diff --git a/talk/session/media/mediasessionclient.cc b/talk/session/media/mediasessionclient.cc
index a5a652c..2ada987 100644
--- a/talk/session/media/mediasessionclient.cc
+++ b/talk/session/media/mediasessionclient.cc
@@ -373,6 +373,7 @@
ParseError* error) {
AudioContentDescription* audio = new AudioContentDescription();
+ int preference = kMaxPayloadId;
if (content_elem->FirstElement()) {
for (const buzz::XmlElement* codec_elem =
content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE);
@@ -380,6 +381,7 @@
codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) {
AudioCodec codec;
if (ParseGingleAudioCodec(codec_elem, &codec)) {
+ codec.preference = preference--;
audio->AddCodec(codec);
}
}
@@ -406,12 +408,14 @@
ParseError* error) {
VideoContentDescription* video = new VideoContentDescription();
+ int preference = kMaxPayloadId;
for (const buzz::XmlElement* codec_elem =
content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE);
codec_elem != NULL;
codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) {
VideoCodec codec;
if (ParseGingleVideoCodec(codec_elem, &codec)) {
+ codec.preference = preference--;
video->AddCodec(codec);
}
}
@@ -571,6 +575,7 @@
FeedbackParams content_feedback_params;
ParseFeedbackParams(content_elem, &content_feedback_params);
+ int preference = kMaxPayloadId;
for (const buzz::XmlElement* payload_elem =
content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
payload_elem != NULL;
@@ -578,6 +583,7 @@
AudioCodec codec;
if (ParseJingleAudioCodec(payload_elem, &codec)) {
AddFeedbackParams(content_feedback_params, &codec.feedback_params);
+ codec.preference = preference--;
audio->AddCodec(codec);
}
}
@@ -611,6 +617,7 @@
FeedbackParams content_feedback_params;
ParseFeedbackParams(content_elem, &content_feedback_params);
+ int preference = kMaxPayloadId;
for (const buzz::XmlElement* payload_elem =
content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
payload_elem != NULL;
@@ -618,6 +625,7 @@
VideoCodec codec;
if (ParseJingleVideoCodec(payload_elem, &codec)) {
AddFeedbackParams(content_feedback_params, &codec.feedback_params);
+ codec.preference = preference--;
video->AddCodec(codec);
}
}
@@ -681,6 +689,7 @@
FeedbackParams content_feedback_params;
ParseFeedbackParams(content_elem, &content_feedback_params);
+ int preference = kMaxPayloadId;
for (const buzz::XmlElement* payload_elem =
content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
payload_elem != NULL;
@@ -688,6 +697,7 @@
DataCodec codec;
if (ParseJingleDataCodec(payload_elem, &codec)) {
AddFeedbackParams(content_feedback_params, &codec.feedback_params);
+ codec.preference = preference--;
data->AddCodec(codec);
}
}
diff --git a/talk/session/media/mediasessionclient_unittest.cc b/talk/session/media/mediasessionclient_unittest.cc
index 7cb1ec9..3f3c4fa 100644
--- a/talk/session/media/mediasessionclient_unittest.cc
+++ b/talk/session/media/mediasessionclient_unittest.cc
@@ -32,6 +32,7 @@
#include "talk/base/logging.h"
#include "talk/base/scoped_ptr.h"
#include "talk/media/base/fakemediaengine.h"
+#include "talk/media/base/testutils.h"
#include "talk/media/devices/fakedevicemanager.h"
#include "talk/p2p/base/constants.h"
#include "talk/p2p/client/basicportallocator.h"
@@ -74,6 +75,29 @@
cricket::AudioCodec(106, "telephone-event", 8000, 0, 1, 1)
};
+// The codecs that our FakeMediaEngine will support with a different order of
+// supported codecs.
+static const cricket::AudioCodec kAudioCodecsDifferentPreference[] = {
+ cricket::AudioCodec(104, "ISAC", 32000, -1, 1, 17),
+ cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14),
+ cricket::AudioCodec(9, "G722", 16000, 64000, 1, 13),
+ cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16),
+ cricket::AudioCodec(103, "ISAC", 16000, -1, 1, 18),
+ cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15),
+ cricket::AudioCodec(100, "EG711U", 8000, 64000, 1, 9),
+ cricket::AudioCodec(101, "EG711A", 8000, 64000, 1, 8),
+ cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 7),
+ cricket::AudioCodec(8, "PCMA", 8000, 64000, 1, 6),
+ cricket::AudioCodec(102, "iLBC", 8000, 13300, 1, 12),
+ cricket::AudioCodec(3, "GSM", 8000, 13000, 1, 10),
+ cricket::AudioCodec(98, "speex", 8000, 11000, 1, 11),
+ cricket::AudioCodec(126, "CN", 32000, 0, 1, 5),
+ cricket::AudioCodec(105, "CN", 16000, 0, 1, 4),
+ cricket::AudioCodec(13, "CN", 8000, 0, 1, 3),
+ cricket::AudioCodec(117, "red", 8000, 0, 1, 2),
+ cricket::AudioCodec(106, "telephone-event", 8000, 0, 1, 1)
+};
+
static const cricket::VideoCodec kVideoCodecs[] = {
cricket::VideoCodec(96, "H264-SVC", 320, 200, 30, 1)
};
@@ -270,123 +294,6 @@
" </jingle> " \
"</iq> ");
-// Initiate string with a different order of supported codecs.
-// Should accept the supported ones, but with our desired order.
-const std::string kGingleInitiateDifferentPreference(
- "<iq xmlns='jabber:client' from='me@domain.com/resource' " \
- " to='user@domain.com/resource' type='set' id='123'> " \
- " <session xmlns='http://www.google.com/session' type='initiate'" \
- " id='abcdef' initiator='me@domain.com/resource'> " \
- " <description xmlns='http://www.google.com/session/phone'> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='104' name='ISAC' clockrate='32000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='97' name='IPCMWB' clockrate='16000' bitrate='80000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='9' name='G722' clockrate='16000' bitrate='64000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='119' name='ISACLC' clockrate='16000' bitrate='40000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='103' name='ISAC' clockrate='16000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='99' name='speex' clockrate='16000' bitrate='22000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='100' name='EG711U' clockrate='8000' bitrate='64000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='101' name='EG711A' clockrate='8000' bitrate='64000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='0' name='PCMU' clockrate='8000' bitrate='64000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='8' name='PCMA' clockrate='8000' bitrate='64000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='102' name='iLBC' clockrate='8000' bitrate='13300' />" \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='3' name='GSM' clockrate='8000' bitrate='13000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='98' name='speex' clockrate='8000' bitrate='11000' />" \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='126' name='CN' clockrate='32000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='105' name='CN' clockrate='16000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='13' name='CN' clockrate='8000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='117' name='red' clockrate='8000' /> " \
- " <payload-type xmlns='http://www.google.com/session/phone' " \
- " id='106' name='telephone-event' clockrate='8000' /> " \
- " </description> " \
- " </session> " \
- "</iq> ");
-
-const std::string kJingleInitiateDifferentPreference(
- "<iq xmlns='jabber:client' from='me@domain.com/resource' " \
- " to='user@domain.com/resource' type='set' id='123'> " \
- " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \
- " sid='abcdef' initiator='me@domain.com/resource'> " \
- " <content name='test audio'> " \
- " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \
- " <payload-type id='104' name='ISAC' clockrate='32000'/> " \
- " <payload-type " \
- " id='97' name='IPCMWB' clockrate='16000'> " \
- " <parameter name='bitrate' value='80000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='9' name='G722' clockrate='16000'> " \
- " <parameter name='bitrate' value='64000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='119' name='ISACLC' clockrate='16000'> " \
- " <parameter name='bitrate' value='40000'/> " \
- " </payload-type> " \
- " <payload-type id='103' name='ISAC' clockrate='16000'/> " \
- " <payload-type " \
- " id='99' name='speex' clockrate='16000'> " \
- " <parameter name='bitrate' value='22000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='100' name='EG711U' clockrate='8000'> " \
- " <parameter name='bitrate' value='64000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='101' name='EG711A' clockrate='8000'> " \
- " <parameter name='bitrate' value='64000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='0' name='PCMU' clockrate='8000'> " \
- " <parameter name='bitrate' value='64000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='8' name='PCMA' clockrate='8000'> " \
- " <parameter name='bitrate' value='64000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='102' name='iLBC' clockrate='8000'> " \
- " <parameter name='bitrate' value='13300'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='3' name='GSM' clockrate='8000'> " \
- " <parameter name='bitrate' value='13000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='98' name='speex' clockrate='8000'> " \
- " <parameter name='bitrate' value='11000'/> " \
- " </payload-type> " \
- " <payload-type " \
- " id='126' name='CN' clockrate='32000' /> " \
- " <payload-type " \
- " id='105' name='CN' clockrate='16000' /> " \
- " <payload-type " \
- " id='13' name='CN' clockrate='8000' /> " \
- " <payload-type " \
- " id='117' name='red' clockrate='8000' /> " \
- " <payload-type " \
- " id='106' name='telephone-event' clockrate='8000' /> " \
- " </description> " \
- " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \
- " </content> " \
- " </jingle> " \
- "</iq> ");
-
const std::string kJingleInitiateWithRtcpFb(
"<iq xmlns='jabber:client' from='me@domain.com/resource' " \
" to='user@domain.com/resource' type='set' id='123'> " \
@@ -2793,6 +2700,8 @@
expected_data_fb_params_ = params_nack;
}
+ cricket::FakeMediaEngine* fme() { return fme_; }
+
private:
void OnSendStanza(cricket::SessionManager* manager,
const buzz::XmlElement* stanza) {
@@ -2949,11 +2858,15 @@
test->TestHasAllSupportedAudioCodecs(elem.get());
}
+// Changes the codecs that our FakeMediaEngine will support with a different
+// preference order than the incoming offer.
+// Verifies the answer accepts the preference order of the remote peer.
TEST(MediaSessionTest, JingleGoodInitiateDifferentPreferenceAudioCodecs) {
talk_base::scoped_ptr<MediaSessionClientTest> test(JingleTest());
+ test->fme()->SetAudioCodecs(MAKE_VECTOR(kAudioCodecsDifferentPreference));
talk_base::scoped_ptr<buzz::XmlElement> elem;
test->TestGoodIncomingInitiate(
- kJingleInitiateDifferentPreference, AudioCallOptions(), elem.use());
+ kJingleInitiate, AudioCallOptions(), elem.use());
test->TestHasAllSupportedAudioCodecs(elem.get());
}
@@ -3213,11 +3126,15 @@
test->TestHasAllSupportedAudioCodecs(elem.get());
}
+// Changes the codecs that our FakeMediaEngine will support with a different
+// preference order than the incoming offer.
+// Verifies the answer accepts the preference order of the remote peer.
TEST(MediaSessionTest, GingleGoodInitiateDifferentPreferenceAudioCodecs) {
- talk_base::scoped_ptr<buzz::XmlElement> elem;
talk_base::scoped_ptr<MediaSessionClientTest> test(GingleTest());
+ test->fme()->SetAudioCodecs(MAKE_VECTOR(kAudioCodecsDifferentPreference));
+ talk_base::scoped_ptr<buzz::XmlElement> elem;
test->TestGoodIncomingInitiate(
- kGingleInitiateDifferentPreference, AudioCallOptions(), elem.use());
+ kGingleInitiate, AudioCallOptions(), elem.use());
test->TestHasAllSupportedAudioCodecs(elem.get());
}