(Auto)update libjingle 66138442-> 66236292

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6057 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
buildbot@webrtc.org 2014-05-05 20:18:08 +00:00
parent 382c0c209d
commit 5ee0f05d5f
8 changed files with 271 additions and 188 deletions

View File

@ -1114,6 +1114,8 @@
'session/tunnel/securetunnelsessionclient.h', 'session/tunnel/securetunnelsessionclient.h',
'session/media/audiomonitor.cc', 'session/media/audiomonitor.cc',
'session/media/audiomonitor.h', 'session/media/audiomonitor.h',
'session/media/bundlefilter.cc',
'session/media/bundlefilter.h',
'session/media/call.cc', 'session/media/call.cc',
'session/media/call.h', 'session/media/call.h',
'session/media/channel.cc', 'session/media/channel.cc',
@ -1139,8 +1141,6 @@
'session/media/soundclip.h', 'session/media/soundclip.h',
'session/media/srtpfilter.cc', 'session/media/srtpfilter.cc',
'session/media/srtpfilter.h', 'session/media/srtpfilter.h',
'session/media/ssrcmuxfilter.cc',
'session/media/ssrcmuxfilter.h',
'session/media/typingmonitor.cc', 'session/media/typingmonitor.cc',
'session/media/typingmonitor.h', 'session/media/typingmonitor.h',
'session/media/voicechannel.h', 'session/media/voicechannel.h',

View File

@ -357,6 +357,7 @@
'p2p/client/connectivitychecker_unittest.cc', 'p2p/client/connectivitychecker_unittest.cc',
'p2p/client/fakeportallocator.h', 'p2p/client/fakeportallocator.h',
'p2p/client/portallocator_unittest.cc', 'p2p/client/portallocator_unittest.cc',
'session/media/bundlefilter_unittest.cc',
'session/media/channel_unittest.cc', 'session/media/channel_unittest.cc',
'session/media/channelmanager_unittest.cc', 'session/media/channelmanager_unittest.cc',
'session/media/currentspeakermonitor_unittest.cc', 'session/media/currentspeakermonitor_unittest.cc',
@ -366,7 +367,6 @@
'session/media/mediasessionclient_unittest.cc', 'session/media/mediasessionclient_unittest.cc',
'session/media/rtcpmuxfilter_unittest.cc', 'session/media/rtcpmuxfilter_unittest.cc',
'session/media/srtpfilter_unittest.cc', 'session/media/srtpfilter_unittest.cc',
'session/media/ssrcmuxfilter_unittest.cc',
], ],
'conditions': [ 'conditions': [
['OS=="win"', { ['OS=="win"', {

View File

@ -25,9 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "talk/session/media/ssrcmuxfilter.h" #include "talk/session/media/bundlefilter.h"
#include <algorithm>
#include "talk/base/logging.h" #include "talk/base/logging.h"
#include "talk/media/base/rtputils.h" #include "talk/media/base/rtputils.h"
@ -36,41 +34,52 @@ namespace cricket {
static const uint32 kSsrc01 = 0x01; static const uint32 kSsrc01 = 0x01;
SsrcMuxFilter::SsrcMuxFilter() { BundleFilter::BundleFilter() {
} }
SsrcMuxFilter::~SsrcMuxFilter() { BundleFilter::~BundleFilter() {
} }
bool SsrcMuxFilter::IsActive() const { bool BundleFilter::DemuxPacket(const char* data, size_t len, bool rtcp) {
return !streams_.empty(); // For rtp packets, we check whether the payload type can be found.
} // For rtcp packets, we check whether the ssrc can be found or is the special
// value 1 except for SDES packets which always pass through. Plus, if
bool SsrcMuxFilter::DemuxPacket(const char* data, size_t len, bool rtcp) { // |streams_| is empty, we will allow all rtcp packets pass through provided
uint32 ssrc = 0; // that they are valid rtcp packets in case that they are for early media.
if (!rtcp) { if (!rtcp) {
GetRtpSsrc(data, len, &ssrc); int payload_type = 0;
if (!GetRtpPayloadType(data, len, &payload_type)) {
return false;
}
return FindPayloadType(payload_type);
}
// Rtcp packets using ssrc filter.
int pl_type = 0;
uint32 ssrc = 0;
if (!GetRtcpType(data, len, &pl_type)) return false;
if (pl_type == kRtcpTypeSDES) {
// SDES packet parsing not supported.
LOG(LS_INFO) << "SDES packet received for demux.";
return true;
} else { } else {
int pl_type = 0; if (!GetRtcpSsrc(data, len, &ssrc)) return false;
if (!GetRtcpType(data, len, &pl_type)) return false; if (ssrc == kSsrc01) {
if (pl_type == kRtcpTypeSDES) { // SSRC 1 has a special meaning and indicates generic feedback on
// SDES packet parsing not supported. // some systems and should never be dropped. If it is forwarded
LOG(LS_INFO) << "SDES packet received for demux."; // incorrectly it will be ignored by lower layers anyway.
return true; return true;
} else {
if (!GetRtcpSsrc(data, len, &ssrc)) return false;
if (ssrc == kSsrc01) {
// SSRC 1 has a special meaning and indicates generic feedback on
// some systems and should never be dropped. If it is forwarded
// incorrectly it will be ignored by lower layers anyway.
return true;
}
} }
} }
return FindStream(ssrc); // Pass through if |streams_| is empty to allow early rtcp packets in.
return !HasStreams() || FindStream(ssrc);
} }
bool SsrcMuxFilter::AddStream(const StreamParams& stream) { void BundleFilter::AddPayloadType(int payload_type) {
payload_types_.insert(payload_type);
}
bool BundleFilter::AddStream(const StreamParams& stream) {
if (GetStreamBySsrc(streams_, stream.first_ssrc(), NULL)) { if (GetStreamBySsrc(streams_, stream.first_ssrc(), NULL)) {
LOG(LS_WARNING) << "Stream already added to filter"; LOG(LS_WARNING) << "Stream already added to filter";
return false; return false;
@ -79,15 +88,27 @@ bool SsrcMuxFilter::AddStream(const StreamParams& stream) {
return true; return true;
} }
bool SsrcMuxFilter::RemoveStream(uint32 ssrc) { bool BundleFilter::RemoveStream(uint32 ssrc) {
return RemoveStreamBySsrc(&streams_, ssrc); return RemoveStreamBySsrc(&streams_, ssrc);
} }
bool SsrcMuxFilter::FindStream(uint32 ssrc) const { bool BundleFilter::HasStreams() const {
return !streams_.empty();
}
bool BundleFilter::FindStream(uint32 ssrc) const {
if (ssrc == 0) { if (ssrc == 0) {
return false; return false;
} }
return (GetStreamBySsrc(streams_, ssrc, NULL)); return (GetStreamBySsrc(streams_, ssrc, NULL));
} }
bool BundleFilter::FindPayloadType(int pl_type) const {
return payload_types_.find(pl_type) != payload_types_.end();
}
void BundleFilter::ClearAllPayloadTypes() {
payload_types_.clear();
}
} // namespace cricket } // namespace cricket

View File

@ -25,9 +25,10 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef TALK_SESSION_MEDIA_SSRCMUXFILTER_H_ #ifndef TALK_SESSION_MEDIA_BUNDLEFILTER_H_
#define TALK_SESSION_MEDIA_SSRCMUXFILTER_H_ #define TALK_SESSION_MEDIA_BUNDLEFILTER_H_
#include <set>
#include <vector> #include <vector>
#include "talk/base/basictypes.h" #include "talk/base/basictypes.h"
@ -35,33 +36,45 @@
namespace cricket { namespace cricket {
// This class maintains list of recv SSRC's destined for cricket::BaseChannel.
// In case of single RTP session and single transport channel, all session // In case of single RTP session and single transport channel, all session
// ( or media) channels share a common transport channel. Hence they all get // ( or media) channels share a common transport channel. Hence they all get
// SignalReadPacket when packet received on transport channel. This requires // SignalReadPacket when packet received on transport channel. This requires
// cricket::BaseChannel to know all the valid sources, else media channel // cricket::BaseChannel to know all the valid sources, else media channel
// will decode invalid packets. // will decode invalid packets.
class SsrcMuxFilter { //
// This class determines whether a packet is destined for cricket::BaseChannel.
// For rtp packets, this is decided based on the payload type. For rtcp packets,
// this is decided based on the sender ssrc values.
class BundleFilter {
public: public:
SsrcMuxFilter(); BundleFilter();
~SsrcMuxFilter(); ~BundleFilter();
// Whether the rtp mux is active for a sdp session.
// Returns true if the filter contains a stream.
bool IsActive() const;
// Determines packet belongs to valid cricket::BaseChannel. // Determines packet belongs to valid cricket::BaseChannel.
bool DemuxPacket(const char* data, size_t len, bool rtcp); bool DemuxPacket(const char* data, size_t len, bool rtcp);
// Adds the supported payload type.
void AddPayloadType(int payload_type);
// Adding a valid source to the filter. // Adding a valid source to the filter.
bool AddStream(const StreamParams& stream); bool AddStream(const StreamParams& stream);
// Removes source from the filter. // Removes source from the filter.
bool RemoveStream(uint32 ssrc); bool RemoveStream(uint32 ssrc);
// Utility method added for unitest.
// Utility methods added for unitest.
// True if |streams_| is not empty.
bool HasStreams() const;
bool FindStream(uint32 ssrc) const; bool FindStream(uint32 ssrc) const;
bool FindPayloadType(int pl_type) const;
void ClearAllPayloadTypes();
private: private:
std::set<int> payload_types_;
std::vector<StreamParams> streams_; std::vector<StreamParams> streams_;
}; };
} // namespace cricket } // namespace cricket
#endif // TALK_SESSION_MEDIA_SSRCMUXFILTER_H_ #endif // TALK_SESSION_MEDIA_BUNDLEFILTER_H_

View File

@ -25,34 +25,34 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "talk/base/gunit.h" #include "talk/base/gunit.h"
#include "talk/session/media/ssrcmuxfilter.h" #include "talk/session/media/bundlefilter.h"
using cricket::StreamParams;
static const int kSsrc1 = 0x1111; static const int kSsrc1 = 0x1111;
static const int kSsrc2 = 0x2222; static const int kSsrc2 = 0x2222;
static const int kSsrc3 = 0x3333; static const int kSsrc3 = 0x3333;
static const int kPayloadType1 = 0x11;
static const int kPayloadType2 = 0x22;
static const int kPayloadType3 = 0x33;
using cricket::StreamParams; // SSRC = 0x1111, Payload type = 0x11
static const unsigned char kRtpPacketPt1Ssrc1[] = {
// SSRC = 0x1111 0x80, kPayloadType1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
static const unsigned char kRtpPacketSsrc1[] = { 0x11,
0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,
}; };
// SSRC = 0x2222 // SSRC = 0x2222, Payload type = 0x22
static const unsigned char kRtpPacketSsrc2[] = { static const unsigned char kRtpPacketPt2Ssrc2[] = {
0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x80, 0x80 + kPayloadType2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x22, 0x22,
}; };
// SSRC = 0 // SSRC = 0x2222, Payload type = 0x33
static const unsigned char kRtpPacketInvalidSsrc[] = { static const unsigned char kRtpPacketPt3Ssrc2[] = {
0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, kPayloadType3, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22,
}; 0x22,
// invalid size
static const unsigned char kRtpPacketTooSmall[] = {
0x80, 0x80, 0x00, 0x00,
}; };
// PT = 200 = SR, len = 28, SSRC of sender = 0x0001 // PT = 200 = SR, len = 28, SSRC of sender = 0x0001
@ -105,80 +105,92 @@ static const unsigned char kRtcpPacketNonCompoundRtcpPliFeedback[] = {
0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11,
}; };
TEST(SsrcMuxFilterTest, AddRemoveStreamTest) { TEST(BundleFilterTest, AddRemoveStreamTest) {
cricket::SsrcMuxFilter ssrc_filter; cricket::BundleFilter bundle_filter;
EXPECT_FALSE(ssrc_filter.IsActive()); EXPECT_FALSE(bundle_filter.HasStreams());
EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc1))); EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
StreamParams stream2; StreamParams stream2;
stream2.ssrcs.push_back(kSsrc2); stream2.ssrcs.push_back(kSsrc2);
stream2.ssrcs.push_back(kSsrc3); stream2.ssrcs.push_back(kSsrc3);
EXPECT_TRUE(ssrc_filter.AddStream(stream2)); EXPECT_TRUE(bundle_filter.AddStream(stream2));
EXPECT_TRUE(ssrc_filter.IsActive()); EXPECT_TRUE(bundle_filter.HasStreams());
EXPECT_TRUE(ssrc_filter.FindStream(kSsrc1)); EXPECT_TRUE(bundle_filter.FindStream(kSsrc1));
EXPECT_TRUE(ssrc_filter.FindStream(kSsrc2)); EXPECT_TRUE(bundle_filter.FindStream(kSsrc2));
EXPECT_TRUE(ssrc_filter.FindStream(kSsrc3)); EXPECT_TRUE(bundle_filter.FindStream(kSsrc3));
EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc1)); EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc1));
EXPECT_FALSE(ssrc_filter.FindStream(kSsrc1)); EXPECT_FALSE(bundle_filter.FindStream(kSsrc1));
EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc3)); EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc3));
EXPECT_FALSE(ssrc_filter.RemoveStream(kSsrc2)); // Already removed. EXPECT_FALSE(bundle_filter.RemoveStream(kSsrc2)); // Already removed.
EXPECT_FALSE(ssrc_filter.IsActive()); EXPECT_FALSE(bundle_filter.HasStreams());
} }
TEST(SsrcMuxFilterTest, RtpPacketTest) { TEST(BundleFilterTest, RtpPacketTest) {
cricket::SsrcMuxFilter ssrc_filter; cricket::BundleFilter bundle_filter;
EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc1))); bundle_filter.AddPayloadType(kPayloadType1);
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtpPacketSsrc1), reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1),
sizeof(kRtpPacketSsrc1), false)); sizeof(kRtpPacketPt1Ssrc1), false));
EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc2))); bundle_filter.AddPayloadType(kPayloadType2);
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtpPacketSsrc2), reinterpret_cast<const char*>(kRtpPacketPt2Ssrc2),
sizeof(kRtpPacketSsrc2), false)); sizeof(kRtpPacketPt2Ssrc2), false));
EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc2));
EXPECT_FALSE(ssrc_filter.DemuxPacket( // Payload type 0x33 is not added.
reinterpret_cast<const char*>(kRtpPacketSsrc2), EXPECT_FALSE(bundle_filter.DemuxPacket(
sizeof(kRtpPacketSsrc2), false)); reinterpret_cast<const char*>(kRtpPacketPt3Ssrc2),
EXPECT_FALSE(ssrc_filter.DemuxPacket( sizeof(kRtpPacketPt3Ssrc2), false));
reinterpret_cast<const char*>(kRtpPacketInvalidSsrc), // Size is too small.
sizeof(kRtpPacketInvalidSsrc), false)); EXPECT_FALSE(bundle_filter.DemuxPacket(
EXPECT_FALSE(ssrc_filter.DemuxPacket( reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1), 11, false));
reinterpret_cast<const char*>(kRtpPacketTooSmall),
sizeof(kRtpPacketTooSmall), false)); bundle_filter.ClearAllPayloadTypes();
EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtpPacketPt1Ssrc1),
sizeof(kRtpPacketPt1Ssrc1), false));
EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtpPacketPt2Ssrc2),
sizeof(kRtpPacketPt2Ssrc2), false));
} }
TEST(SsrcMuxFilterTest, RtcpPacketTest) { TEST(BundleFilterTest, RtcpPacketTest) {
cricket::SsrcMuxFilter ssrc_filter; cricket::BundleFilter bundle_filter;
EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc1))); EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc1)));
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketCompoundSrSdesSsrc1), reinterpret_cast<const char*>(kRtcpPacketCompoundSrSdesSsrc1),
sizeof(kRtcpPacketCompoundSrSdesSsrc1), true)); sizeof(kRtcpPacketCompoundSrSdesSsrc1), true));
EXPECT_TRUE(ssrc_filter.AddStream(StreamParams::CreateLegacy(kSsrc2))); EXPECT_TRUE(bundle_filter.AddStream(StreamParams::CreateLegacy(kSsrc2)));
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc2), reinterpret_cast<const char*>(kRtcpPacketSrSsrc2),
sizeof(kRtcpPacketSrSsrc2), true)); sizeof(kRtcpPacketSrSsrc2), true));
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2), reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2),
sizeof(kRtcpPacketSdesSsrc2), true)); sizeof(kRtcpPacketSdesSsrc2), true));
EXPECT_TRUE(ssrc_filter.RemoveStream(kSsrc2)); EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc2));
// RTCP Packets other than SR and RR are demuxed regardless of SSRC. // RTCP Packets other than SR and RR are demuxed regardless of SSRC.
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2), reinterpret_cast<const char*>(kRtcpPacketSdesSsrc2),
sizeof(kRtcpPacketSdesSsrc2), true)); sizeof(kRtcpPacketSdesSsrc2), true));
// RTCP Packets with 'special' SSRC 0x01 are demuxed also // RTCP Packets with 'special' SSRC 0x01 are demuxed also
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc01), reinterpret_cast<const char*>(kRtcpPacketSrSsrc01),
sizeof(kRtcpPacketSrSsrc01), true)); sizeof(kRtcpPacketSrSsrc01), true));
EXPECT_FALSE(ssrc_filter.DemuxPacket( EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc2), reinterpret_cast<const char*>(kRtcpPacketSrSsrc2),
sizeof(kRtcpPacketSrSsrc2), true)); sizeof(kRtcpPacketSrSsrc2), true));
EXPECT_FALSE(ssrc_filter.DemuxPacket( EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketFixedHeaderOnly), reinterpret_cast<const char*>(kRtcpPacketFixedHeaderOnly),
sizeof(kRtcpPacketFixedHeaderOnly), true)); sizeof(kRtcpPacketFixedHeaderOnly), true));
EXPECT_FALSE(ssrc_filter.DemuxPacket( EXPECT_FALSE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketTooSmall), reinterpret_cast<const char*>(kRtcpPacketTooSmall),
sizeof(kRtcpPacketTooSmall), true)); sizeof(kRtcpPacketTooSmall), true));
EXPECT_TRUE(ssrc_filter.DemuxPacket( EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketNonCompoundRtcpPliFeedback), reinterpret_cast<const char*>(kRtcpPacketNonCompoundRtcpPliFeedback),
sizeof(kRtcpPacketNonCompoundRtcpPliFeedback), true)); sizeof(kRtcpPacketNonCompoundRtcpPliFeedback), true));
// If the streams_ is empty, rtcp packet passes through
EXPECT_TRUE(bundle_filter.RemoveStream(kSsrc1));
EXPECT_FALSE(bundle_filter.HasStreams());
EXPECT_TRUE(bundle_filter.DemuxPacket(
reinterpret_cast<const char*>(kRtcpPacketSrSsrc2),
sizeof(kRtcpPacketSrSsrc2), true));
} }

View File

@ -38,7 +38,6 @@
#include "talk/p2p/base/transportchannel.h" #include "talk/p2p/base/transportchannel.h"
#include "talk/session/media/channelmanager.h" #include "talk/session/media/channelmanager.h"
#include "talk/session/media/mediamessages.h" #include "talk/session/media/mediamessages.h"
#include "talk/session/media/rtcpmuxfilter.h"
#include "talk/session/media/typingmonitor.h" #include "talk/session/media/typingmonitor.h"
@ -559,15 +558,9 @@ bool BaseChannel::WantsPacket(bool rtcp, talk_base::Buffer* packet) {
<< packet->length(); << packet->length();
return false; return false;
} }
// If this channel is suppose to handle RTP data, that is determined by
// checking against ssrc filter. This is necessary to do it here to avoid
// double decryption.
if (ssrc_filter_.IsActive() &&
!ssrc_filter_.DemuxPacket(packet->data(), packet->length(), rtcp)) {
return false;
}
return true; // Bundle filter handles both rtp and rtcp packets.
return bundle_filter_.DemuxPacket(packet->data(), packet->length(), rtcp);
} }
void BaseChannel::HandlePacket(bool rtcp, talk_base::Buffer* packet, void BaseChannel::HandlePacket(bool rtcp, talk_base::Buffer* packet,
@ -996,12 +989,12 @@ bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
if (!media_channel()->AddRecvStream(sp)) if (!media_channel()->AddRecvStream(sp))
return false; return false;
return ssrc_filter_.AddStream(sp); return bundle_filter_.AddStream(sp);
} }
bool BaseChannel::RemoveRecvStream_w(uint32 ssrc) { bool BaseChannel::RemoveRecvStream_w(uint32 ssrc) {
ASSERT(worker_thread() == talk_base::Thread::Current()); ASSERT(worker_thread() == talk_base::Thread::Current());
ssrc_filter_.RemoveStream(ssrc); bundle_filter_.RemoveStream(ssrc);
return media_channel()->RemoveRecvStream(ssrc); return media_channel()->RemoveRecvStream(ssrc);
} }
@ -1479,6 +1472,10 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
// If everything worked, see if we can start receiving. // If everything worked, see if we can start receiving.
if (ret) { if (ret) {
std::vector<AudioCodec>::const_iterator it = audio->codecs().begin();
for (; it != audio->codecs().end(); ++it) {
bundle_filter()->AddPayloadType(it->id);
}
ChangeState(); ChangeState();
} else { } else {
LOG(LS_WARNING) << "Failed to set local voice description"; LOG(LS_WARNING) << "Failed to set local voice description";
@ -1844,6 +1841,10 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
// If everything worked, see if we can start receiving. // If everything worked, see if we can start receiving.
if (ret) { if (ret) {
std::vector<VideoCodec>::const_iterator it = video->codecs().begin();
for (; it != video->codecs().end(); ++it) {
bundle_filter()->AddPayloadType(it->id);
}
ChangeState(); ChangeState();
} else { } else {
LOG(LS_WARNING) << "Failed to set local video description"; LOG(LS_WARNING) << "Failed to set local video description";
@ -2249,7 +2250,6 @@ bool DataChannel::SetLocalContent_w(const MediaContentDescription* content,
} }
} else { } else {
ret = SetBaseLocalContent_w(content, action, error_desc); ret = SetBaseLocalContent_w(content, action, error_desc);
if (action != CA_UPDATE || data->has_codecs()) { if (action != CA_UPDATE || data->has_codecs()) {
if (!media_channel()->SetRecvCodecs(data->codecs())) { if (!media_channel()->SetRecvCodecs(data->codecs())) {
SafeSetError("Failed to set data receive codecs.", error_desc); SafeSetError("Failed to set data receive codecs.", error_desc);
@ -2260,6 +2260,10 @@ bool DataChannel::SetLocalContent_w(const MediaContentDescription* content,
// If everything worked, see if we can start receiving. // If everything worked, see if we can start receiving.
if (ret) { if (ret) {
std::vector<DataCodec>::const_iterator it = data->codecs().begin();
for (; it != data->codecs().end(); ++it) {
bundle_filter()->AddPayloadType(it->id);
}
ChangeState(); ChangeState();
} else { } else {
LOG(LS_WARNING) << "Failed to set local data description"; LOG(LS_WARNING) << "Failed to set local data description";

View File

@ -44,11 +44,11 @@
#include "talk/p2p/base/session.h" #include "talk/p2p/base/session.h"
#include "talk/p2p/client/socketmonitor.h" #include "talk/p2p/client/socketmonitor.h"
#include "talk/session/media/audiomonitor.h" #include "talk/session/media/audiomonitor.h"
#include "talk/session/media/bundlefilter.h"
#include "talk/session/media/mediamonitor.h" #include "talk/session/media/mediamonitor.h"
#include "talk/session/media/mediasession.h" #include "talk/session/media/mediasession.h"
#include "talk/session/media/rtcpmuxfilter.h" #include "talk/session/media/rtcpmuxfilter.h"
#include "talk/session/media/srtpfilter.h" #include "talk/session/media/srtpfilter.h"
#include "talk/session/media/ssrcmuxfilter.h"
namespace cricket { namespace cricket {
@ -213,7 +213,7 @@ class BaseChannel
} }
} }
SsrcMuxFilter* ssrc_filter() { return &ssrc_filter_; } BundleFilter* bundle_filter() { return &bundle_filter_; }
const std::vector<StreamParams>& local_streams() const { const std::vector<StreamParams>& local_streams() const {
return local_streams_; return local_streams_;
@ -372,7 +372,7 @@ class BaseChannel
TransportChannel* rtcp_transport_channel_; TransportChannel* rtcp_transport_channel_;
SrtpFilter srtp_filter_; SrtpFilter srtp_filter_;
RtcpMuxFilter rtcp_mux_filter_; RtcpMuxFilter rtcp_mux_filter_;
SsrcMuxFilter ssrc_filter_; BundleFilter bundle_filter_;
talk_base::scoped_ptr<SocketMonitor> socket_monitor_; talk_base::scoped_ptr<SocketMonitor> socket_monitor_;
bool enabled_; bool enabled_;
bool writable_; bool writable_;

View File

@ -71,6 +71,8 @@ static const cricket::DataCodec kGoogleDataCodec(101, "google-data", 0);
static const uint32 kSsrc1 = 0x1111; static const uint32 kSsrc1 = 0x1111;
static const uint32 kSsrc2 = 0x2222; static const uint32 kSsrc2 = 0x2222;
static const uint32 kSsrc3 = 0x3333; static const uint32 kSsrc3 = 0x3333;
static const int kAudioPts[] = {0, 8};
static const int kVideoPts[] = {97, 99};
template<class ChannelT, template<class ChannelT,
class MediaChannelT, class MediaChannelT,
@ -408,13 +410,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
static_cast<int>(rtcp_packet_.size())); static_cast<int>(rtcp_packet_.size()));
} }
// Methods to send custom data. // Methods to send custom data.
bool SendCustomRtp1(uint32 ssrc, int sequence_number) { bool SendCustomRtp1(uint32 ssrc, int sequence_number, int pl_type = -1) {
std::string data(CreateRtpData(ssrc, sequence_number)); std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel1_->SendRtp(data.c_str(), return media_channel1_->SendRtp(data.c_str(),
static_cast<int>(data.size())); static_cast<int>(data.size()));
} }
bool SendCustomRtp2(uint32 ssrc, int sequence_number) { bool SendCustomRtp2(uint32 ssrc, int sequence_number, int pl_type = -1) {
std::string data(CreateRtpData(ssrc, sequence_number)); std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel2_->SendRtp(data.c_str(), return media_channel2_->SendRtp(data.c_str(),
static_cast<int>(data.size())); static_cast<int>(data.size()));
} }
@ -445,13 +447,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
static_cast<int>(rtcp_packet_.size())); static_cast<int>(rtcp_packet_.size()));
} }
// Methods to check custom data. // Methods to check custom data.
bool CheckCustomRtp1(uint32 ssrc, int sequence_number) { bool CheckCustomRtp1(uint32 ssrc, int sequence_number, int pl_type = -1 ) {
std::string data(CreateRtpData(ssrc, sequence_number)); std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel1_->CheckRtp(data.c_str(), return media_channel1_->CheckRtp(data.c_str(),
static_cast<int>(data.size())); static_cast<int>(data.size()));
} }
bool CheckCustomRtp2(uint32 ssrc, int sequence_number) { bool CheckCustomRtp2(uint32 ssrc, int sequence_number, int pl_type = -1) {
std::string data(CreateRtpData(ssrc, sequence_number)); std::string data(CreateRtpData(ssrc, sequence_number, pl_type));
return media_channel2_->CheckRtp(data.c_str(), return media_channel2_->CheckRtp(data.c_str(),
static_cast<int>(data.size())); static_cast<int>(data.size()));
} }
@ -465,11 +467,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
return media_channel2_->CheckRtcp(data.c_str(), return media_channel2_->CheckRtcp(data.c_str(),
static_cast<int>(data.size())); static_cast<int>(data.size()));
} }
std::string CreateRtpData(uint32 ssrc, int sequence_number) { std::string CreateRtpData(uint32 ssrc, int sequence_number, int pl_type) {
std::string data(rtp_packet_); std::string data(rtp_packet_);
// Set SSRC in the rtp packet copy. // Set SSRC in the rtp packet copy.
talk_base::SetBE32(const_cast<char*>(data.c_str()) + 8, ssrc); talk_base::SetBE32(const_cast<char*>(data.c_str()) + 8, ssrc);
talk_base::SetBE16(const_cast<char*>(data.c_str()) + 2, sequence_number); talk_base::SetBE16(const_cast<char*>(data.c_str()) + 2, sequence_number);
if (pl_type >= 0) {
talk_base::Set8(const_cast<char*>(data.c_str()), 1, pl_type);
}
return data; return data;
} }
std::string CreateRtcpData(uint32 ssrc) { std::string CreateRtcpData(uint32 ssrc) {
@ -1438,60 +1443,63 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(CheckNoRtp2()); EXPECT_TRUE(CheckNoRtp2());
} }
void SendSsrcMuxToSsrcMuxWithRtcpMux() { void SendBundleToBundle(
const int* pl_types, int len, bool rtcp_mux, bool secure) {
ASSERT_EQ(2, len);
int sequence_number1_1 = 0, sequence_number2_2 = 0; int sequence_number1_1 = 0, sequence_number2_2 = 0;
CreateChannels(SSRC_MUX | RTCP | RTCP_MUX, SSRC_MUX | RTCP | RTCP_MUX); // Only pl_type1 was added to the bundle filter for both |channel1_|
// and |channel2_|.
int pl_type1 = pl_types[0];
int pl_type2 = pl_types[1];
int flags = SSRC_MUX | RTCP;
if (secure) flags |= SECURE;
uint32 expected_channels = 2U;
if (rtcp_mux) {
flags |= RTCP_MUX;
expected_channels = 1U;
}
CreateChannels(flags, flags);
EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendInitiate());
EXPECT_EQ(2U, GetTransport1()->channels().size()); EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size()); EXPECT_EQ(expected_channels, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept()); EXPECT_TRUE(SendAccept());
EXPECT_EQ(1U, GetTransport1()->channels().size()); EXPECT_EQ(expected_channels, GetTransport1()->channels().size());
EXPECT_EQ(1U, GetTransport2()->channels().size()); EXPECT_EQ(expected_channels, GetTransport2()->channels().size());
EXPECT_TRUE(channel1_->ssrc_filter()->IsActive()); EXPECT_TRUE(channel1_->bundle_filter()->FindPayloadType(pl_type1));
// channel1 - should have media_content2 as remote. i.e. kSsrc2 EXPECT_TRUE(channel2_->bundle_filter()->FindPayloadType(pl_type1));
EXPECT_TRUE(channel1_->ssrc_filter()->FindStream(kSsrc2)); EXPECT_FALSE(channel1_->bundle_filter()->FindPayloadType(pl_type2));
EXPECT_TRUE(channel2_->ssrc_filter()->IsActive()); EXPECT_FALSE(channel2_->bundle_filter()->FindPayloadType(pl_type2));
// channel2 - should have media_content1 as remote. i.e. kSsrc1 // channel1 - should only have media_content2 as remote. i.e. kSsrc2
EXPECT_TRUE(channel2_->ssrc_filter()->FindStream(kSsrc1)); EXPECT_TRUE(channel1_->bundle_filter()->FindStream(kSsrc2));
EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1)); EXPECT_FALSE(channel1_->bundle_filter()->FindStream(kSsrc1));
EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2)); // channel2 - should only have media_content1 as remote. i.e. kSsrc1
EXPECT_TRUE(channel2_->bundle_filter()->FindStream(kSsrc1));
EXPECT_FALSE(channel2_->bundle_filter()->FindStream(kSsrc2));
// Both channels can receive pl_type1 only.
EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type1));
EXPECT_TRUE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type1));
EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type1));
EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type1));
EXPECT_TRUE(CheckNoRtp1());
EXPECT_TRUE(CheckNoRtp2());
// RTCP test
EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type2));
EXPECT_FALSE(CheckCustomRtp2(kSsrc1, sequence_number1_1, pl_type2));
EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2, pl_type2));
EXPECT_FALSE(CheckCustomRtp1(kSsrc2, sequence_number2_2, pl_type2));
EXPECT_TRUE(SendCustomRtcp1(kSsrc1)); EXPECT_TRUE(SendCustomRtcp1(kSsrc1));
EXPECT_TRUE(SendCustomRtcp2(kSsrc2)); EXPECT_TRUE(SendCustomRtcp2(kSsrc2));
EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2));
EXPECT_TRUE(CheckNoRtp1());
EXPECT_TRUE(CheckCustomRtp2(kSsrc1, sequence_number1_1));
EXPECT_TRUE(CheckNoRtp2());
EXPECT_TRUE(CheckCustomRtcp1(kSsrc2)); EXPECT_TRUE(CheckCustomRtcp1(kSsrc2));
EXPECT_TRUE(CheckNoRtcp1()); EXPECT_TRUE(CheckNoRtcp1());
EXPECT_TRUE(CheckCustomRtcp2(kSsrc1)); EXPECT_TRUE(CheckCustomRtcp2(kSsrc1));
EXPECT_TRUE(CheckNoRtcp2()); EXPECT_TRUE(CheckNoRtcp2());
}
void SendSsrcMuxToSsrcMux() { EXPECT_TRUE(SendCustomRtcp1(kSsrc2));
int sequence_number1_1 = 0, sequence_number2_2 = 0; EXPECT_TRUE(SendCustomRtcp2(kSsrc1));
CreateChannels(SSRC_MUX | RTCP, SSRC_MUX | RTCP);
EXPECT_TRUE(SendInitiate());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_TRUE(SendAccept());
EXPECT_EQ(2U, GetTransport1()->channels().size());
EXPECT_EQ(2U, GetTransport2()->channels().size());
EXPECT_TRUE(channel1_->ssrc_filter()->IsActive());
// channel1 - should have media_content2 as remote. i.e. kSsrc2
EXPECT_TRUE(channel1_->ssrc_filter()->FindStream(kSsrc2));
EXPECT_TRUE(channel2_->ssrc_filter()->IsActive());
// channel2 - should have media_content1 as remote. i.e. kSsrc1
EXPECT_TRUE(SendCustomRtp1(kSsrc1, ++sequence_number1_1));
EXPECT_TRUE(SendCustomRtp2(kSsrc2, ++sequence_number2_2));
EXPECT_TRUE(SendCustomRtcp1(kSsrc1));
EXPECT_TRUE(SendCustomRtcp2(kSsrc2));
EXPECT_TRUE(CheckCustomRtp1(kSsrc2, sequence_number2_2));
EXPECT_FALSE(CheckCustomRtp1(kSsrc1, sequence_number2_2));
EXPECT_TRUE(CheckCustomRtp2(kSsrc1, sequence_number1_1));
EXPECT_FALSE(CheckCustomRtp2(kSsrc2, sequence_number1_1));
EXPECT_TRUE(CheckCustomRtcp1(kSsrc2));
EXPECT_FALSE(CheckCustomRtcp1(kSsrc1)); EXPECT_FALSE(CheckCustomRtcp1(kSsrc1));
EXPECT_TRUE(CheckCustomRtcp2(kSsrc1));
EXPECT_FALSE(CheckCustomRtcp2(kSsrc2)); EXPECT_FALSE(CheckCustomRtcp2(kSsrc2));
} }
@ -1753,9 +1761,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> {
error_); error_);
} }
void TestSrtpError() { void TestSrtpError(int pl_type) {
static const unsigned char kBadPacket[] = { // For Audio, only pl_type 0 is added to the bundle filter.
0x84, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 // For Video, only pl_type 97 is added to the bundle filter.
// So we need to pass in pl_type so that the packet can pass through
// the bundle filter before it can be processed by the srtp filter.
// The packet is not a valid srtp packet because it is too short.
unsigned const char kBadPacket[] = {
0x84, pl_type, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
}; };
CreateChannels(RTCP | SECURE, RTCP | SECURE); CreateChannels(RTCP | SECURE, RTCP | SECURE);
EXPECT_FALSE(channel1_->secure()); EXPECT_FALSE(channel1_->secure());
@ -2277,7 +2290,7 @@ TEST_F(VoiceChannelTest, TestChangeStateError) {
} }
TEST_F(VoiceChannelTest, TestSrtpError) { TEST_F(VoiceChannelTest, TestSrtpError) {
Base::TestSrtpError(); Base::TestSrtpError(kAudioPts[0]);
} }
TEST_F(VoiceChannelTest, TestOnReadyToSend) { TEST_F(VoiceChannelTest, TestOnReadyToSend) {
@ -2389,12 +2402,22 @@ TEST_F(VoiceChannelTest, TestScaleVolumeMultiwayCall) {
EXPECT_DOUBLE_EQ(0.0, right); EXPECT_DOUBLE_EQ(0.0, right);
} }
TEST_F(VoiceChannelTest, SendSsrcMuxToSsrcMux) { TEST_F(VoiceChannelTest, SendBundleToBundle) {
Base::SendSsrcMuxToSsrcMux(); Base::SendBundleToBundle(kAudioPts, ARRAY_SIZE(kAudioPts), false, false);
} }
TEST_F(VoiceChannelTest, SendSsrcMuxToSsrcMuxWithRtcpMux) { TEST_F(VoiceChannelTest, SendBundleToBundleSecure) {
Base::SendSsrcMuxToSsrcMuxWithRtcpMux(); Base::SendBundleToBundle(kAudioPts, ARRAY_SIZE(kAudioPts), false, true);
}
TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMux) {
Base::SendBundleToBundle(
kAudioPts, ARRAY_SIZE(kAudioPts), true, false);
}
TEST_F(VoiceChannelTest, SendBundleToBundleWithRtcpMuxSecure) {
Base::SendBundleToBundle(
kAudioPts, ARRAY_SIZE(kAudioPts), true, true);
} }
TEST_F(VoiceChannelTest, TestSetChannelOptions) { TEST_F(VoiceChannelTest, TestSetChannelOptions) {
@ -2604,18 +2627,28 @@ TEST_F(VideoChannelTest, TestFlushRtcp) {
Base::TestFlushRtcp(); Base::TestFlushRtcp();
} }
TEST_F(VideoChannelTest, SendSsrcMuxToSsrcMux) { TEST_F(VideoChannelTest, SendBundleToBundle) {
Base::SendSsrcMuxToSsrcMux(); Base::SendBundleToBundle(kVideoPts, ARRAY_SIZE(kVideoPts), false, false);
} }
TEST_F(VideoChannelTest, SendSsrcMuxToSsrcMuxWithRtcpMux) { TEST_F(VideoChannelTest, SendBundleToBundleSecure) {
Base::SendSsrcMuxToSsrcMuxWithRtcpMux(); Base::SendBundleToBundle(kVideoPts, ARRAY_SIZE(kVideoPts), false, true);
}
TEST_F(VideoChannelTest, SendBundleToBundleWithRtcpMux) {
Base::SendBundleToBundle(
kVideoPts, ARRAY_SIZE(kVideoPts), true, false);
}
TEST_F(VideoChannelTest, SendBundleToBundleWithRtcpMuxSecure) {
Base::SendBundleToBundle(
kVideoPts, ARRAY_SIZE(kVideoPts), true, true);
} }
// TODO(gangji): Add VideoChannelTest.TestChangeStateError. // TODO(gangji): Add VideoChannelTest.TestChangeStateError.
TEST_F(VideoChannelTest, TestSrtpError) { TEST_F(VideoChannelTest, TestSrtpError) {
Base::TestSrtpError(); Base::TestSrtpError(kVideoPts[0]);
} }
TEST_F(VideoChannelTest, TestOnReadyToSend) { TEST_F(VideoChannelTest, TestOnReadyToSend) {