* VideoCapture refactoring.
* Bug fixes.
Review URL: https://webrtc-codereview.appspot.com/350010
git-svn-id: http://libjingle.googlecode.com/svn/trunk@108 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/app/webrtcv1/webrtcsession.cc b/talk/app/webrtcv1/webrtcsession.cc
index 057cbda..dc2364d 100644
--- a/talk/app/webrtcv1/webrtcsession.cc
+++ b/talk/app/webrtcv1/webrtcsession.cc
@@ -122,7 +122,7 @@
// Limit the amount of time that setting up a call may take.
StartTransportTimeout(kCallSetupTimeout);
// Set default secure option to SEC_REQUIRED.
- desc_factory_.set_secure(cricket::SEC_REQUIRED);
+ // desc_factory_.set_secure(cricket::SEC_REQUIRED);
return true;
}
@@ -444,9 +444,7 @@
transport_->ConnectChannels();
EnableAllStreams();
- if (!SetVideoCapture(true)) {
- return false;
- }
+ SetVideoCapture(true);
set_local_description(answer.release());
diff --git a/talk/base/stream.cc b/talk/base/stream.cc
index dbe13bd..24a97dc 100644
--- a/talk/base/stream.cc
+++ b/talk/base/stream.cc
@@ -735,6 +735,12 @@
// all events are done on the owner_ thread
}
+FifoBuffer::FifoBuffer(size_t size, Thread *owner)
+ : state_(SS_OPEN), buffer_(new char[size]), buffer_length_(size),
+ data_length_(0), read_position_(0), owner_(owner) {
+ // all events are done on the owner_ thread
+}
+
FifoBuffer::~FifoBuffer() {
}
diff --git a/talk/base/stream.h b/talk/base/stream.h
index 15a706c..808156c 100644
--- a/talk/base/stream.h
+++ b/talk/base/stream.h
@@ -129,7 +129,7 @@
// latter operation but not the former.
//
- // The following four methods are used to avoid coping data multiple times.
+ // The following four methods are used to avoid copying data multiple times.
// GetReadData returns a pointer to a buffer which is owned by the stream.
// The buffer contains data_len bytes. NULL is returned if no data is
@@ -560,6 +560,8 @@
public:
// Creates a FIFO buffer with the specified capacity.
explicit FifoBuffer(size_t length);
+ // Creates a FIFO buffer with the specified capacity and owner
+ FifoBuffer(size_t length, Thread* owner);
virtual ~FifoBuffer();
// Gets the amount of data currently readable from the buffer.
bool GetBuffered(size_t* data_len) const;
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index a31009e..4cfed14 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -248,6 +248,7 @@
"session/phone/soundclip.cc",
"session/phone/srtpfilter.cc",
"session/phone/ssrcmuxfilter.cc",
+ "session/phone/streamparams.cc",
"session/phone/videoadapter.cc",
"session/phone/videocapturer.cc",
"session/phone/videocommon.cc",
diff --git a/talk/session/phone/call.cc b/talk/session/phone/call.cc
index 4b2e229..3c770af 100644
--- a/talk/session/phone/call.cc
+++ b/talk/session/phone/call.cc
@@ -181,30 +181,28 @@
void Call::AddVoiceStream(Session *session, uint32 voice_ssrc) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel && voice_ssrc) {
- voice_channel->AddStream(voice_ssrc);
+ voice_channel->AddRecvStream(StreamParams::CreateLegacy(voice_ssrc));
}
}
void Call::AddVideoStream(Session *session, uint32 video_ssrc) {
VideoChannel *video_channel = GetVideoChannel(session);
if (video_channel && video_ssrc) {
- // TODO: Do we need the audio_ssrc here?
- // It doesn't seem to be used.
- video_channel->AddStream(video_ssrc, 0U);
+ video_channel->AddRecvStream(StreamParams::CreateLegacy(video_ssrc));
}
}
void Call::RemoveVoiceStream(Session *session, uint32 voice_ssrc) {
VoiceChannel *voice_channel = GetVoiceChannel(session);
if (voice_channel && voice_ssrc) {
- voice_channel->RemoveStream(voice_ssrc);
+ voice_channel->RemoveRecvStream(voice_ssrc);
}
}
void Call::RemoveVideoStream(Session *session, uint32 video_ssrc) {
VideoChannel *video_channel = GetVideoChannel(session);
if (video_channel && video_ssrc) {
- video_channel->RemoveStream(video_ssrc);
+ video_channel->RemoveRecvStream(video_ssrc);
}
}
@@ -239,13 +237,6 @@
VoiceChannel *voice_channel = NULL;
VideoChannel *video_channel = NULL;
- // Generate a random string for the RTCP CNAME, as stated in RFC 6222.
- // This string is only used for synchronization, and therefore is opaque.
- std::string rtcp_cname;
- if (!talk_base::CreateRandomString(16, &rtcp_cname)) {
- return false;
- }
-
const ContentInfo* audio_offer = GetFirstAudioContent(offer);
const ContentInfo* video_offer = GetFirstVideoContent(offer);
video_ = (video_offer != NULL);
@@ -257,7 +248,6 @@
// voice_channel can be NULL in case of NullVoiceEngine.
if (voice_channel) {
voice_channel_map_[session->id()] = voice_channel;
- voice_channel->SetRtcpCName(rtcp_cname);
voice_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
voice_channel->StartMediaMonitor(kMediaMonitorInterval);
} else {
@@ -271,7 +261,6 @@
// video_channel can be NULL in case of NullVideoEngine.
if (video_channel) {
video_channel_map_[session->id()] = video_channel;
- video_channel->SetRtcpCName(rtcp_cname);
video_channel->SignalMediaMonitor.connect(this, &Call::OnMediaMonitor);
video_channel->StartMediaMonitor(kMediaMonitorInterval);
} else {
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index cbd670d..a58734f 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -61,6 +61,18 @@
VideoMediaChannel::Error error;
};
+struct SsrcMessageData : public talk_base::MessageData {
+ explicit SsrcMessageData(uint32 ssrc) : ssrc(ssrc), result(false) {}
+ uint32 ssrc;
+ bool result;
+};
+
+struct StreamMessageData : public talk_base::MessageData {
+ explicit StreamMessageData(const StreamParams& sp) : sp(sp), result(false) {}
+ StreamParams sp;
+ bool result;
+};
+
static const char* PacketType(bool rtcp) {
return (!rtcp) ? "RTP" : "RTCP";
}
@@ -146,15 +158,15 @@
return true;
}
-bool BaseChannel::RemoveStream(uint32 ssrc) {
- StreamMessageData data(ssrc, 0);
- Send(MSG_REMOVESTREAM, &data);
- return true;
+bool BaseChannel::AddRecvStream(const StreamParams& sp) {
+ StreamMessageData data(sp);
+ Send(MSG_ADDRECVSTREAM, &data);
+ return data.result;
}
-bool BaseChannel::SetRtcpCName(const std::string& cname) {
- SetRtcpCNameData data(cname);
- Send(MSG_SETRTCPCNAME, &data);
+bool BaseChannel::RemoveRecvStream(uint32 ssrc) {
+ SsrcMessageData data(ssrc);
+ Send(MSG_REMOVERECVSTREAM, &data);
return data.result;
}
@@ -518,10 +530,6 @@
return media_channel()->SetSendBandwidth(true, max_bandwidth);
}
-bool BaseChannel::SetRtcpCName_w(const std::string& cname) {
- return media_channel()->SetRtcpCName(cname);
-}
-
bool BaseChannel::SetSrtp_w(const std::vector<CryptoParams>& cryptos,
ContentAction action, ContentSource src) {
bool ret;
@@ -558,14 +566,186 @@
return ret;
}
-bool BaseChannel::AddSsrcMuxStreams_w(
- const std::vector<StreamParams>& streams) {
- for (std::vector<StreamParams>::const_iterator it = streams.begin();
- it != streams.end(); ++it) {
- if (!ssrc_filter_.AddStream(*it))
- return false;
+bool BaseChannel::AddRecvStream_w(const StreamParams& sp) {
+ ASSERT(worker_thread() == talk_base::Thread::Current());
+ if (!media_channel()->AddRecvStream(sp))
+ return false;
+
+ return ssrc_filter_.AddStream(sp);
+}
+
+bool BaseChannel::RemoveRecvStream_w(uint32 ssrc) {
+ ASSERT(worker_thread() == talk_base::Thread::Current());
+ ssrc_filter_.RemoveStream(ssrc);
+ return media_channel()->RemoveRecvStream(ssrc);
+}
+
+bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
+ ContentAction action) {
+ if (!VERIFY(action == CA_OFFER || action == CA_ANSWER || action == CA_UPDATE))
+ return false;
+
+ // If this is an update, streams only contain streams that have changed.
+ if (action == CA_UPDATE) {
+ for (StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ StreamParams existing_stream;
+ bool stream_exist = GetStreamByNickAndName(local_streams_, it->nick,
+ it->name, &existing_stream);
+ if (!stream_exist && it->has_ssrcs()) {
+ if (media_channel()->AddSendStream(*it)) {
+ local_streams_.push_back(*it);
+ LOG(LS_INFO) << "Add send stream ssrc: " << it->first_ssrc();
+ } else {
+ LOG(LS_INFO) << "Failed to add send stream ssrc: "
+ << it->first_ssrc();
+ return false;
+ }
+ } else if (stream_exist) {
+ if (!media_channel()->RemoveSendStream(existing_stream.first_ssrc())) {
+ LOG(LS_ERROR) << "Failed to remove send stream with ssrc "
+ << it->first_ssrc() << ".";
+ return false;
+ }
+ RemoveStreamBySsrc(&local_streams_, existing_stream.first_ssrc());
+ } else {
+ LOG(LS_ERROR) << "Unknown send stream update.";
+ return false;
+ }
+ }
+ return true;
}
- return true;
+ // Else streams are all the streams we want to send.
+
+ // Check for streams that have been removed.
+ bool ret = true;
+ for (StreamParamsVec::const_iterator it = local_streams_.begin();
+ it != local_streams_.end(); ++it) {
+ if (!GetStreamBySsrc(streams, it->first_ssrc(), NULL)) {
+ if (!media_channel()->RemoveSendStream(it->first_ssrc())) {
+ LOG(LS_ERROR) << "Failed to remove send stream with ssrc "
+ << it->first_ssrc() << ".";
+ ret = false;
+ }
+ }
+ }
+ // Check for new streams.
+ for (StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ if (!GetStreamBySsrc(local_streams_, it->first_ssrc(), NULL)) {
+ if (media_channel()->AddSendStream(*it)) {
+ LOG(LS_INFO) << "Add send ssrc: " << it->ssrcs[0];
+ } else {
+ LOG(LS_INFO) << "Failed to add send stream ssrc: " << it->first_ssrc();
+ ret = false;
+ }
+ }
+ }
+ local_streams_ = streams;
+ return ret;
+}
+
+bool BaseChannel::UpdateRemoteStreams_w(
+ const std::vector<StreamParams>& streams,
+ ContentAction action) {
+ // If this is an update, streams only contain streams that have changed.
+ if (action == CA_UPDATE) {
+ for (StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ StreamParams existing_stream;
+ bool stream_exists = GetStreamByNickAndName(remote_streams_, it->nick,
+ it->name, &existing_stream);
+ if (!stream_exists && it->has_ssrcs()) {
+ if (AddRecvStream_w(*it)) {
+ remote_streams_.push_back(*it);
+ LOG(LS_INFO) << "Add remote stream ssrc: " << it->first_ssrc();
+ } else {
+ LOG(LS_INFO) << "Failed to add remote stream ssrc: "
+ << it->first_ssrc();
+ return false;
+ }
+ } else if (stream_exists) {
+ if (!RemoveRecvStream_w(existing_stream.first_ssrc())) {
+ LOG(LS_ERROR) << "Failed to remove remote stream with ssrc "
+ << it->first_ssrc() << ".";
+ return false;
+ }
+ RemoveStreamBySsrc(&remote_streams_, existing_stream.first_ssrc());
+ } else {
+ LOG(LS_ERROR) << "Unknown remote stream update.";
+ return false;
+ }
+ }
+ return true;
+ }
+ // Else streams are all the streams we want to receive.
+
+ // Check for streams that have been removed.
+ bool ret = true;
+ for (StreamParamsVec::const_iterator it = remote_streams_.begin();
+ it != remote_streams_.end(); ++it) {
+ if (!GetStreamBySsrc(streams, it->first_ssrc(), NULL)) {
+ if (!RemoveRecvStream_w(it->first_ssrc())) {
+ LOG(LS_ERROR) << "Failed to remove remote stream with ssrc "
+ << it->first_ssrc() << ".";
+ ret = false;
+ }
+ }
+ }
+ // Check for new streams.
+ for (StreamParamsVec::const_iterator it = streams.begin();
+ it != streams.end(); ++it) {
+ if (!GetStreamBySsrc(remote_streams_, it->first_ssrc(), NULL)) {
+ if (AddRecvStream_w(*it)) {
+ LOG(LS_INFO) << "Add remote ssrc: " << it->ssrcs[0];
+ } else {
+ LOG(LS_INFO) << "Failed to add remote stream ssrc: "
+ << it->first_ssrc();
+ ret = false;
+ }
+ }
+ }
+ remote_streams_ = streams;
+ return ret;
+}
+
+bool BaseChannel::SetBaseLocalContent_w(const MediaContentDescription* content,
+ ContentAction action) {
+ bool ret = UpdateLocalStreams_w(content->streams(), action);
+ // Set local SRTP parameters (what we will encrypt with).
+ if (ret) {
+ ret = SetSrtp_w(content->cryptos(), action, CS_LOCAL);
+ }
+ // Set local RTCP mux parameters.
+ if (ret) {
+ ret = SetRtcpMux_w(content->rtcp_mux(), action, CS_LOCAL);
+ }
+ // Set local RTP header extensions.
+ if (ret && content->rtp_header_extensions_set()) {
+ ret = media_channel()->SetRecvRtpHeaderExtensions(
+ content->rtp_header_extensions());
+ }
+ return ret;
+}
+
+bool BaseChannel::SetBaseRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action) {
+ bool ret = UpdateRemoteStreams_w(content->streams(), action);
+ // Set remote SRTP parameters (what the other side will encrypt with).
+ if (ret) {
+ ret = SetSrtp_w(content->cryptos(), action, CS_REMOTE);
+ }
+ // Set remote RTCP mux parameters.
+ if (ret) {
+ ret = SetRtcpMux_w(content->rtcp_mux(), action, CS_REMOTE);
+ }
+
+ // Set remote RTP header extensions.
+ if (ret && content->rtp_header_extensions_set()) {
+ ret = media_channel()->SetSendRtpHeaderExtensions(
+ content->rtp_header_extensions());
+ }
+ return ret;
}
void BaseChannel::OnMessage(talk_base::Message *pmsg) {
@@ -583,13 +763,6 @@
case MSG_UNMUTE:
UnmuteMedia_w();
break;
-
- case MSG_SETRTCPCNAME: {
- SetRtcpCNameData* data = static_cast<SetRtcpCNameData*>(pmsg->pdata);
- data->result = SetRtcpCName_w(data->cname);
- break;
- }
-
case MSG_SETLOCALCONTENT: {
SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
data->result = SetLocalContent_w(data->content, data->action);
@@ -600,13 +773,16 @@
data->result = SetRemoteContent_w(data->content, data->action);
break;
}
-
- case MSG_REMOVESTREAM: {
+ case MSG_ADDRECVSTREAM: {
StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- RemoveStream_w(data->ssrc1);
+ data->result = AddRecvStream_w(data->sp);
break;
}
-
+ case MSG_REMOVERECVSTREAM: {
+ SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
+ data->result = RemoveRecvStream_w(data->ssrc);
+ break;
+ }
case MSG_SETMAXSENDBANDWIDTH: {
SetBandwidthData* data = static_cast<SetBandwidthData*>(pmsg->pdata);
data->result = SetMaxSendBandwidth_w(data->value);
@@ -686,12 +862,6 @@
return true;
}
-bool VoiceChannel::AddStream(uint32 ssrc) {
- StreamMessageData data(ssrc, 0);
- Send(MSG_ADDSTREAM, &data);
- return true;
-}
-
bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
SetRingbackToneMessageData data(buf, len);
Send(MSG_SETRINGBACKTONE, &data);
@@ -795,7 +965,7 @@
if (!media_channel()->SetPlayout(recv)) {
SendLastMediaError();
}
-
+
// Send outgoing data if we're the active call, we have the remote content,
// and we have had some form of connectivity.
bool send = enabled() && has_remote_content() && was_ever_writable();
@@ -826,27 +996,13 @@
static_cast<const AudioContentDescription*>(content);
ASSERT(audio != NULL);
- bool ret;
- if (audio->has_ssrcs()) {
- // TODO: Handle multiple streams and ssrcs here.
- media_channel()->SetSendSsrc(audio->first_ssrc());
- LOG(LS_INFO) << "Set send ssrc for audio: " << audio->first_ssrc();
- }
- // Set local SRTP parameters (what we will encrypt with).
- ret = SetSrtp_w(audio->cryptos(), action, CS_LOCAL);
- // Set local RTCP mux parameters.
- if (ret) {
- ret = SetRtcpMux_w(audio->rtcp_mux(), action, CS_LOCAL);
- }
+ bool ret = SetBaseLocalContent_w(content, action);
+
// Set local audio codecs (what we want to receive).
if (ret) {
ret = media_channel()->SetRecvCodecs(audio->codecs());
}
- // Set local RTP header extensions.
- if (ret && audio->rtp_header_extensions_set()) {
- ret = media_channel()->SetRecvRtpHeaderExtensions(
- audio->rtp_header_extensions());
- }
+
// If everything worked, see if we can start receiving.
if (ret) {
set_has_local_content(true);
@@ -866,28 +1022,11 @@
static_cast<const AudioContentDescription*>(content);
ASSERT(audio != NULL);
- bool ret;
- // Set remote SRTP parameters (what the other side will encrypt with).
- ret = SetSrtp_w(audio->cryptos(), action, CS_REMOTE);
- // Set remote RTCP mux parameters.
- if (ret) {
- ret = SetRtcpMux_w(audio->rtcp_mux(), action, CS_REMOTE);
- }
- // Set SSRC mux filter
- if (ret) {
- // TODO: Refactor adding / removing to the ssrc mux filter
- // when updating receiving streams based on the streams in content.
- ret = AddSsrcMuxStreams_w(audio->streams());
- }
-
// Set remote video codecs (what the other side wants to receive).
+ bool ret = media_channel()->SetSendCodecs(audio->codecs());
+
if (ret) {
- ret = media_channel()->SetSendCodecs(audio->codecs());
- }
- // Set remote RTP header extensions.
- if (ret && audio->rtp_header_extensions_set()) {
- ret = media_channel()->SetSendRtpHeaderExtensions(
- audio->rtp_header_extensions());
+ ret = SetBaseRemoteContent_w(content, action);
}
// Tweak our audio processing settings, if needed.
@@ -913,19 +1052,6 @@
return ret;
}
-void VoiceChannel::AddStream_w(uint32 ssrc) {
- ASSERT(worker_thread() == talk_base::Thread::Current());
- media_channel()->AddStream(ssrc);
- // TODO: Work is ongoing to refactor AddStream_w to take
- // StreamParams as input.
- ssrc_filter()->AddStream(StreamParams::CreateLegacy(ssrc));
-}
-
-void VoiceChannel::RemoveStream_w(uint32 ssrc) {
- media_channel()->RemoveStream(ssrc);
- ssrc_filter()->RemoveStream(ssrc);
-}
-
bool VoiceChannel::SetRingbackTone_w(const void* buf, int len) {
ASSERT(worker_thread() == talk_base::Thread::Current());
return media_channel()->SetRingbackTone(static_cast<const char*>(buf), len);
@@ -963,11 +1089,6 @@
void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_ADDSTREAM: {
- StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- AddStream_w(data->ssrc1);
- break;
- }
case MSG_SETRINGBACKTONE: {
SetRingbackToneMessageData* data =
static_cast<SetRingbackToneMessageData*>(pmsg->pdata);
@@ -1100,12 +1221,6 @@
DisableMedia_w();
}
-bool VideoChannel::AddStream(uint32 ssrc, uint32 voice_ssrc) {
- StreamMessageData data(ssrc, voice_ssrc);
- Send(MSG_ADDSTREAM, &data);
- return true;
-}
-
bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
RenderMessageData data(ssrc, renderer);
Send(MSG_SETRENDERER, &data);
@@ -1191,28 +1306,13 @@
static_cast<const VideoContentDescription*>(content);
ASSERT(video != NULL);
- bool ret;
- if (video->has_ssrcs()) {
- // TODO: Handle multiple streams and ssrcs here.
- media_channel()->SetSendSsrc(video->first_ssrc());
- LOG(LS_INFO) << "Set send ssrc for video: " << video->first_ssrc();
- }
- // Set local SRTP parameters (what we will encrypt with).
- ret = SetSrtp_w(video->cryptos(), action, CS_LOCAL);
- // Set local RTCP mux parameters.
- if (ret) {
- ret = SetRtcpMux_w(video->rtcp_mux(), action, CS_LOCAL);
- }
+ bool ret = SetBaseLocalContent_w(content, action);
// Set local video codecs (what we want to receive).
if (ret) {
ret = media_channel()->SetRecvCodecs(video->codecs());
}
- // Set local RTP header extensions.
- if (ret && video->rtp_header_extensions_set()) {
- ret = media_channel()->SetRecvRtpHeaderExtensions(
- video->rtp_header_extensions());
- }
+
// If everything worked, see if we can start receiving.
if (ret) {
set_has_local_content(true);
@@ -1232,27 +1332,11 @@
static_cast<const VideoContentDescription*>(content);
ASSERT(video != NULL);
- bool ret;
- // Set remote SRTP parameters (what the other side will encrypt with).
- ret = SetSrtp_w(video->cryptos(), action, CS_REMOTE);
- // Set remote RTCP mux parameters.
- if (ret) {
- ret = SetRtcpMux_w(video->rtcp_mux(), action, CS_REMOTE);
- }
- // Set SSRC mux filter
- if (ret) {
- // TODO: Refactor adding / removing to the ssrc mux filter
- // when updating receiving streams based on the streams in content.
- ret = AddSsrcMuxStreams_w(video->streams());
- }
// Set remote video codecs (what the other side wants to receive).
+ bool ret = media_channel()->SetSendCodecs(video->codecs());
+
if (ret) {
- ret = media_channel()->SetSendCodecs(video->codecs());
- }
- // Set remote RTP header extensions.
- if (ret && video->rtp_header_extensions_set()) {
- ret = media_channel()->SetSendRtpHeaderExtensions(
- video->rtp_header_extensions());
+ ret = SetBaseRemoteContent_w(content, action);
}
// Tweak our video processing settings, if needed.
int video_options = 0;
@@ -1279,18 +1363,6 @@
return ret;
}
-void VideoChannel::AddStream_w(uint32 ssrc, uint32 voice_ssrc) {
- media_channel()->AddStream(ssrc, voice_ssrc);
- // TODO: Work is ongoing to refactor AddStream_w to take
- // StreamParams as input.
- ssrc_filter()->AddStream(StreamParams::CreateLegacy(ssrc));
-}
-
-void VideoChannel::RemoveStream_w(uint32 ssrc) {
- media_channel()->RemoveStream(ssrc);
- ssrc_filter()->RemoveStream(ssrc);
-}
-
void VideoChannel::SetRenderer_w(uint32 ssrc, VideoRenderer* renderer) {
media_channel()->SetRenderer(ssrc, renderer);
}
@@ -1311,11 +1383,6 @@
void VideoChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_ADDSTREAM: {
- StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- AddStream_w(data->ssrc1, data->ssrc2);
- break;
- }
case MSG_SETRENDERER: {
RenderMessageData* data = static_cast<RenderMessageData*>(pmsg->pdata);
SetRenderer_w(data->ssrc, data->renderer);
diff --git a/talk/session/phone/channel.h b/talk/session/phone/channel.h
index 3272d4b..f262e00 100644
--- a/talk/session/phone/channel.h
+++ b/talk/session/phone/channel.h
@@ -45,6 +45,7 @@
#include "talk/session/phone/rtcpmuxfilter.h"
#include "talk/session/phone/screencastid.h"
#include "talk/session/phone/ssrcmuxfilter.h"
+#include "talk/session/phone/streamparams.h"
#include "talk/session/phone/srtpfilter.h"
namespace cricket {
@@ -62,14 +63,14 @@
MSG_EARLYMEDIATIMEOUT = 8,
MSG_PRESSDTMF = 9,
MSG_SETRENDERER = 10,
- MSG_ADDSTREAM = 11,
- MSG_REMOVESTREAM = 12,
+ MSG_ADDRECVSTREAM = 11,
+ MSG_REMOVERECVSTREAM = 12,
MSG_SETRINGBACKTONE = 13,
MSG_PLAYRINGBACKTONE = 14,
MSG_SETMAXSENDBANDWIDTH = 15,
MSG_ADDSCREENCAST = 16,
MSG_REMOVESCREENCAST = 17,
- MSG_SETRTCPCNAME = 18,
+ // Removed MSG_SETRTCPCNAME = 18. It is no longer used.
MSG_SENDINTRAFRAME = 19,
MSG_REQUESTINTRAFRAME = 20,
MSG_SCREENCASTWINDOWEVENT = 21,
@@ -108,7 +109,6 @@
bool secure() const { return srtp_filter_.IsActive(); }
// Channel control
- bool SetRtcpCName(const std::string& cname);
bool SetLocalContent(const MediaContentDescription* content,
ContentAction action);
bool SetRemoteContent(const MediaContentDescription* content,
@@ -119,7 +119,8 @@
bool Mute(bool mute);
// Multiplexing
- bool RemoveStream(uint32 ssrc);
+ bool AddRecvStream(const StreamParams& sp);
+ bool RemoveRecvStream(uint32 ssrc);
// Monitoring
void StartConnectionMonitor(int cms);
@@ -215,24 +216,10 @@
void UnmuteMedia_w();
void ChannelWritable_w();
void ChannelNotWritable_w();
-
- struct StreamMessageData : public talk_base::MessageData {
- StreamMessageData(uint32 s1, uint32 s2) : ssrc1(s1), ssrc2(s2) {}
- uint32 ssrc1;
- uint32 ssrc2;
- };
- virtual void RemoveStream_w(uint32 ssrc) = 0;
+ bool AddRecvStream_w(const StreamParams& sp);
+ bool RemoveRecvStream_w(uint32 ssrc);
virtual void ChangeState() = 0;
-
- struct SetRtcpCNameData : public talk_base::MessageData {
- explicit SetRtcpCNameData(const std::string& cname)
- : cname(cname), result(false) {}
- std::string cname;
- bool result;
- };
- bool SetRtcpCName_w(const std::string& cname);
-
struct SetContentData : public talk_base::MessageData {
SetContentData(const MediaContentDescription* content,
ContentAction action)
@@ -245,8 +232,16 @@
// Gets the content appropriate to the channel (audio or video).
virtual const MediaContentDescription* GetFirstContent(
const SessionDescription* sdesc) = 0;
+ bool UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
+ ContentAction action);
+ bool UpdateRemoteStreams_w(const std::vector<StreamParams>& streams,
+ ContentAction action);
+ bool SetBaseLocalContent_w(const MediaContentDescription* content,
+ ContentAction action);
virtual bool SetLocalContent_w(const MediaContentDescription* content,
ContentAction action) = 0;
+ bool SetBaseRemoteContent_w(const MediaContentDescription* content,
+ ContentAction action);
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
ContentAction action) = 0;
@@ -254,9 +249,6 @@
ContentSource src);
bool SetRtcpMux_w(bool enable, ContentAction action, ContentSource src);
- // SSRC mux handling methods.
- bool AddSsrcMuxStreams_w(const std::vector<StreamParams>& streams);
-
struct SetBandwidthData : public talk_base::MessageData {
explicit SetBandwidthData(int value) : value(value), result(false) {}
int value;
@@ -281,6 +273,8 @@
MediaEngineInterface *media_engine_;
BaseSession *session_;
MediaChannel *media_channel_;
+ std::vector<StreamParams> local_streams_;
+ std::vector<StreamParams> remote_streams_;
std::string content_name_;
bool rtcp_;
@@ -313,9 +307,6 @@
return static_cast<VoiceMediaChannel*>(BaseChannel::media_channel());
}
- // Add an incoming stream with the specified SSRC.
- bool AddStream(uint32 ssrc);
-
bool SetRingbackTone(const void* buf, int len);
void SetEarlyMedia(bool enable);
// This signal is emitted when we have gone a period of time without
@@ -412,9 +403,6 @@
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
ContentAction action);
- void AddStream_w(uint32 ssrc);
- void RemoveStream_w(uint32 ssrc);
-
bool SetRingbackTone_w(const void* buf, int len);
bool PlayRingbackTone_w(uint32 ssrc, bool play, bool loop);
void HandleEarlyMediaTimeout();
@@ -454,9 +442,6 @@
return static_cast<VideoMediaChannel*>(BaseChannel::media_channel());
}
- // Add an incoming stream with the specified SSRC.
- bool AddStream(uint32 ssrc, uint32 voice_ssrc);
-
bool SetRenderer(uint32 ssrc, VideoRenderer* renderer);
bool AddScreencast(uint32 ssrc, const ScreencastId& id);
@@ -487,9 +472,6 @@
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
ContentAction action);
- void AddStream_w(uint32 ssrc, uint32 voice_ssrc);
- void RemoveStream_w(uint32 ssrc);
-
void SendIntraFrame_w() {
media_channel()->SendIntraFrame();
}
diff --git a/talk/session/phone/channel_unittest.cc b/talk/session/phone/channel_unittest.cc
index 86d3b6d..b53cca0 100644
--- a/talk/session/phone/channel_unittest.cc
+++ b/talk/session/phone/channel_unittest.cc
@@ -40,6 +40,7 @@
using cricket::CA_OFFER;
using cricket::CA_ANSWER;
using cricket::CA_UPDATE;
+using cricket::StreamParams;
static const cricket::AudioCodec kPcmuCodec(0, "PCMU", 64000, 8000, 1, 0);
static const cricket::AudioCodec kPcmaCodec(8, "PCMA", 64000, 8000, 1, 0);
@@ -48,6 +49,8 @@
static const cricket::VideoCodec kH264SvcCodec(99, "H264-SVC", 320, 200, 15, 0);
static const uint32 kSsrc1 = 0x1111;
static const uint32 kSsrc2 = 0x2222;
+static const uint32 kSsrc3 = 0x3333;
+static const char kCName[] = "a@b.com";
class VoiceTraits {
public:
@@ -123,10 +126,23 @@
this, &ChannelTest<T>::OnMediaChannelError);
channel2_->SignalMediaError.connect(
this, &ChannelTest<T>::OnMediaChannelError);
- CreateContent(flags1, kPcmuCodec, kH264Codec, &media_content1_);
- CreateContent(flags2, kPcmuCodec, kH264Codec, &media_content2_);
- AddLegacyStreamInContent(kSsrc1, flags1, &media_content1_);
- AddLegacyStreamInContent(kSsrc2, flags2, &media_content2_);
+ CreateContent(flags1, kPcmuCodec, kH264Codec, &local_media_content1_);
+ CreateContent(flags2, kPcmuCodec, kH264Codec, &local_media_content2_);
+ CopyContent(local_media_content1_, &remote_media_content1_);
+ CopyContent(local_media_content2_, &remote_media_content2_);
+ // Add stream information (SSRC) to the local content but not to the remote
+ // content. This means that we per default know the SSRC of what we send but
+ // not what we receive.
+ AddLegacyStreamInContent(kSsrc1, flags1, &local_media_content1_);
+ AddLegacyStreamInContent(kSsrc2, flags2, &local_media_content2_);
+
+ // If SSRC_MUX is used we also need to know the SSRC of the incoming stream.
+ if (flags1 & SSRC_MUX) {
+ AddLegacyStreamInContent(kSsrc1, flags1, &remote_media_content1_);
+ }
+ if (flags2 & SSRC_MUX) {
+ AddLegacyStreamInContent(kSsrc2, flags2, &remote_media_content2_);
+ }
}
void CreateChannels(
@@ -144,10 +160,21 @@
this, &ChannelTest<T>::OnMediaMonitor);
channel2_->SignalMediaError.connect(
this, &ChannelTest<T>::OnMediaChannelError);
- CreateContent(flags, kPcmuCodec, kH264Codec, &media_content1_);
- CreateContent(flags, kPcmuCodec, kH264Codec, &media_content2_);
- AddLegacyStreamInContent(kSsrc1, flags, &media_content1_);
- AddLegacyStreamInContent(kSsrc2, flags, &media_content2_);
+ CreateContent(flags, kPcmuCodec, kH264Codec, &local_media_content1_);
+ CreateContent(flags, kPcmuCodec, kH264Codec, &local_media_content2_);
+ CopyContent(local_media_content1_, &remote_media_content1_);
+ CopyContent(local_media_content2_, &remote_media_content2_);
+ // Add stream information (SSRC) to the local content but not to the remote
+ // content. This means that we per default know the SSRC of what we send but
+ // not what we receive.
+ AddLegacyStreamInContent(kSsrc1, flags, &local_media_content1_);
+ AddLegacyStreamInContent(kSsrc2, flags, &local_media_content2_);
+
+ // If SSRC_MUX is used we also need to know the SSRC of the incoming stream.
+ if (flags & SSRC_MUX) {
+ AddLegacyStreamInContent(kSsrc1, flags, &remote_media_content1_);
+ AddLegacyStreamInContent(kSsrc2, flags, &remote_media_content2_);
+ }
}
typename T::Channel* CreateChannel(talk_base::Thread* thread,
cricket::MediaEngineInterface* engine,
@@ -164,12 +191,12 @@
}
bool SendInitiate() {
- bool result = channel1_->SetLocalContent(&media_content1_, CA_OFFER);
+ bool result = channel1_->SetLocalContent(&local_media_content1_, CA_OFFER);
if (result) {
channel1_->Enable(true);
- result = channel2_->SetRemoteContent(&media_content1_, CA_OFFER);
+ result = channel2_->SetRemoteContent(&remote_media_content1_, CA_OFFER);
if (result) {
- result = channel2_->SetLocalContent(&media_content2_, CA_ANSWER);
+ result = channel2_->SetLocalContent(&local_media_content2_, CA_ANSWER);
if (result) {
session1_.Connect(&session2_);
}
@@ -179,7 +206,7 @@
}
bool SendAccept() {
channel2_->Enable(true);
- return channel1_->SetRemoteContent(&media_content2_, CA_ANSWER);
+ return channel1_->SetRemoteContent(&remote_media_content2_, CA_ANSWER);
}
bool SendTerminate() {
channel1_.reset();
@@ -188,10 +215,10 @@
}
bool AddStream1(int id) {
- return channel1_->AddStream(id);
+ return channel1_->AddRecvStream(cricket::StreamParams::CreateLegacy(id));
}
bool RemoveStream1(int id) {
- return channel1_->RemoveStream(id);
+ return channel1_->RemoveRecvStream(id);
}
cricket::FakeTransport* GetTransport1() {
@@ -293,6 +320,10 @@
typename T::Content* content) {
// overridden in specialized classes
}
+ void CopyContent(const typename T::Content& source,
+ typename T::Content* content) {
+ // overridden in specialized classes
+ }
class CallThread : public talk_base::SignalThread {
public:
@@ -361,21 +392,11 @@
EXPECT_FALSE(media_channel1_->sending());
EXPECT_FALSE(media_channel1_->playout());
EXPECT_TRUE(media_channel1_->codecs().empty());
- EXPECT_TRUE(media_channel1_->streams().empty());
+ EXPECT_TRUE(media_channel1_->recv_streams().empty());
EXPECT_TRUE(media_channel1_->rtp_packets().empty());
EXPECT_TRUE(media_channel1_->rtcp_packets().empty());
}
- // Test that SetRtcpCName sets the RTCP CNAME successfully.
- void TestSetRtcpCName() {
- static const char* kTestCName = "a@b.com";
- CreateChannels(0, 0);
- EXPECT_TRUE(channel1_->SetRtcpCName(kTestCName));
- EXPECT_EQ(kTestCName, media_channel1_->rtcp_cname());
- EXPECT_TRUE(channel2_->SetRtcpCName(kTestCName));
- EXPECT_EQ(kTestCName, media_channel2_->rtcp_cname());
- }
-
// Test that SetLocalContent and SetRemoteContent properly configure
// the codecs.
void TestSetContents() {
@@ -454,11 +475,193 @@
CreateChannels(0, 0);
EXPECT_TRUE(AddStream1(1));
EXPECT_TRUE(AddStream1(2));
- EXPECT_EQ(2U, media_channel1_->streams().size());
+ EXPECT_EQ(2U, media_channel1_->recv_streams().size());
EXPECT_TRUE(RemoveStream1(2));
- EXPECT_EQ(1U, media_channel1_->streams().size());
+ EXPECT_EQ(1U, media_channel1_->recv_streams().size());
EXPECT_TRUE(RemoveStream1(1));
- EXPECT_EQ(0U, media_channel1_->streams().size());
+ EXPECT_EQ(0U, media_channel1_->recv_streams().size());
+ }
+
+ // Test that SetLocalContent properly handles adding and removing StreamParams
+ // to the local content description.
+ // This test uses the CA_UPDATE action that don't require a full
+ // MediaContentDescription to do an update.
+ void TestUpdateStreamsInLocalContent() {
+ cricket::StreamParams stream1;
+ stream1.name = "Stream1";
+ stream1.nick = "1";
+ stream1.ssrcs.push_back(kSsrc1);
+ stream1.cname = "stream1_cname";
+
+ cricket::StreamParams stream2;
+ stream2.name = "Stream2";
+ stream2.nick = "2";
+ stream2.ssrcs.push_back(kSsrc2);
+ stream2.cname = "stream2_cname";
+
+ cricket::StreamParams stream3;
+ stream3.name = "Stream3";
+ stream3.nick = "3";
+ stream3.ssrcs.push_back(kSsrc3);
+ stream3.cname = "stream3_cname";
+
+ CreateChannels(0, 0);
+ typename T::Content content1;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content1);
+ content1.AddStream(stream1);
+ EXPECT_EQ(0u, media_channel1_->send_streams().size());
+ EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER));
+
+ ASSERT_EQ(1u, media_channel1_->send_streams().size());
+ EXPECT_EQ(stream1, media_channel1_->send_streams()[0]);
+
+ // Update the local streams by adding another sending stream.
+ // Use a partial updated session description.
+ typename T::Content content2;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content2);
+ content2.AddStream(stream2);
+ content2.AddStream(stream3);
+ EXPECT_TRUE(channel1_->SetLocalContent(&content2, CA_UPDATE));
+ ASSERT_EQ(3u, media_channel1_->send_streams().size());
+ EXPECT_EQ(stream1, media_channel1_->send_streams()[0]);
+ EXPECT_EQ(stream2, media_channel1_->send_streams()[1]);
+ EXPECT_EQ(stream3, media_channel1_->send_streams()[2]);
+
+ // Update the local streams by removing the first sending stream.
+ // This is done by removing all SSRCS for this particular stream.
+ typename T::Content content3;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content3);
+ stream1.ssrcs.clear();
+ content3.AddStream(stream1);
+
+ EXPECT_TRUE(channel1_->SetLocalContent(&content3, CA_UPDATE));
+ ASSERT_EQ(2u, media_channel1_->send_streams().size());
+ EXPECT_EQ(stream2, media_channel1_->send_streams()[0]);
+ EXPECT_EQ(stream3, media_channel1_->send_streams()[1]);
+ }
+
+ // Test that SetRemoteContent properly handles adding and removing
+ // StreamParams to the remote content description.
+ // This test uses the CA_UPDATE action that don't require a full
+ // MediaContentDescription to do an update.
+ void TestUpdateStreamsInRemoteContent() {
+ cricket::StreamParams stream1;
+ stream1.name = "Stream1";
+ stream1.nick = "1";
+ stream1.ssrcs.push_back(kSsrc1);
+ stream1.cname = "stream1_cname";
+
+ cricket::StreamParams stream2;
+ stream2.name = "Stream2";
+ stream2.nick = "2";
+ stream2.ssrcs.push_back(kSsrc2);
+ stream2.cname = "stream2_cname";
+
+ cricket::StreamParams stream3;
+ stream3.name = "Stream3";
+ stream3.nick = "3";
+ stream3.ssrcs.push_back(kSsrc3);
+ stream3.cname = "stream3_cname";
+
+ CreateChannels(0, 0);
+ typename T::Content content1;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content1);
+ content1.AddStream(stream1);
+ EXPECT_EQ(0u, media_channel1_->recv_streams().size());
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content1, CA_OFFER));
+
+ ASSERT_EQ(1u, media_channel1_->recv_streams().size());
+ EXPECT_EQ(stream1, media_channel1_->recv_streams()[0]);
+
+ // Update the local streams by adding another sending stream.
+ // Use a partial updated session description.
+ typename T::Content content2;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content2);
+ content2.AddStream(stream2);
+ content2.AddStream(stream3);
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_UPDATE));
+ ASSERT_EQ(3u, media_channel1_->recv_streams().size());
+ EXPECT_EQ(stream1, media_channel1_->recv_streams()[0]);
+ EXPECT_EQ(stream2, media_channel1_->recv_streams()[1]);
+ EXPECT_EQ(stream3, media_channel1_->recv_streams()[2]);
+
+ // Update the remote streams by removing the first stream.
+ // This is done by removing all SSRCS for this particular stream.
+ typename T::Content content3;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content3);
+ stream1.ssrcs.clear();
+ content3.AddStream(stream1);
+
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_UPDATE));
+ ASSERT_EQ(2u, media_channel1_->recv_streams().size());
+ EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
+ EXPECT_EQ(stream3, media_channel1_->recv_streams()[1]);
+ }
+
+ // Test that SetLocalContent and SetRemoteContent properly
+ // handles adding and removing StreamParams when the action is a full
+ // CA_OFFER / CA_ANSWER.
+ void TestChangeStreamParamsInContent() {
+ cricket::StreamParams stream1;
+ stream1.name = "Stream1";
+ stream1.ssrcs.push_back(kSsrc1);
+ stream1.cname = "stream1_cname";
+
+ cricket::StreamParams stream2;
+ stream2.name = "Stream2";
+ stream2.ssrcs.push_back(kSsrc2);
+ stream2.cname = "stream2_cname";
+
+ // Setup a call where channel 1 send |stream1| to channel 2.
+ CreateChannels(0, 0);
+ typename T::Content content1;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content1);
+ content1.AddStream(stream1);
+ EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER));
+ EXPECT_TRUE(channel1_->Enable(true));
+ EXPECT_EQ(1u, media_channel1_->send_streams().size());
+
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER));
+ EXPECT_EQ(1u, media_channel2_->recv_streams().size());
+ session1_.Connect(&session2_);
+
+ // Channel 2 do not send anything.
+ typename T::Content content2;
+ CreateContent(0, kPcmuCodec, kH264Codec, &content2);
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER));
+ EXPECT_EQ(0u, media_channel1_->recv_streams().size());
+ EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER));
+ EXPECT_TRUE(channel2_->Enable(true));
+ EXPECT_EQ(0u, media_channel2_->send_streams().size());
+
+ EXPECT_TRUE(SendCustomRtp1(kSsrc1));
+ EXPECT_TRUE(CheckCustomRtp2(kSsrc1));
+
+ // Let channel 2 update the content by sending |stream2| and enable SRTP.
+ typename T::Content content3;
+ CreateContent(SECURE, kPcmuCodec, kH264Codec, &content3);
+ content3.AddStream(stream2);
+ EXPECT_TRUE(channel2_->SetLocalContent(&content3, CA_OFFER));
+ ASSERT_EQ(1u, media_channel2_->send_streams().size());
+ EXPECT_EQ(stream2, media_channel2_->send_streams()[0]);
+
+ EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_OFFER));
+ ASSERT_EQ(1u, media_channel1_->recv_streams().size());
+ EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]);
+
+ // Channel 1 replies but stop sending stream1.
+ typename T::Content content4;
+ CreateContent(SECURE, kPcmuCodec, kH264Codec, &content4);
+ EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_ANSWER));
+ EXPECT_EQ(0u, media_channel1_->send_streams().size());
+
+ EXPECT_TRUE(channel2_->SetRemoteContent(&content4, CA_ANSWER));
+ EXPECT_EQ(0u, media_channel2_->recv_streams().size());
+
+ EXPECT_TRUE(channel1_->secure());
+ EXPECT_TRUE(channel2_->secure());
+ EXPECT_TRUE(SendCustomRtp2(kSsrc2));
+ EXPECT_TRUE(CheckCustomRtp1(kSsrc2));
}
// Test that we only start playout and sending at the right times.
@@ -471,13 +674,13 @@
EXPECT_TRUE(channel1_->Enable(true));
EXPECT_FALSE(media_channel1_->playout());
EXPECT_FALSE(media_channel1_->sending());
- EXPECT_TRUE(channel1_->SetLocalContent(&media_content1_, CA_OFFER));
+ EXPECT_TRUE(channel1_->SetLocalContent(&local_media_content1_, CA_OFFER));
EXPECT_TRUE(media_channel1_->playout());
EXPECT_FALSE(media_channel1_->sending());
- EXPECT_TRUE(channel2_->SetRemoteContent(&media_content1_, CA_OFFER));
+ EXPECT_TRUE(channel2_->SetRemoteContent(&local_media_content1_, CA_OFFER));
EXPECT_FALSE(media_channel2_->playout());
EXPECT_FALSE(media_channel2_->sending());
- EXPECT_TRUE(channel2_->SetLocalContent(&media_content2_, CA_ANSWER));
+ EXPECT_TRUE(channel2_->SetLocalContent(&local_media_content2_, CA_ANSWER));
EXPECT_FALSE(media_channel2_->playout());
EXPECT_FALSE(media_channel2_->sending());
session1_.Connect(&session2_);
@@ -488,7 +691,7 @@
EXPECT_TRUE(channel2_->Enable(true));
EXPECT_TRUE(media_channel2_->playout());
EXPECT_TRUE(media_channel2_->sending());
- EXPECT_TRUE(channel1_->SetRemoteContent(&media_content2_, CA_ANSWER));
+ EXPECT_TRUE(channel1_->SetRemoteContent(&local_media_content2_, CA_ANSWER));
EXPECT_TRUE(media_channel1_->playout());
EXPECT_TRUE(media_channel1_->sending());
}
@@ -1083,8 +1286,10 @@
typename T::MediaChannel* media_channel2_;
talk_base::scoped_ptr<typename T::Channel> channel1_;
talk_base::scoped_ptr<typename T::Channel> channel2_;
- typename T::Content media_content1_;
- typename T::Content media_content2_;
+ typename T::Content local_media_content1_;
+ typename T::Content local_media_content2_;
+ typename T::Content remote_media_content1_;
+ typename T::Content remote_media_content2_;
// The RTP and RTCP packets to send in the tests.
std::string rtp_packet_;
std::string rtcp_packet_;
@@ -1111,6 +1316,13 @@
}
template<>
+void ChannelTest<VoiceTraits>::CopyContent(
+ const cricket::AudioContentDescription& source,
+ cricket::AudioContentDescription* audio) {
+ *audio = source;
+}
+
+template<>
bool ChannelTest<VoiceTraits>::CodecMatches(const cricket::AudioCodec& c1,
const cricket::AudioCodec& c2) {
return c1.name == c2.name && c1.clockrate == c2.clockrate &&
@@ -1120,8 +1332,7 @@
template<>
void ChannelTest<VoiceTraits>::AddLegacyStreamInContent(
uint32 ssrc, int flags, cricket::AudioContentDescription* audio) {
- if (flags & SSRC_MUX)
- audio->AddLegacyStream(ssrc);
+ audio->AddLegacyStream(ssrc);
}
class VoiceChannelTest
@@ -1152,7 +1363,7 @@
// override to add 0 parameter
template<>
bool ChannelTest<VideoTraits>::AddStream1(int id) {
- return channel1_->AddStream(id, 0);
+ return channel1_->AddRecvStream(cricket::StreamParams::CreateLegacy(id));
}
template<>
@@ -1171,6 +1382,13 @@
}
template<>
+void ChannelTest<VideoTraits>::CopyContent(
+ const cricket::VideoContentDescription& source,
+ cricket::VideoContentDescription* video) {
+ *video = source;
+}
+
+template<>
bool ChannelTest<VideoTraits>::CodecMatches(const cricket::VideoCodec& c1,
const cricket::VideoCodec& c2) {
return c1.name == c2.name && c1.width == c2.width && c1.height == c2.height &&
@@ -1180,8 +1398,7 @@
template<>
void ChannelTest<VideoTraits>::AddLegacyStreamInContent(
uint32 ssrc, int flags, cricket::VideoContentDescription* video) {
- if (flags & SSRC_MUX)
- video->AddLegacyStream(ssrc);
+ video->AddLegacyStream(ssrc);
}
class VideoChannelTest
@@ -1203,10 +1420,6 @@
EXPECT_TRUE(media_channel1_->dtmf_queue().empty());
}
-TEST_F(VoiceChannelTest, TestSetRtcpCName) {
- Base::TestSetRtcpCName();
-}
-
TEST_F(VoiceChannelTest, TestSetContents) {
Base::TestSetContents();
}
@@ -1227,6 +1440,18 @@
Base::TestStreams();
}
+TEST_F(VoiceChannelTest, TestUpdateStreamsInLocalContent) {
+ Base::TestUpdateStreamsInLocalContent();
+}
+
+TEST_F(VoiceChannelTest, TestUpdateRemoteStreamsInContent) {
+ Base::TestUpdateStreamsInRemoteContent();
+}
+
+TEST_F(VoiceChannelTest, TestChangeStreamParamsInContent) {
+ Base::TestChangeStreamParamsInContent();
+}
+
TEST_F(VoiceChannelTest, TestPlayoutAndSendingStates) {
Base::TestPlayoutAndSendingStates();
}
@@ -1495,10 +1720,6 @@
Base::TestInit();
}
-TEST_F(VideoChannelTest, TestSetRtcpCName) {
- Base::TestSetRtcpCName();
-}
-
TEST_F(VideoChannelTest, TestSetContents) {
Base::TestSetContents();
}
@@ -1519,6 +1740,18 @@
Base::TestStreams();
}
+TEST_F(VideoChannelTest, TestUpdateStreamsInLocalContent) {
+ Base::TestUpdateStreamsInLocalContent();
+}
+
+TEST_F(VideoChannelTest, TestUpdateRemoteStreamsInContent) {
+ Base::TestUpdateStreamsInRemoteContent();
+}
+
+TEST_F(VideoChannelTest, TestChangeStreamParamsInContent) {
+ Base::TestChangeStreamParamsInContent();
+}
+
TEST_F(VideoChannelTest, TestPlayoutAndSendingStates) {
Base::TestPlayoutAndSendingStates();
}
diff --git a/talk/session/phone/fakemediaengine.h b/talk/session/phone/fakemediaengine.h
index 1656b58..ee0f7e7 100644
--- a/talk/session/phone/fakemediaengine.h
+++ b/talk/session/phone/fakemediaengine.h
@@ -35,7 +35,9 @@
#include <vector>
#include "talk/base/buffer.h"
+#include "talk/p2p/base/sessiondescription.h"
#include "talk/session/phone/mediaengine.h"
+#include "talk/session/phone/streamparams.h"
#include "talk/session/phone/rtputils.h"
namespace cricket {
@@ -67,7 +69,6 @@
const std::list<std::string>& rtp_packets() const { return rtp_packets_; }
const std::list<std::string>& rtcp_packets() const { return rtcp_packets_; }
int options() const { return options_; }
- const uint32 send_ssrc() { return send_ssrc_; }
bool SendRtp(const void* data, int len) {
if (!sending_ || !Base::network_interface_) {
@@ -128,12 +129,57 @@
void set_fail_set_recv_codecs(bool fail) {
fail_set_recv_codecs_ = fail;
}
- virtual void SetSendSsrc(uint32 ssrc) {
- send_ssrc_ = ssrc;
+ virtual bool AddSendStream(const StreamParams& sp) {
+ if (std::find(send_streams_.begin(), send_streams_.end(), sp) !=
+ send_streams_.end()) {
+ return false;
+ }
+ send_streams_.push_back(sp);
+ return true;
+ }
+ virtual bool RemoveSendStream(uint32 ssrc) {
+ return RemoveStreamBySsrc(&send_streams_, ssrc);
+ }
+ virtual bool AddRecvStream(const StreamParams& sp) {
+ if (std::find(receive_streams_.begin(), receive_streams_.end(), sp) !=
+ receive_streams_.end()) {
+ return false;
+ }
+ receive_streams_.push_back(sp);
+ return true;
+ }
+ virtual bool RemoveRecvStream(uint32 ssrc) {
+ return RemoveStreamBySsrc(&receive_streams_, ssrc);
+ }
+ const std::vector<StreamParams>& send_streams() { return send_streams_; }
+ const std::vector<StreamParams>& recv_streams() {
+ return receive_streams_;
+ }
+ bool HasRecvStream(uint32 ssrc) const {
+ return GetStreamBySsrc(receive_streams_, ssrc, NULL);
+ }
+
+ // TODO: This is to support legacy unit test that only check one
+ // sending stream.
+ const uint32 send_ssrc() {
+ if (send_streams_.empty())
+ return 0;
+ return send_streams_[0].first_ssrc();
+ }
+
+ // TODO: This is to support legacy unit test that only check one
+ // sending stream.
+ const std::string rtcp_cname() {
+ if (send_streams_.empty())
+ return "";
+ return send_streams_[0].cname;
}
protected:
- void set_sending(bool send) { sending_ = send; }
+ bool set_sending(bool send) {
+ sending_ = send;
+ return true;
+ }
void set_playout(bool playout) { playout_ = playout; }
virtual void OnPacketReceived(talk_base::Buffer* packet) {
rtp_packets_.push_back(std::string(packet->data(), packet->length()));
@@ -156,9 +202,12 @@
std::vector<RtpHeaderExtension> send_extensions_;
std::list<std::string> rtp_packets_;
std::list<std::string> rtcp_packets_;
+ std::vector<StreamParams> send_streams_;
+ std::vector<StreamParams> receive_streams_;
bool fail_set_send_codecs_;
bool fail_set_recv_codecs_;
uint32 send_ssrc_;
+ std::string rtcp_cname_;
};
class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> {
@@ -178,9 +227,7 @@
const std::vector<AudioCodec>& send_codecs() const { return send_codecs_; }
const std::vector<AudioCodec>& codecs() const { return send_codecs(); }
bool muted() const { return muted_; }
- const std::set<uint32>& streams() const { return streams_; }
const std::vector<DtmfEvent>& dtmf_queue() const { return dtmf_queue_; }
- const std::string& rtcp_cname() const { return rtcp_cname_; }
uint32 ringback_tone_ssrc() const { return ringback_tone_ssrc_; }
bool ringback_tone_play() const { return ringback_tone_play_; }
@@ -210,26 +257,22 @@
if (fail_set_send_) {
return false;
}
- set_sending(flag != SEND_NOTHING);
- return true;
- }
- virtual bool SetRtcpCName(const std::string& cname) {
- rtcp_cname_ = cname;
- return true;
+ return set_sending(flag != SEND_NOTHING);
}
virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
virtual bool Mute(bool on) {
muted_ = on;
return true;
}
-
- virtual bool AddStream(uint32 ssrc) {
- streams_.insert(ssrc);
- output_scalings_[ssrc] = OutputScaling();
+ virtual bool AddRecvStream(const StreamParams& sp) {
+ if (!RtpHelper<VoiceMediaChannel>::AddRecvStream(sp))
+ return false;
+ output_scalings_[sp.first_ssrc()] = OutputScaling();
return true;
}
- virtual bool RemoveStream(uint32 ssrc) {
- streams_.erase(ssrc);
+ virtual bool RemoveRecvStream(uint32 ssrc) {
+ if (!RtpHelper<VoiceMediaChannel>::RemoveRecvStream(ssrc))
+ return false;
output_scalings_.erase(ssrc);
return true;
}
@@ -297,10 +340,8 @@
std::vector<AudioCodec> recv_codecs_;
std::vector<AudioCodec> send_codecs_;
bool muted_;
- std::set<uint32> streams_;
std::map<uint32, OutputScaling> output_scalings_;
std::vector<DtmfEvent> dtmf_queue_;
- std::string rtcp_cname_;
bool fail_set_send_;
uint32 ringback_tone_ssrc_;
bool ringback_tone_play_;
@@ -323,8 +364,7 @@
const std::vector<VideoCodec>& codecs() const { return send_codecs(); }
bool muted() const { return muted_; }
bool rendering() const { return playout(); }
- const std::map<uint32, VideoRenderer*>& streams() const { return streams_; }
- const std::string rtcp_cname() const { return rtcp_cname_; }
+ const std::map<uint32, VideoRenderer*>& renderers() const { return streams_; }
virtual bool SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
if (fail_set_recv_codecs()) {
@@ -357,8 +397,7 @@
}
virtual bool SetSend(bool send) {
- set_sending(send);
- return true;
+ return set_sending(send);
}
virtual bool AddScreencast(uint32 ssrc, const ScreencastId& id) {
screen_casting_ = true;
@@ -368,24 +407,20 @@
screen_casting_ = false;
return true;
}
- virtual bool SetRtcpCName(const std::string& cname) {
- rtcp_cname_ = cname;
- return true;
- }
virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
virtual bool Mute(bool on) {
muted_ = on;
return true;
}
-
- virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) {
- if (streams_.find(ssrc) != streams_.end()) {
+ virtual bool AddRecvStream(const StreamParams& sp) {
+ if (!RtpHelper<VideoMediaChannel>::AddRecvStream(sp))
return false;
- }
- streams_[ssrc] = NULL;
+ streams_[sp.first_ssrc()] = NULL;
return true;
}
- virtual bool RemoveStream(uint32 ssrc) {
+ virtual bool RemoveRecvStream(uint32 ssrc) {
+ if (!RtpHelper<VideoMediaChannel>::RemoveRecvStream(ssrc))
+ return false;
streams_.erase(ssrc);
return true;
}
@@ -415,7 +450,6 @@
std::map<uint32, VideoRenderer*> streams_;
bool muted_;
bool screen_casting_;
- std::string rtcp_cname_;
bool sent_intra_frame_;
bool requested_intra_frame_;
};
diff --git a/talk/session/phone/filemediaengine.cc b/talk/session/phone/filemediaengine.cc
index 2a7b8d8..6f2c5e1 100644
--- a/talk/session/phone/filemediaengine.cc
+++ b/talk/session/phone/filemediaengine.cc
@@ -34,6 +34,7 @@
#include "talk/base/stream.h"
#include "talk/session/phone/rtpdump.h"
#include "talk/session/phone/rtputils.h"
+#include "talk/session/phone/streamparams.h"
namespace cricket {
@@ -258,7 +259,8 @@
FileVoiceChannel::FileVoiceChannel(
talk_base::StreamInterface* input_file_stream,
talk_base::StreamInterface* output_file_stream)
- : rtp_sender_receiver_(new RtpSenderReceiver(this, input_file_stream,
+ : send_ssrc_(0),
+ rtp_sender_receiver_(new RtpSenderReceiver(this, input_file_stream,
output_file_stream)) {}
FileVoiceChannel::~FileVoiceChannel() {}
@@ -272,8 +274,22 @@
return rtp_sender_receiver_->SetSend(flag != SEND_NOTHING);
}
-void FileVoiceChannel::SetSendSsrc(uint32 ssrc) {
- rtp_sender_receiver_->SetSendSsrc(ssrc);
+bool FileVoiceChannel::AddSendStream(const StreamParams& sp) {
+ if (send_ssrc_ != 0 || sp.ssrcs.size() != 1) {
+ LOG(LS_ERROR) << "FileVoiceChannel only supports one send stream.";
+ return false;
+ }
+ send_ssrc_ = sp.ssrcs[0];
+ rtp_sender_receiver_->SetSendSsrc(send_ssrc_);
+ return true;
+}
+
+bool FileVoiceChannel::RemoveSendStream(uint32 ssrc) {
+ if (ssrc != send_ssrc_)
+ return false;
+ send_ssrc_ = 0;
+ rtp_sender_receiver_->SetSendSsrc(send_ssrc_);
+ return true;
}
void FileVoiceChannel::OnPacketReceived(talk_base::Buffer* packet) {
@@ -286,7 +302,8 @@
FileVideoChannel::FileVideoChannel(
talk_base::StreamInterface* input_file_stream,
talk_base::StreamInterface* output_file_stream)
- : rtp_sender_receiver_(new RtpSenderReceiver(this, input_file_stream,
+ : send_ssrc_(0),
+ rtp_sender_receiver_(new RtpSenderReceiver(this, input_file_stream,
output_file_stream)) {}
FileVideoChannel::~FileVideoChannel() {}
@@ -300,8 +317,22 @@
return rtp_sender_receiver_->SetSend(send);
}
-void FileVideoChannel::SetSendSsrc(uint32 ssrc) {
- rtp_sender_receiver_->SetSendSsrc(ssrc);
+bool FileVideoChannel::AddSendStream(const StreamParams& sp) {
+ if (send_ssrc_ != 0 || sp.ssrcs.size() != 1) {
+ LOG(LS_ERROR) << "FileVideoChannel only support one send stream.";
+ return false;
+ }
+ send_ssrc_ = sp.ssrcs[0];
+ rtp_sender_receiver_->SetSendSsrc(send_ssrc_);
+ return true;
+}
+
+bool FileVideoChannel::RemoveSendStream(uint32 ssrc) {
+ if (ssrc != send_ssrc_)
+ return false;
+ send_ssrc_ = 0;
+ rtp_sender_receiver_->SetSendSsrc(send_ssrc_);
+ return true;
}
void FileVideoChannel::OnPacketReceived(talk_base::Buffer* packet) {
diff --git a/talk/session/phone/filemediaengine.h b/talk/session/phone/filemediaengine.h
index 8f61638..f181dc8 100644
--- a/talk/session/phone/filemediaengine.h
+++ b/talk/session/phone/filemediaengine.h
@@ -165,8 +165,6 @@
}
virtual bool SetPlayout(bool playout) { return true; }
virtual bool SetSend(SendFlags flag);
- virtual bool AddStream(uint32 ssrc) { return true; }
- virtual bool RemoveStream(uint32 ssrc) { return true; }
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) { return true; }
virtual int GetOutputLevel() { return 0; }
virtual bool SetOutputScaling(uint32 ssrc, double left, double right) {
@@ -185,13 +183,16 @@
// Implement pure virtual methods of MediaChannel.
virtual void OnPacketReceived(talk_base::Buffer* packet);
virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
- virtual void SetSendSsrc(uint32 ssrc);
- virtual bool SetRtcpCName(const std::string& cname) { return true; }
+ virtual bool AddSendStream(const StreamParams& sp);
+ virtual bool RemoveSendStream(uint32 ssrc);
+ virtual bool AddRecvStream(const StreamParams& sp) { return true; }
+ virtual bool RemoveRecvStream(uint32 ssrc) { return true; }
virtual bool Mute(bool on) { return false; }
virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
virtual bool SetOptions(int options) { return true; }
private:
+ uint32 send_ssrc_;
talk_base::scoped_ptr<RtpSenderReceiver> rtp_sender_receiver_;
DISALLOW_COPY_AND_ASSIGN(FileVoiceChannel);
};
@@ -217,8 +218,6 @@
}
virtual bool SetRender(bool render) { return true; }
virtual bool SetSend(bool send);
- virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) { return true; }
- virtual bool RemoveStream(uint32 ssrc) { return true; }
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
return true;
}
@@ -233,13 +232,16 @@
// Implement pure virtual methods of MediaChannel.
virtual void OnPacketReceived(talk_base::Buffer* packet);
virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
- virtual void SetSendSsrc(uint32 ssrc);
- virtual bool SetRtcpCName(const std::string& cname) { return true; }
+ virtual bool AddSendStream(const StreamParams& sp);
+ virtual bool RemoveSendStream(uint32 ssrc);
+ virtual bool AddRecvStream(const StreamParams& sp) { return true; }
+ virtual bool RemoveRecvStream(uint32 ssrc) { return true; }
virtual bool Mute(bool on) { return false; }
virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
virtual bool SetOptions(int options) { return true; }
private:
+ uint32 send_ssrc_;
talk_base::scoped_ptr<RtpSenderReceiver> rtp_sender_receiver_;
DISALLOW_COPY_AND_ASSIGN(FileVideoChannel);
};
diff --git a/talk/session/phone/filemediaengine_unittest.cc b/talk/session/phone/filemediaengine_unittest.cc
index cab7120..c915251 100644
--- a/talk/session/phone/filemediaengine_unittest.cc
+++ b/talk/session/phone/filemediaengine_unittest.cc
@@ -34,6 +34,7 @@
#include "talk/base/stream.h"
#include "talk/session/phone/filemediaengine.h"
#include "talk/session/phone/rtpdump.h"
+#include "talk/session/phone/streamparams.h"
#include "talk/session/phone/testutils.h"
namespace cricket {
@@ -379,7 +380,7 @@
voice_output_filename_, "", "", 1));
EXPECT_TRUE(NULL != voice_channel_.get());
const uint32 send_ssrc = RtpTestUtility::kDefaultSsrc + 1;
- voice_channel_->SetSendSsrc(send_ssrc);
+ voice_channel_->AddSendStream(StreamParams::CreateLegacy(send_ssrc));
talk_base::MemoryStream net_dump;
FileNetworkInterface net_interface(&net_dump, voice_channel_.get());
diff --git a/talk/session/phone/mediachannel.h b/talk/session/phone/mediachannel.h
index b1022e8..83aa3e4 100644
--- a/talk/session/phone/mediachannel.h
+++ b/talk/session/phone/mediachannel.h
@@ -46,6 +46,7 @@
namespace cricket {
class ScreencastId;
+struct StreamParams;
class VideoRenderer;
const int kMinRtpHeaderExtensionId = 1;
@@ -116,10 +117,21 @@
virtual void OnPacketReceived(talk_base::Buffer* packet) = 0;
// Called when a RTCP packet is received.
virtual void OnRtcpReceived(talk_base::Buffer* packet) = 0;
- // Sets the SSRC to be used for outgoing data.
- virtual void SetSendSsrc(uint32 id) = 0;
- // Set the CNAME of RTCP
- virtual bool SetRtcpCName(const std::string& cname) = 0;
+ // Creates a new outgoing media stream with SSRCs and CNAME as described
+ // by sp.
+ virtual bool AddSendStream(const StreamParams& sp) = 0;
+ // Removes an outgoing media stream.
+ // ssrc must be the first SSRC of the media stream if the stream uses
+ // multiple SSRCs.
+ virtual bool RemoveSendStream(uint32 ssrc) = 0;
+ // Creates a new incoming media stream with SSRCs and CNAME as described
+ // by sp.
+ virtual bool AddRecvStream(const StreamParams& sp) = 0;
+ // Removes an incoming media stream.
+ // ssrc must be the first SSRC of the media stream if the stream uses
+ // multiple SSRCs.
+ virtual bool RemoveRecvStream(uint32 ssrc) = 0;
+
// Mutes the channel.
virtual bool Mute(bool on) = 0;
@@ -348,10 +360,6 @@
virtual bool SetPlayout(bool playout) = 0;
// Starts or stops sending (and potentially capture) of local audio.
virtual bool SetSend(SendFlags flag) = 0;
- // Adds a new receive-only stream with the specified SSRC.
- virtual bool AddStream(uint32 ssrc) = 0;
- // Removes a stream added with AddStream.
- virtual bool RemoveStream(uint32 ssrc) = 0;
// Gets current energy levels for all incoming streams.
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) = 0;
// Get the current energy level of the stream sent to the speaker.
@@ -406,10 +414,6 @@
virtual bool SetRender(bool render) = 0;
// Starts or stops transmission (and potentially capture) of local video.
virtual bool SetSend(bool send) = 0;
- // Adds a new receive-only stream with the specified SSRC.
- virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) = 0;
- // Removes a stream added with AddStream.
- virtual bool RemoveStream(uint32 ssrc) = 0;
// Sets the renderer object to be used for the specified stream.
// If SSRC is 0, the renderer is used for the 'default' stream.
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) = 0;
diff --git a/talk/session/phone/mediasession.cc b/talk/session/phone/mediasession.cc
index 4e66872..0784b56 100644
--- a/talk/session/phone/mediasession.cc
+++ b/talk/session/phone/mediasession.cc
@@ -105,17 +105,6 @@
return false;
}
-static const StreamParams* FindStreamParamsByName(
- const StreamParamsVec& params_vec,
- const std::string& name) {
- for (StreamParamsVec::const_iterator it = params_vec.begin();
- it != params_vec.end(); ++it) {
- if (it->name == name)
- return &*it;
- }
- return NULL;
-}
-
static const StreamParams* FindFirstStreamParamsByCname(
const StreamParamsVec& params_vec,
const std::string& cname) {
@@ -127,21 +116,6 @@
return NULL;
}
-static const StreamParams* FindStreamParamsBySsrc(
- const StreamParamsVec& params_vec,
- uint32 ssrc) {
- for (StreamParamsVec::const_iterator stream_it = params_vec.begin();
- stream_it != params_vec.end(); ++stream_it) {
- const std::vector<uint32>& ssrcs = stream_it->ssrcs;
- for (std::vector<uint32>::const_iterator ssrc_it = ssrcs.begin();
- ssrc_it != ssrcs.end(); ++ssrc_it) {
- if (ssrc == *ssrc_it)
- return &*stream_it;
- }
- }
- return NULL;
-}
-
// Generates a new CNAME or the CNAME of an already existing StreamParams
// if a StreamParams exist for another Stream in streams with sync_label
// sync_label.
@@ -158,10 +132,13 @@
stream_it != streams.end() ; ++stream_it) {
if (synch_label != stream_it->sync_label)
continue;
- const StreamParams* param = FindStreamParamsByName(params_vec,
- stream_it->name);
- if (param) {
- *cname = param->cname;
+
+ StreamParams param;
+ // nick is empty for StreamParams generated using
+ // MediaSessionDescriptionFactory.
+ if (GetStreamByNickAndName(params_vec, "", stream_it->name,
+ ¶m)) {
+ *cname = param.cname;
return true;
}
}
@@ -183,7 +160,7 @@
uint32 ssrc = 0;
do {
ssrc = talk_base::CreateRandomNonZeroId();
- } while (FindStreamParamsBySsrc(params_vec, ssrc));
+ } while (GetStreamBySsrc(params_vec, ssrc, NULL));
return ssrc;
}
@@ -221,9 +198,11 @@
stream_it != streams.end(); ++stream_it) {
if (stream_it->type != media_type)
continue; // Wrong media type.
- const StreamParams* params = FindStreamParamsByName(*current_params,
- stream_it->name);
- if (!params) {
+
+ StreamParams param;
+ // nick is empty for StreamParams generated using
+ // MediaSessionDescriptionFactory.
+ if (!GetStreamByNickAndName(*current_params, "", stream_it->name, ¶m)) {
// This is a new stream.
// Get a CNAME. Either new or same as one of the other synched streams.
std::string cname;
@@ -245,7 +224,7 @@
// This is necessary so that we can use the CNAME for other media types.
current_params->push_back(stream_param);
} else {
- content_description->AddStream(*params);
+ content_description->AddStream(param);
}
}
return true;
diff --git a/talk/session/phone/mediasession.h b/talk/session/phone/mediasession.h
index 4a10836..c35a994 100644
--- a/talk/session/phone/mediasession.h
+++ b/talk/session/phone/mediasession.h
@@ -46,7 +46,6 @@
typedef std::vector<AudioCodec> AudioCodecs;
typedef std::vector<VideoCodec> VideoCodecs;
typedef std::vector<CryptoParams> CryptoParamsVec;
-typedef std::vector<StreamParams> StreamParamsVec;
// SEC_ENABLED and SEC_REQUIRED should only be used if the session
// was negotiated over TLS, to protect the inline crypto material
@@ -179,7 +178,15 @@
void AddLegacyStream(uint32 ssrc) {
streams_.push_back(StreamParams::CreateLegacy(ssrc));
}
-
+ // Sets the CNAME of all StreamParams if it have not been set.
+ // This can be used to set the CNAME of legacy streams.
+ void SetCnameIfEmpty(const std::string& cname) {
+ for (cricket::StreamParamsVec::iterator it = streams_.begin();
+ it != streams_.end(); ++it) {
+ if (it->cname.empty())
+ it->cname = cname;
+ }
+ }
uint32 first_ssrc() const {
if (streams_.empty()) {
return 0;
diff --git a/talk/session/phone/mediasessionclient_unittest.cc b/talk/session/phone/mediasessionclient_unittest.cc
index 574b052..0b99106 100644
--- a/talk/session/phone/mediasessionclient_unittest.cc
+++ b/talk/session/phone/mediasessionclient_unittest.cc
@@ -2133,14 +2133,11 @@
cricket::FakeVoiceMediaChannel* voice_channel = fme_->GetVoiceChannel(0);
ASSERT_TRUE(voice_channel != NULL);
- ASSERT_TRUE(
- voice_channel->streams().find(1234U) != voice_channel->streams().end());
- ASSERT_TRUE(
- voice_channel->streams().find(2468U) != voice_channel->streams().end());
+ ASSERT_TRUE(voice_channel->HasRecvStream(1234U));
+ ASSERT_TRUE(voice_channel->HasRecvStream(2468U));
cricket::FakeVideoMediaChannel* video_channel = fme_->GetVideoChannel(0);
ASSERT_TRUE(video_channel != NULL);
- ASSERT_TRUE(
- video_channel->streams().find(5678U) != video_channel->streams().end());
+ ASSERT_TRUE(video_channel->HasRecvStream(5678U));
ClearStanzas();
cricket::ViewRequest viewRequest;
@@ -2194,14 +2191,11 @@
voice_channel = fme_->GetVoiceChannel(0);
ASSERT_TRUE(voice_channel != NULL);
- ASSERT_FALSE(
- voice_channel->streams().find(1234U) != voice_channel->streams().end());
- ASSERT_TRUE(
- voice_channel->streams().find(2468U) != voice_channel->streams().end());
+ ASSERT_FALSE(voice_channel->HasRecvStream(1234U));
+ ASSERT_TRUE(voice_channel->HasRecvStream(2468U));
video_channel = fme_->GetVideoChannel(0);
ASSERT_TRUE(video_channel != NULL);
- ASSERT_FALSE(
- video_channel->streams().find(5678U) != video_channel->streams().end());
+ ASSERT_FALSE(video_channel->HasRecvStream(5678U));
// Fails because ssrc is now invalid.
ASSERT_FALSE(
diff --git a/talk/session/phone/srtpfilter.cc b/talk/session/phone/srtpfilter.cc
index dbff814..af02a7c 100644
--- a/talk/session/phone/srtpfilter.cc
+++ b/talk/session/phone/srtpfilter.cc
@@ -34,6 +34,7 @@
#include "talk/base/base64.h"
#include "talk/base/logging.h"
+#include "talk/base/stringencode.h"
#include "talk/base/timeutils.h"
#include "talk/session/phone/rtputils.h"
@@ -65,6 +66,8 @@
const char CS_AES_CM_128_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80";
const char CS_AES_CM_128_HMAC_SHA1_32[] = "AES_CM_128_HMAC_SHA1_32";
const int SRTP_MASTER_KEY_BASE64_LEN = SRTP_MASTER_KEY_LEN * 4 / 3;
+const int SRTP_MASTER_KEY_KEY_LEN = 16;
+const int SRTP_MASTER_KEY_SALT_LEN = 14;
#ifndef HAVE_SRTP
@@ -143,6 +146,68 @@
return ret;
}
+bool SrtpFilter::SetRtpParams(const std::string& send_cs,
+ const uint8* send_key, int send_key_len,
+ const std::string& recv_cs,
+ const uint8* recv_key, int recv_key_len) {
+ if (state_ == ST_ACTIVE) {
+ LOG(LS_ERROR) << "Tried to set SRTP Params when filter already active";
+ return false;
+ }
+ CreateSrtpSessions();
+ if (!send_session_->SetSend(send_cs, send_key, send_key_len))
+ return false;
+
+ if (!recv_session_->SetRecv(recv_cs, recv_key, recv_key_len))
+ return false;
+
+ state_ = ST_ACTIVE;
+
+ LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
+ << " send cipher_suite " << send_cs
+ << " recv cipher_suite " << recv_cs;
+
+ return true;
+}
+
+// This function is provided separately because DTLS-SRTP behaves
+// differently in RTP/RTCP mux and non-mux modes.
+//
+// - In the non-muxed case, RTP and RTCP are keyed with different
+// keys (from different DTLS handshakes), and so we need a new
+// SrtpSession.
+// - In the muxed case, they are keyed with the same keys, so
+// this function is not needed
+bool SrtpFilter::SetRtcpParams(const std::string& send_cs,
+ const uint8* send_key, int send_key_len,
+ const std::string& recv_cs,
+ const uint8* recv_key, int recv_key_len) {
+ // This can only be called once, but can be safely called after
+ // SetRtpParams
+ if (send_rtcp_session_.get() || send_rtcp_session_.get()) {
+ LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
+ return false;
+ }
+
+ send_rtcp_session_.reset(new SrtpSession());
+ SignalSrtpError.repeat(send_rtcp_session_->SignalSrtpError);
+ send_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms_);
+ if (!send_rtcp_session_->SetRecv(send_cs, send_key, send_key_len))
+ return false;
+
+ recv_rtcp_session_.reset(new SrtpSession());
+ SignalSrtpError.repeat(recv_rtcp_session_->SignalSrtpError);
+ recv_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms_);
+ if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len))
+ return false;
+
+ LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
+ << " send cipher_suite " << send_cs
+ << " recv cipher_suite " << recv_cs;
+
+ return true;
+}
+
bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
if (!IsActive()) {
LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
@@ -156,7 +221,11 @@
LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
return false;
}
- return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
+ if (send_rtcp_session_.get()) {
+ return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
+ } else {
+ return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
+ }
}
bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) {
@@ -172,7 +241,11 @@
LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
return false;
}
- return recv_session_->UnprotectRtcp(p, in_len, out_len);
+ if (recv_rtcp_session_.get()) {
+ return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
+ } else {
+ return recv_session_->UnprotectRtcp(p, in_len, out_len);
+ }
}
void SrtpFilter::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
@@ -180,6 +253,10 @@
if (state_ == ST_ACTIVE) {
send_session_->set_signal_silent_time(signal_silent_time_in_ms);
recv_session_->set_signal_silent_time(signal_silent_time_in_ms);
+ if (send_rtcp_session_.get())
+ send_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms);
+ if (recv_rtcp_session_.get())
+ recv_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms);
}
}
diff --git a/talk/session/phone/srtpfilter.h b/talk/session/phone/srtpfilter.h
index aad461a..da7a236 100644
--- a/talk/session/phone/srtpfilter.h
+++ b/talk/session/phone/srtpfilter.h
@@ -57,6 +57,10 @@
// Key is 128 bits and salt is 112 bits == 30 bytes. B64 bloat => 40 bytes.
extern const int SRTP_MASTER_KEY_BASE64_LEN;
+// Needed for DTLS-SRTP
+extern const int SRTP_MASTER_KEY_KEY_LEN;
+extern const int SRTP_MASTER_KEY_SALT_LEN;
+
class SrtpSession;
class SrtpStat;
@@ -99,6 +103,17 @@
bool SetAnswer(const std::vector<CryptoParams>& answer_params,
ContentSource source);
+ // Just set up both sets of keys directly.
+ // Used with DTLS-SRTP.
+ bool SetRtpParams(const std::string& send_cs,
+ const uint8* send_key, int send_key_len,
+ const std::string& recv_cs,
+ const uint8* recv_key, int recv_key_len);
+ bool SetRtcpParams(const std::string& send_cs,
+ const uint8* send_key, int send_key_len,
+ const std::string& recv_cs,
+ const uint8* recv_key, int recv_key_len);
+
// Encrypts/signs an individual RTP/RTCP packet, in-place.
// If an HMAC is used, this will increase the packet size.
bool ProtectRtp(void* data, int in_len, int max_len, int* out_len);
@@ -142,6 +157,8 @@
std::vector<CryptoParams> offer_params_;
talk_base::scoped_ptr<SrtpSession> send_session_;
talk_base::scoped_ptr<SrtpSession> recv_session_;
+ talk_base::scoped_ptr<SrtpSession> send_rtcp_session_;
+ talk_base::scoped_ptr<SrtpSession> recv_rtcp_session_;
};
// Class that wraps a libSRTP session.
diff --git a/talk/session/phone/srtpfilter_unittest.cc b/talk/session/phone/srtpfilter_unittest.cc
index fe93908..276c341 100644
--- a/talk/session/phone/srtpfilter_unittest.cc
+++ b/talk/session/phone/srtpfilter_unittest.cc
@@ -365,6 +365,64 @@
EXPECT_FALSE(f2_.IsActive());
}
+// Test directly setting the params with AES_CM_128_HMAC_SHA1_80
+TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_80) {
+ EXPECT_TRUE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey2, kTestKeyLen));
+ EXPECT_TRUE(f2_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey2, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey2, kTestKeyLen));
+ EXPECT_TRUE(f2_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey2, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(f1_.IsActive());
+ EXPECT_TRUE(f2_.IsActive());
+ TestProtectUnprotect(CS_AES_CM_128_HMAC_SHA1_80, CS_AES_CM_128_HMAC_SHA1_80);
+}
+
+// Test directly setting the params with AES_CM_128_HMAC_SHA1_32
+TEST_F(SrtpFilterTest, TestProtect_SetParamsDirect_AES_CM_128_HMAC_SHA1_32) {
+ EXPECT_TRUE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey1, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey2, kTestKeyLen));
+ EXPECT_TRUE(f2_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey2, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey1, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey2, kTestKeyLen));
+ EXPECT_TRUE(f2_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey2, kTestKeyLen,
+ CS_AES_CM_128_HMAC_SHA1_32,
+ kTestKey1, kTestKeyLen));
+ EXPECT_TRUE(f1_.IsActive());
+ EXPECT_TRUE(f2_.IsActive());
+ TestProtectUnprotect(CS_AES_CM_128_HMAC_SHA1_32, CS_AES_CM_128_HMAC_SHA1_32);
+}
+
+// Test directly setting the params with bogus keys
+TEST_F(SrtpFilterTest, TestSetParamsKeyTooShort) {
+ EXPECT_FALSE(f1_.SetRtpParams(CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen - 1,
+ CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen - 1));
+ EXPECT_FALSE(f1_.SetRtcpParams(CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen - 1,
+ CS_AES_CM_128_HMAC_SHA1_80,
+ kTestKey1, kTestKeyLen - 1));
+}
+
class SrtpSessionTest : public testing::Test {
protected:
virtual void SetUp() {
diff --git a/talk/session/phone/ssrcmuxfilter.cc b/talk/session/phone/ssrcmuxfilter.cc
index c0da3ee..d81feab 100644
--- a/talk/session/phone/ssrcmuxfilter.cc
+++ b/talk/session/phone/ssrcmuxfilter.cc
@@ -32,44 +32,6 @@
#include "talk/base/logging.h"
#include "talk/session/phone/rtputils.h"
-namespace {
-
-using cricket::StreamParams;
-
-// TODO: Remove this function once cl 25538785 is landed.
-bool GetStreamBySsrc(const std::vector<StreamParams>& streams, uint32 ssrc,
- StreamParams* stream_out) {
- for (std::vector<StreamParams>::const_iterator stream = streams.begin();
- stream != streams.end(); ++stream) {
- if (std::find(stream->ssrcs.begin(), stream->ssrcs.end(),
- ssrc) != stream->ssrcs.end()) {
- if (stream_out != NULL) {
- *stream_out = *stream;
- }
- return true;
- }
- }
- return false;
-}
-
-// TODO: Remove this function once cl 25538785 is landed.
-bool RemoveStreamBySsrc(std::vector<StreamParams>* streams, uint32 ssrc) {
- bool ret = false;
- for (std::vector<StreamParams>::iterator stream = streams->begin();
- stream != streams->end(); ) {
- if (std::find(stream->ssrcs.begin(), stream->ssrcs.end(),
- ssrc) != stream->ssrcs.end()) {
- stream = streams->erase(stream);
- ret = true;
- } else {
- ++stream;
- }
- }
- return ret;
-}
-
-} // namespace
-
namespace cricket {
static const uint32 kSsrc01 = 0x01;
diff --git a/talk/session/phone/streamparams.cc b/talk/session/phone/streamparams.cc
new file mode 100644
index 0000000..415c4c7
--- /dev/null
+++ b/talk/session/phone/streamparams.cc
@@ -0,0 +1,90 @@
+/*
+ * 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/session/phone/streamparams.h"
+
+namespace cricket {
+
+bool GetStreamBySsrc(const StreamParamsVec& streams, uint32 ssrc,
+ StreamParams* stream_out) {
+ for (StreamParamsVec::const_iterator stream = streams.begin();
+ stream != streams.end(); ++stream) {
+ if (stream->has_ssrc(ssrc)) {
+ if (stream_out != NULL)
+ *stream_out = *stream;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GetStreamByNickAndName(const StreamParamsVec& streams,
+ const std::string& nick,
+ const std::string& name,
+ StreamParams* stream_out) {
+ for (StreamParamsVec::const_iterator stream = streams.begin();
+ stream != streams.end(); ++stream) {
+ if (stream->nick == nick && stream->name == name) {
+ if (stream_out != NULL)
+ *stream_out = *stream;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RemoveStreamBySsrc(StreamParamsVec* streams, uint32 ssrc) {
+ bool ret = false;
+ for (StreamParamsVec::iterator stream = streams->begin();
+ stream != streams->end(); ) {
+ if (stream->has_ssrc(ssrc)) {
+ stream = streams->erase(stream);
+ ret = true;
+ } else {
+ ++stream;
+ }
+ }
+ return ret;
+}
+
+bool RemoveStreamByNickAndName(StreamParamsVec* streams,
+ const std::string& nick,
+ const std::string& name) {
+ bool ret = false;
+ for (StreamParamsVec::iterator stream = streams->begin();
+ stream != streams->end(); ) {
+ if (stream->nick == nick && stream->name == name) {
+ stream = streams->erase(stream);
+ ret = true;
+ } else {
+ ++stream;
+ }
+ }
+ return ret;
+}
+
+} // namespace cricket
diff --git a/talk/session/phone/streamparams.h b/talk/session/phone/streamparams.h
index ec4b380..3e2bd94 100644
--- a/talk/session/phone/streamparams.h
+++ b/talk/session/phone/streamparams.h
@@ -43,9 +43,12 @@
#ifndef TALK_SESSION_PHONE_STREAMPARAMS_H_
#define TALK_SESSION_PHONE_STREAMPARAMS_H_
+#include <algorithm>
#include <string>
#include <vector>
+#include "talk/base/basictypes.h"
+
namespace cricket {
struct SsrcGroup {
@@ -94,6 +97,9 @@
bool has_ssrcs() const {
return !ssrcs.empty();
}
+ bool has_ssrc(uint32 ssrc) const {
+ return std::find(ssrcs.begin(), ssrcs.end(), ssrc) != ssrcs.end();
+ }
// Resource of the MUC jid of the participant of with this stream.
// For 1:1 calls, should be left empty (which means remote streams
@@ -111,6 +117,29 @@
std::string sync_label; // Friendly name of cname.
};
+typedef std::vector<StreamParams> StreamParamsVec;
+
+// Finds the stream in streams with the specified ssrc.
+// If you are only interested in the stream exist it is ok to call this function
+// stream_out = NULL.
+bool GetStreamBySsrc(const StreamParamsVec& streams, uint32 ssrc,
+ StreamParams* stream_out);
+
+// Finds the stream in streams with the specified nick and name.
+// If you are only interested in the stream exist it is ok to call this function
+// stream_out = NULL.
+bool GetStreamByNickAndName(const StreamParamsVec& streams,
+ const std::string& nick,
+ const std::string& name,
+ StreamParams* stream_out);
+
+// Removes the stream with ssrc from streams. Returns true if a stream is
+// removed, false otherwise.
+bool RemoveStreamBySsrc(StreamParamsVec* streams, uint32 ssrc);
+bool RemoveStreamByNickAndName(StreamParamsVec* streams,
+ const std::string& nick,
+ const std::string& name);
+
} // namespace cricket
#endif // TALK_SESSION_PHONE_STREAMPARAMS_H_
diff --git a/talk/session/phone/testutils.cc b/talk/session/phone/testutils.cc
index 679506a..f427f96 100644
--- a/talk/session/phone/testutils.cc
+++ b/talk/session/phone/testutils.cc
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2011 Google Inc.
+ * Copyright 2004 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -29,6 +29,9 @@
#include <math.h>
+#ifdef HAVE_YUV
+#include "libyuv/compare.h"
+#endif
#include "talk/base/bytebuffer.h"
#include "talk/base/fileutils.h"
#include "talk/base/gunit.h"
@@ -277,14 +280,17 @@
return 10.0 * log10(65025.0 * size / sse);
}
-double ComputeSumSquareError(const uint8 *org, const uint8 *rec,
- int size) {
+double ComputeSumSquareError(const uint8 *org, const uint8 *rec, int size) {
+#ifdef HAVE_YUV
+ return static_cast<double>(libyuv::ComputeSumSquareError(org, rec, size));
+#else
double sse = 0.;
for (int j = 0; j < size; ++j) {
const int diff = static_cast<int>(org[j]) - static_cast<int>(rec[j]);
sse += static_cast<double>(diff * diff);
}
return sse;
+#endif
}
// Loads the image with the specified prefix and size into |out|.
diff --git a/talk/session/phone/testutils.h b/talk/session/phone/testutils.h
index b4ce454..f5556e7 100644
--- a/talk/session/phone/testutils.h
+++ b/talk/session/phone/testutils.h
@@ -1,6 +1,6 @@
/*
* libjingle
- * Copyright 2004--2011 Google Inc.
+ * Copyright 2004 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
diff --git a/talk/session/phone/videocommon.h b/talk/session/phone/videocommon.h
index 6662bfc..fa695f0 100644
--- a/talk/session/phone/videocommon.h
+++ b/talk/session/phone/videocommon.h
@@ -36,34 +36,26 @@
namespace cricket {
//////////////////////////////////////////////////////////////////////////////
-// Definition of fourcc.
+// Definition of FourCC codes
//////////////////////////////////////////////////////////////////////////////
-// Convert four characters to a fourcc code.
+// Convert four characters to a FourCC code.
// Needs to be a macro otherwise the OS X compiler complains when the kFormat*
// constants are used in a switch.
-#define FOURCC(a, b, c, d) (\
+#define FOURCC(a, b, c, d) ( \
(static_cast<uint32>(a)) | (static_cast<uint32>(b) << 8) | \
(static_cast<uint32>(c) << 16) | (static_cast<uint32>(d) << 24))
-// Get the name, that is, string with four characters, of a fourcc code.
-inline std::string GetFourccName(uint32 fourcc) {
- std::string name;
- name.push_back(static_cast<char>(fourcc & 0xFF));
- name.push_back(static_cast<char>((fourcc >> 8) & 0xFF));
- name.push_back(static_cast<char>((fourcc >> 16) & 0xFF));
- name.push_back(static_cast<char>((fourcc >> 24) & 0xFF));
- return name;
-}
-
-// FourCC codes used in Google Talk.
-// Some good pages discussing FourCC codes:
-// http://developer.apple.com/quicktime/icefloe/dispatch020.html
+// Some pages discussing FourCC codes:
// http://www.fourcc.org/yuv.php
+// http://v4l2spec.bytesex.org/spec/book1.htm
+// http://developer.apple.com/quicktime/icefloe/dispatch020.html
+
enum FourCC {
// Canonical fourcc codes used in our code.
FOURCC_I420 = FOURCC('I', '4', '2', '0'),
FOURCC_I422 = FOURCC('I', '4', '2', '2'),
FOURCC_I444 = FOURCC('I', '4', '4', '4'),
+ FOURCC_I400 = FOURCC('I', '4', '0', '0'),
FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
@@ -75,6 +67,9 @@
FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'),
+ FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // bgr565
+ FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // abgr1555
+ FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444
FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
FOURCC_RAW = FOURCC('r', 'a', 'w', ' '),
FOURCC_NV21 = FOURCC('N', 'V', '2', '1'),
@@ -109,6 +104,16 @@
// Converts fourcc aliases into canonical ones.
uint32 CanonicalFourCC(uint32 fourcc);
+// Get FourCC code as a string
+inline std::string GetFourccName(uint32 fourcc) {
+ std::string name;
+ name.push_back(static_cast<char>(fourcc & 0xFF));
+ name.push_back(static_cast<char>((fourcc >> 8) & 0xFF));
+ name.push_back(static_cast<char>((fourcc >> 16) & 0xFF));
+ name.push_back(static_cast<char>((fourcc >> 24) & 0xFF));
+ return name;
+}
+
//////////////////////////////////////////////////////////////////////////////
// Definition of VideoFormat.
//////////////////////////////////////////////////////////////////////////////
diff --git a/talk/session/phone/webrtcvideoengine.cc b/talk/session/phone/webrtcvideoengine.cc
index 2fae254..9667538 100644
--- a/talk/session/phone/webrtcvideoengine.cc
+++ b/talk/session/phone/webrtcvideoengine.cc
@@ -40,6 +40,7 @@
#include "talk/base/logging.h"
#include "talk/base/stringutils.h"
#include "talk/session/phone/rtputils.h"
+#include "talk/session/phone/streamparams.h"
#include "talk/session/phone/videorenderer.h"
#include "talk/session/phone/webrtcpassthroughrender.h"
#include "talk/session/phone/webrtcvoiceengine.h"
@@ -58,6 +59,7 @@
static const int kMinVideoBitrate = 100;
static const int kStartVideoBitrate = 300;
static const int kMaxVideoBitrate = 2000;
+static const int kConferenceModeMaxVideoBitrate = 500;
static const int kVideoMtu = 1200;
@@ -535,6 +537,11 @@
return false;
}
LOG(LS_INFO) << "Camera created with VCM";
+ CaptureResult ret = SetCapture(true);
+ if (ret != cricket::CR_SUCCESS && ret != cricket::CR_PENDING) {
+ LOG(LS_ERROR) << "Failed to start camera.";
+ return false;
+ }
return true;
}
@@ -764,21 +771,21 @@
}
void WebRtcVideoEngine::ConvertToCricketVideoCodec(
- const webrtc::VideoCodec& in_codec, VideoCodec& out_codec) {
- out_codec.id = in_codec.plType;
- out_codec.name = in_codec.plName;
- out_codec.width = in_codec.width;
- out_codec.height = in_codec.height;
- out_codec.framerate = in_codec.maxFramerate;
+ const webrtc::VideoCodec& in_codec, VideoCodec* out_codec) {
+ out_codec->id = in_codec.plType;
+ out_codec->name = in_codec.plName;
+ out_codec->width = in_codec.width;
+ out_codec->height = in_codec.height;
+ out_codec->framerate = in_codec.maxFramerate;
}
bool WebRtcVideoEngine::ConvertFromCricketVideoCodec(
- const VideoCodec& in_codec, webrtc::VideoCodec& out_codec) {
+ const VideoCodec& in_codec, webrtc::VideoCodec* out_codec) {
bool found = false;
int ncodecs = vie_wrapper_->codec()->NumberOfCodecs();
for (int i = 0; i < ncodecs; ++i) {
- if (vie_wrapper_->codec()->GetCodec(i, out_codec) == 0 &&
- in_codec.name == out_codec.plName) {
+ if (vie_wrapper_->codec()->GetCodec(i, *out_codec) == 0 &&
+ in_codec.name == out_codec->plName) {
found = true;
break;
}
@@ -790,21 +797,21 @@
}
if (in_codec.id != 0)
- out_codec.plType = in_codec.id;
+ out_codec->plType = in_codec.id;
if (in_codec.width != 0)
- out_codec.width = in_codec.width;
+ out_codec->width = in_codec.width;
if (in_codec.height != 0)
- out_codec.height = in_codec.height;
+ out_codec->height = in_codec.height;
if (in_codec.framerate != 0)
- out_codec.maxFramerate = in_codec.framerate;
+ out_codec->maxFramerate = in_codec.framerate;
// Init the codec with the default bandwidth options.
- out_codec.minBitrate = kMinVideoBitrate;
- out_codec.startBitrate = kStartVideoBitrate;
- out_codec.maxBitrate = kMaxVideoBitrate;
+ out_codec->minBitrate = kMinVideoBitrate;
+ out_codec->startBitrate = kStartVideoBitrate;
+ out_codec->maxBitrate = kMaxVideoBitrate;
return true;
}
@@ -822,7 +829,7 @@
bool WebRtcVideoEngine::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) {
if (initialized_) {
- LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init.";
+ LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init";
return false;
}
voice_engine_ = voice_engine;
@@ -831,7 +838,7 @@
bool WebRtcVideoEngine::EnableTimedRender() {
if (initialized_) {
- LOG(LS_WARNING) << "EnableTimedRender can not be called after Init.";
+ LOG(LS_WARNING) << "EnableTimedRender can not be called after Init";
return false;
}
render_module_.reset(webrtc::VideoRender::CreateVideoRender(0, NULL,
@@ -880,7 +887,7 @@
if (capturer == NULL) {
// Stop capturing before clearing the capturer.
if (SetCapture(false) != CR_SUCCESS) {
- LOG(LS_WARNING) << "Camera failed to stop.";
+ LOG(LS_WARNING) << "Camera failed to stop";
return false;
}
ClearCapturer();
@@ -980,6 +987,7 @@
sending_(false),
render_started_(false),
muted_(false),
+ local_ssrc_(0),
send_min_bitrate_(kMinVideoBitrate),
send_start_bitrate_(kStartVideoBitrate),
send_max_bitrate_(kMaxVideoBitrate),
@@ -1059,7 +1067,7 @@
// Remove all receive streams and the default channel.
while (!mux_channels_.empty()) {
- RemoveStream(mux_channels_.begin()->first);
+ RemoveRecvStream(mux_channels_.begin()->first);
}
}
@@ -1074,7 +1082,7 @@
iter != codecs.end(); ++iter) {
if (engine()->FindCodec(*iter)) {
webrtc::VideoCodec wcodec;
- if (engine()->ConvertFromCricketVideoCodec(*iter, wcodec)) {
+ if (engine()->ConvertFromCricketVideoCodec(*iter, &wcodec)) {
receive_codecs_.push_back(wcodec);
}
} else {
@@ -1099,7 +1107,7 @@
VideoCodec checked_codec;
VideoCodec current; // defaults to 0x0
if (sending_) {
- engine()->ConvertToCricketVideoCodec(*send_codec_, current);
+ engine()->ConvertToCricketVideoCodec(*send_codec_, ¤t);
}
for (std::vector<VideoCodec>::const_iterator iter = codecs.begin();
iter != codecs.end(); ++iter) {
@@ -1109,7 +1117,7 @@
fec_type = iter->id;
} else if (engine()->CanSendCodec(*iter, current, &checked_codec)) {
webrtc::VideoCodec wcodec;
- if (engine()->ConvertFromCricketVideoCodec(checked_codec, wcodec)) {
+ if (engine()->ConvertFromCricketVideoCodec(checked_codec, &wcodec)) {
send_codecs.push_back(wcodec);
}
} else {
@@ -1185,8 +1193,12 @@
}
bool WebRtcVideoMediaChannel::SetSend(bool send) {
+ if (local_ssrc_ == 0 && send) {
+ LOG(LS_ERROR) << "No stream added";
+ return false;
+ }
if (send == sending()) {
- return true; // no action required
+ return true; // No action required.
}
if (send) {
@@ -1195,20 +1207,18 @@
if (!send_codec_.get()) {
return false;
}
-
- if (engine()->vie()->base()->StartSend(vie_channel_) != 0) {
- LOG_RTCERR1(StartSend, vie_channel_);
+ // Start send now.
+ if (!StartSend()) {
return false;
}
} else {
// We've been asked to stop sending.
- if (engine()->vie()->base()->StopSend(vie_channel_) != 0) {
- LOG_RTCERR1(StopSend, vie_channel_);
+ if (!StopSend()) {
return false;
}
}
-
sending_ = send;
+
return true;
}
@@ -1217,8 +1227,58 @@
return (it != mux_channels_.end()) ? it->second->channel_id() : -1;
}
-bool WebRtcVideoMediaChannel::AddStream(uint32 ssrc, uint32 voice_ssrc) {
- if (mux_channels_.find(ssrc) != mux_channels_.end()) {
+bool WebRtcVideoMediaChannel::AddSendStream(const StreamParams& sp) {
+ // TODO: Implement send media from multiple streams.
+ if (local_ssrc_ != 0) {
+ LOG(LS_ERROR) << "WebRtcVideoMediaChannel supports one sending channel";
+ return false;
+ }
+ if (sp.ssrcs.size() != 1) {
+ LOG(LS_ERROR) << "WebRtcVideoMediaChannel supports one sending SSRC per"
+ << " stream";
+ return false;
+ }
+ if (engine()->vie()->rtp()->SetLocalSSRC(vie_channel_,
+ sp.first_ssrc()) != 0) {
+ LOG_RTCERR1(SetLocalSSRC, vie_channel_);
+ return false;
+ }
+ if (engine()->vie()->rtp()->SetRTCPCName(vie_channel_,
+ sp.cname.c_str()) != 0) {
+ LOG_RTCERR2(SetRTCPCName, vie_channel_, sp.cname.c_str());
+ return false;
+ }
+
+ local_ssrc_ = sp.first_ssrc();
+
+ if (sending_) {
+ return StartSend();
+ }
+ return true;
+}
+
+bool WebRtcVideoMediaChannel::RemoveSendStream(uint32 ssrc) {
+ // TODO: Implement send media from multiple streams.
+ if (ssrc != local_ssrc_) {
+ return false;
+ }
+ if (sending_) {
+ StopSend();
+ }
+ local_ssrc_ = 0;
+ return true;
+}
+
+bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
+ if (mux_channels_.find(sp.first_ssrc()) != mux_channels_.end()) {
+ LOG(LS_ERROR) << "Stream already exists";
+ return false;
+ }
+
+ // TODO: Implement recv media from multiple SSRCs per stream.
+ if (sp.ssrcs.size() != 1) {
+ LOG(LS_ERROR) << "WebRtcVideoMediaChannel supports one receiving SSRC per"
+ << " stream";
return false;
}
@@ -1231,19 +1291,20 @@
LOG_RTCERR1(CreateChannel, channel_id);
return false;
}
- if (!ConfigureChannel(channel_id) || !ConfigureReceiving(channel_id, ssrc)) {
+ if (!ConfigureChannel(channel_id) || !ConfigureReceiving(channel_id,
+ sp.first_ssrc())) {
engine_->vie()->base()->DeleteChannel(channel_id);
return false;
}
- LOG(LS_INFO) << "New video stream " << ssrc
+ LOG(LS_INFO) << "New video stream " << sp.first_ssrc()
<< " registered to VideoEngine channel #"
- << channel_id << ".";
+ << channel_id;
return true;
}
-bool WebRtcVideoMediaChannel::RemoveStream(uint32 ssrc) {
+bool WebRtcVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
ChannelMap::iterator it = mux_channels_.find(ssrc);
if (it == mux_channels_.end()) {
@@ -1266,7 +1327,7 @@
LOG(LS_INFO) << "Removing video stream " << ssrc
<< " with VideoEngine channel #"
- << channel_id << ".";
+ << channel_id;
if (engine()->vie()->base()->DeleteChannel(channel_id) == -1) {
LOG_RTCERR1(DeleteChannel, channel_id);
// Leak the WebRtcVideoChannelInfo owned by |it| but remove the channel from
@@ -1280,6 +1341,22 @@
return true;
}
+bool WebRtcVideoMediaChannel::StartSend() {
+ if (engine()->vie()->base()->StartSend(vie_channel_) != 0) {
+ LOG_RTCERR1(StartSend, vie_channel_);
+ return false;
+ }
+ return true;
+}
+
+bool WebRtcVideoMediaChannel::StopSend() {
+ if (engine()->vie()->base()->StopSend(vie_channel_) != 0) {
+ LOG_RTCERR1(StopSend, vie_channel_);
+ return false;
+ }
+ return true;
+}
+
bool WebRtcVideoMediaChannel::SetRenderer(uint32 ssrc,
VideoRenderer* renderer) {
if (mux_channels_.find(ssrc) == mux_channels_.end())
@@ -1317,7 +1394,7 @@
sinfo.framerate_input = local_stream_info_->framerate();
sinfo.framerate_sent = encoder_observer_->framerate();
sinfo.nominal_bitrate = encoder_observer_->bitrate();
- sinfo.preferred_bitrate = kMaxVideoBitrate;
+ sinfo.preferred_bitrate = send_max_bitrate_;
// Get received RTCP statistics for the sender, if available.
// It's not a fatal error if we can't, since RTCP may not have arrived yet.
@@ -1452,12 +1529,12 @@
uint32 ssrc = 0;
if (!GetRtcpSsrc(packet->data(), packet->length(), &ssrc)) {
- LOG(LS_WARNING) << "Failed to parse SSRC from received RTCP packet.";
+ LOG(LS_WARNING) << "Failed to parse SSRC from received RTCP packet";
return;
}
int type = 0;
if (!GetRtcpType(packet->data(), packet->length(), & type)) {
- LOG(LS_WARNING) << "Failed to parse type from received RTCP packet.";
+ LOG(LS_WARNING) << "Failed to parse type from received RTCP packet";
return;
}
@@ -1476,25 +1553,6 @@
packet->length());
}
-void WebRtcVideoMediaChannel::SetSendSsrc(uint32 id) {
- if (!sending_) {
- if (engine()->vie()->rtp()->SetLocalSSRC(vie_channel_, id) != 0) {
- LOG_RTCERR1(SetLocalSSRC, vie_channel_);
- }
- } else {
- LOG(LS_ERROR) << "Channel already in send state";
- }
-}
-
-bool WebRtcVideoMediaChannel::SetRtcpCName(const std::string& cname) {
- if (engine()->vie()->rtp()->SetRTCPCName(vie_channel_,
- cname.c_str()) != 0) {
- LOG_RTCERR2(SetRTCPCName, vie_channel_, cname.c_str());
- return false;
- }
- return true;
-}
-
bool WebRtcVideoMediaChannel::Mute(bool on) {
muted_ = on;
return true;
@@ -1504,7 +1562,7 @@
LOG(LS_INFO) << "RtcVideoMediaChanne::SetSendBandwidth";
if (!send_codec_.get()) {
- LOG(LS_INFO) << "The send codec has not been set up yet.";
+ LOG(LS_INFO) << "The send codec has not been set up yet";
return true;
}
@@ -1515,7 +1573,7 @@
// Use the default values for min bitrate.
min_bitrate = kMinVideoBitrate;
// Use the default value or the bps for the max
- max_bitrate = (bps <= 0) ? kMaxVideoBitrate : (bps / 1000);
+ max_bitrate = (bps <= 0) ? send_max_bitrate_ : (bps / 1000);
// Maximum start bitrate can be kStartVideoBitrate.
start_bitrate = talk_base::_min(kStartVideoBitrate, max_bitrate);
} else {
@@ -1547,6 +1605,20 @@
// Save the options, to be interpreted where appropriate.
channel_options_ = options;
+ // Adjust send codec bitrate if needed.
+ int expected_bitrate = (0 != (channel_options_ & OPT_CONFERENCE)) ?
+ kConferenceModeMaxVideoBitrate : kMaxVideoBitrate;
+ if (NULL != send_codec_.get() && send_max_bitrate_ != expected_bitrate) {
+ // On success, SetSendCodec() will reset send_max_bitrate_ to
+ // expected_bitrate.
+ if (!SetSendCodec(*send_codec_,
+ send_min_bitrate_,
+ send_start_bitrate_,
+ expected_bitrate)) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/talk/session/phone/webrtcvideoengine.h b/talk/session/phone/webrtcvideoengine.h
index c0e49f3..c25c4da 100644
--- a/talk/session/phone/webrtcvideoengine.h
+++ b/talk/session/phone/webrtcvideoengine.h
@@ -129,9 +129,9 @@
void RegisterChannel(WebRtcVideoMediaChannel* channel);
void UnregisterChannel(WebRtcVideoMediaChannel* channel);
void ConvertToCricketVideoCodec(const webrtc::VideoCodec& in_codec,
- VideoCodec& out_codec);
+ VideoCodec* out_codec);
bool ConvertFromCricketVideoCodec(const VideoCodec& in_codec,
- webrtc::VideoCodec& out_codec);
+ webrtc::VideoCodec* out_codec);
// Check whether the supplied trace should be ignored.
bool ShouldIgnoreTrace(const std::string& trace);
int GetNumOfChannels();
@@ -212,8 +212,11 @@
virtual bool SetSendCodecs(const std::vector<VideoCodec> &codecs);
virtual bool SetRender(bool render);
virtual bool SetSend(bool send);
- virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc);
- virtual bool RemoveStream(uint32 ssrc);
+
+ virtual bool AddSendStream(const StreamParams& sp);
+ virtual bool RemoveSendStream(uint32 ssrc);
+ virtual bool AddRecvStream(const StreamParams& sp);
+ virtual bool RemoveRecvStream(uint32 ssrc);
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer);
virtual bool GetStats(VideoMediaInfo* info);
virtual bool AddScreencast(uint32 ssrc, const ScreencastId& id) {
@@ -227,8 +230,6 @@
virtual void OnPacketReceived(talk_base::Buffer* packet);
virtual void OnRtcpReceived(talk_base::Buffer* packet);
- virtual void SetSendSsrc(uint32 id);
- virtual bool SetRtcpCName(const std::string& cname);
virtual bool Mute(bool on);
virtual bool SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
@@ -279,6 +280,12 @@
// |reset| is set to whether resetting has happened on vie or not.
// Returns false on error.
bool MaybeResetVieSendCodec(int new_width, int new_height, bool* reset);
+ // Call Webrtc function to start sending media on |vie_channel_|.
+ // Does not affect |sending_|.
+ bool StartSend();
+ // Call Webrtc function to stop sending media on |vie_channel_|.
+ // Does not affect |sending_|.
+ bool StopSend();
WebRtcVideoEngine* engine_;
VoiceMediaChannel* voice_channel_;
@@ -288,6 +295,8 @@
bool sending_;
bool render_started_;
bool muted_; // Flag to tell if we need to mute video.
+ // Our local SSRC. Currently only one send stream is supported.
+ uint32 local_ssrc_;
int send_min_bitrate_;
int send_start_bitrate_;
int send_max_bitrate_;
diff --git a/talk/session/phone/webrtcvideoengine_unittest.cc b/talk/session/phone/webrtcvideoengine_unittest.cc
index 1db450e..88d1505 100644
--- a/talk/session/phone/webrtcvideoengine_unittest.cc
+++ b/talk/session/phone/webrtcvideoengine_unittest.cc
@@ -51,6 +51,7 @@
static const unsigned int kMinBandwidthKbps = 100;
static const unsigned int kStartBandwidthKbps = 300;
static const unsigned int kMaxBandwidthKbps = 2000;
+static const unsigned int kConferenceModeMaxBandwidthKbps = 500;
class FakeViEWrapper : public cricket::ViEWrapper {
public:
@@ -275,6 +276,8 @@
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
+ EXPECT_TRUE(channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSend(true));
// Capture a smaller frame and verify vie send codec has been reset to
@@ -303,7 +306,7 @@
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
webrtc::VideoCodec wcodec;
- EXPECT_TRUE(engine_.ConvertFromCricketVideoCodec(kVP8Codec, wcodec));
+ EXPECT_TRUE(engine_.ConvertFromCricketVideoCodec(kVP8Codec, &wcodec));
EXPECT_TRUE(vie_.ReceiveCodecRegistered(channel_num, wcodec));
}
@@ -385,6 +388,8 @@
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(123)));
// Verify we can start/stop/start/stop sending.
EXPECT_TRUE(channel_->SetSend(true));
@@ -445,32 +450,60 @@
}
// Test SetSendSsrc.
-TEST_F(WebRtcVideoEngineTestFake, SetSendSsrc) {
+TEST_F(WebRtcVideoEngineTestFake, SetSendSsrcAndCname) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
- // Verify ssrc is set correctly.
- channel_->SetSendSsrc(1234);
+ cricket::StreamParams stream;
+ stream.ssrcs.push_back(1234);
+ stream.cname = "cname";
+ channel_->AddSendStream(stream);
+
unsigned int ssrc = 0;
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1234U, ssrc);
-}
-// Test SetRtcpCName.
-TEST_F(WebRtcVideoEngineTestFake, SetRtcpCName) {
- EXPECT_TRUE(SetupEngine());
- int channel_num = vie_.GetLastChannel();
-
- // Verify rtcp cname is set correctly.
- EXPECT_TRUE(channel_->SetRtcpCName("cname"));
char rtcp_cname[256];
EXPECT_EQ(0, vie_.GetRTCPCName(channel_num, rtcp_cname));
EXPECT_STREQ("cname", rtcp_cname);
}
-// Test SetOptions.
-// TODO: Test whatever need to be turned on for multiway WebRTC call.
-TEST_F(WebRtcVideoEngineTestFake, SetOptions) {
+// Test SetOptions with OPT_CONFERENCE flag.
+TEST_F(WebRtcVideoEngineTestFake, SetOptionsWithConferenceMode) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
+
+ // Verify default send codec and bitrate.
+ webrtc::VideoCodec gcodec;
+ EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
+ EXPECT_EQ(kVP8Codec.id, gcodec.plType);
+ EXPECT_STREQ(kVP8Codec.name.c_str(), gcodec.plName);
+ EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
+ EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
+ EXPECT_EQ(kMaxBandwidthKbps, gcodec.maxBitrate);
+
+ // Set options with OPT_CONFERENCE flag.
+ EXPECT_TRUE(channel_->SetOptions(cricket::OPT_CONFERENCE));
+
+ // Verify channel now has new max bitrate.
+ EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
+ EXPECT_EQ(kVP8Codec.id, gcodec.plType);
+ EXPECT_STREQ(kVP8Codec.name.c_str(), gcodec.plName);
+ EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
+ EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
+ EXPECT_EQ(kConferenceModeMaxBandwidthKbps, gcodec.maxBitrate);
+
+ // Set options back to zero.
+ EXPECT_TRUE(channel_->SetOptions(0));
+
+ // Verify channel now has default max bitrate again.
+ EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
+ EXPECT_EQ(kVP8Codec.id, gcodec.plType);
+ EXPECT_STREQ(kVP8Codec.name.c_str(), gcodec.plName);
+ EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
+ EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
+ EXPECT_EQ(kMaxBandwidthKbps, gcodec.maxBitrate);
}
/////////////////////////
@@ -569,9 +602,8 @@
// Technically we should call vcm->AddRef since we are using the vcm below,
// however the FakeWebRtcVideoCaptureModule didn't implemented the refcount.
// So for testing, this should be fine.
+ // The SetCaptureModule call always starts the capture.
EXPECT_TRUE(engine_.SetCaptureModule(vcm));
- EXPECT_FALSE(engine_.IsCapturing());
- EXPECT_EQ(cricket::CR_PENDING, engine_.SetCapture(true));
EXPECT_TRUE(engine_.IsCapturing());
EXPECT_EQ(engine_.default_codec_format().width, vcm->cap().width);
EXPECT_EQ(engine_.default_codec_format().height, vcm->cap().height);
@@ -685,6 +717,10 @@
Base::AddRemoveRecvStreams();
}
+TEST_F(WebRtcVideoMediaChannelTest, AddRemoveSendStreams) {
+ Base::AddRemoveSendStreams();
+}
+
TEST_F(WebRtcVideoMediaChannelTest, SimulateConference) {
Base::SimulateConference();
}
diff --git a/talk/session/phone/webrtcvideoframe_unittest.cc b/talk/session/phone/webrtcvideoframe_unittest.cc
index 5793ab8..b115625 100644
--- a/talk/session/phone/webrtcvideoframe_unittest.cc
+++ b/talk/session/phone/webrtcvideoframe_unittest.cc
@@ -67,6 +67,11 @@
TEST_WEBRTCVIDEOFRAME(ConvertToABGRBuffer)
#endif
TEST_WEBRTCVIDEOFRAME(ConvertToARGBBuffer)
+//TEST_LMIVIDEOFRAME(ConvertToRGB24Buffer)
+//TEST_LMIVIDEOFRAME(ConvertToRAWBuffer)
+//TEST_LMIVIDEOFRAME(ConvertToRGB565Buffer)
+//TEST_LMIVIDEOFRAME(ConvertToARGB1555Buffer)
+//TEST_LMIVIDEOFRAME(ConvertToARGB4444Buffer)
//TEST_WEBRTCVIDEOFRAME(ConvertToYUY2Buffer)
//TEST_WEBRTCVIDEOFRAME(ConvertToI422Buffer)
TEST_WEBRTCVIDEOFRAME(ConvertARGBToBayerGRBG)
diff --git a/talk/session/phone/webrtcvoiceengine.cc b/talk/session/phone/webrtcvoiceengine.cc
index 561c13c..da9829a 100644
--- a/talk/session/phone/webrtcvoiceengine.cc
+++ b/talk/session/phone/webrtcvoiceengine.cc
@@ -45,6 +45,7 @@
#include "talk/base/logging.h"
#include "talk/base/stringencode.h"
#include "talk/base/stringutils.h"
+#include "talk/session/phone/streamparams.h"
#include "talk/session/phone/voiceprocessor.h"
#include "talk/session/phone/webrtcvoe.h"
@@ -494,7 +495,7 @@
}
// No typing detection support on iOS or Android.
-#endif // !IOS && !ANDROID
+#endif // !IOS && !ANDROID
return true;
}
@@ -1191,7 +1192,8 @@
desired_playout_(false),
playout_(false),
desired_send_(SEND_NOTHING),
- send_(SEND_NOTHING) {
+ send_(SEND_NOTHING),
+ local_ssrc_(0) {
engine->RegisterChannel(this);
LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel "
<< voe_channel();
@@ -1205,9 +1207,6 @@
// Enable RTCP (for quality stats and feedback messages)
EnableRtcp(voe_channel());
- // Create a random but nonzero send SSRC
- SetSendSsrc(talk_base::CreateRandomNonZeroId());
-
// Reset all recv codecs; they will be enabled via SetRecvCodecs.
ResetRecvCodecs(voe_channel());
}
@@ -1226,7 +1225,7 @@
engine()->UnregisterChannel(this);
// Remove any remaining streams.
while (!mux_channels_.empty()) {
- RemoveStream(mux_channels_.begin()->first);
+ RemoveRecvStream(mux_channels_.begin()->first);
}
// Delete the primary channel.
@@ -1462,7 +1461,9 @@
bool WebRtcVoiceMediaChannel::SetSend(SendFlags send) {
desired_send_ = send;
- return ChangeSend(desired_send_);
+ if (local_ssrc_ != 0)
+ return ChangeSend(desired_send_);
+ return true;
}
bool WebRtcVoiceMediaChannel::PauseSend() {
@@ -1573,9 +1574,46 @@
return true;
}
-bool WebRtcVoiceMediaChannel::AddStream(uint32 ssrc) {
+bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
+ if (local_ssrc_ != 0) {
+ LOG(LS_ERROR) << "WebRtcVoiceMediaChannel supports one sending channel.";
+ return false;
+ }
+
+ if (engine()->voe()->rtp()->SetLocalSSRC(voe_channel(), sp.first_ssrc())
+ == -1) {
+ LOG_RTCERR2(SetSendSSRC, voe_channel(), sp.first_ssrc());
+ return false;
+ }
+
+ if (engine()->voe()->rtp()->SetRTCP_CNAME(voe_channel(),
+ sp.cname.c_str()) == -1) {
+ LOG_RTCERR2(SetRTCP_CNAME, voe_channel(), sp.cname);
+ return false;
+ }
+
+ local_ssrc_ = sp.first_ssrc();
+ if (desired_send_ != send_)
+ return ChangeSend(desired_send_);
+ return true;
+}
+
+bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
+ if (ssrc != local_ssrc_) {
+ return false;
+ }
+ local_ssrc_ = 0;
+ ChangeSend(SEND_NOTHING);
+ return true;
+}
+
+bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
talk_base::CritScope lock(&mux_channels_cs_);
+ if (!VERIFY(sp.ssrcs.size() == 1))
+ return false;
+ uint32 ssrc = sp.first_ssrc();
+
if (mux_channels_.find(ssrc) != mux_channels_.end()) {
return false;
}
@@ -1644,7 +1682,7 @@
return SetPlayout(channel, playout_);
}
-bool WebRtcVoiceMediaChannel::RemoveStream(uint32 ssrc) {
+bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
talk_base::CritScope lock(&mux_channels_cs_);
ChannelMap::iterator it = mux_channels_.find(ssrc);
@@ -1888,22 +1926,6 @@
packet->length());
}
-void WebRtcVoiceMediaChannel::SetSendSsrc(uint32 ssrc) {
- if (engine()->voe()->rtp()->SetLocalSSRC(voe_channel(), ssrc)
- == -1) {
- LOG_RTCERR2(SetSendSSRC, voe_channel(), ssrc);
- }
-}
-
-bool WebRtcVoiceMediaChannel::SetRtcpCName(const std::string& cname) {
- if (engine()->voe()->rtp()->SetRTCP_CNAME(voe_channel(),
- cname.c_str()) == -1) {
- LOG_RTCERR2(SetRTCP_CNAME, voe_channel(), cname);
- return false;
- }
- return true;
-}
-
bool WebRtcVoiceMediaChannel::Mute(bool muted) {
if (engine()->voe()->volume()->SetInputMute(voe_channel(),
muted) == -1) {
@@ -1978,7 +2000,6 @@
sinfo.echo_delay_std_ms = -1;
if (engine()->voe()->processing()->GetEcMetricsStatus(echo_metrics_on) !=
-1 && echo_metrics_on) {
-
// TODO: we may want to use VoECallReport::GetEchoMetricsSummary
// here, but it appears to be unsuitable currently. Revisit after this is
// investigated: http://b/issue?id=5666755
diff --git a/talk/session/phone/webrtcvoiceengine.h b/talk/session/phone/webrtcvoiceengine.h
index ef677d8..dfb9023 100644
--- a/talk/session/phone/webrtcvoiceengine.h
+++ b/talk/session/phone/webrtcvoiceengine.h
@@ -296,8 +296,10 @@
virtual bool SetSend(SendFlags send);
bool PauseSend();
bool ResumeSend();
- virtual bool AddStream(uint32 ssrc);
- virtual bool RemoveStream(uint32 ssrc);
+ virtual bool AddSendStream(const StreamParams& sp);
+ virtual bool RemoveSendStream(uint32 ssrc);
+ virtual bool AddRecvStream(const StreamParams& sp);
+ virtual bool RemoveRecvStream(uint32 ssrc);
virtual bool GetActiveStreams(AudioInfo::StreamList* actives);
virtual int GetOutputLevel();
virtual bool SetOutputScaling(uint32 ssrc, double left, double right);
@@ -309,8 +311,6 @@
virtual void OnPacketReceived(talk_base::Buffer* packet);
virtual void OnRtcpReceived(talk_base::Buffer* packet);
- virtual void SetSendSsrc(uint32 id);
- virtual bool SetRtcpCName(const std::string& cname);
virtual bool Mute(bool mute);
virtual bool SetSendBandwidth(bool autobw, int bps) { return false; }
virtual bool GetStats(VoiceMediaInfo* info);
@@ -355,12 +355,14 @@
bool playout_;
SendFlags desired_send_;
SendFlags send_;
+ uint32 local_ssrc_;
ChannelMap mux_channels_; // for multiple sources
// mux_channels_ can be read from WebRtc callback thread. Accesses off the
// WebRtc thread must be synchronized with edits on the worker thread. Reads
// on the worker thread are ok.
mutable talk_base::CriticalSection mux_channels_cs_;
};
-}
+
+} // namespace cricket
#endif // TALK_SESSION_PHONE_WEBRTCVOICEENGINE_H_
diff --git a/talk/session/phone/webrtcvoiceengine_unittest.cc b/talk/session/phone/webrtcvoiceengine_unittest.cc
index 6bcc04e..82838d1 100644
--- a/talk/session/phone/webrtcvoiceengine_unittest.cc
+++ b/talk/session/phone/webrtcvoiceengine_unittest.cc
@@ -26,6 +26,7 @@
&kTelephoneEventCodec,
};
const char kRingbackTone[] = "RIFF____WAVE____ABCD1234";
+static uint32 kSsrc1 = 0x99;
class FakeVoEWrapper : public cricket::VoEWrapper {
public:
@@ -103,6 +104,10 @@
channel_ = engine_.CreateChannel();
result = (channel_ != NULL);
}
+ if (result) {
+ result = channel_->AddSendStream(
+ cricket::StreamParams::CreateLegacy(kSsrc1));
+ }
return result;
}
void DeliverPacket(const void* data, int len) {
@@ -255,7 +260,8 @@
codecs[0].id = 106; // collide with existing telephone-event
codecs[2].id = 126;
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
- EXPECT_TRUE(channel_->AddStream(2));
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc1)));
int channel_num2 = voe_.GetLastChannel();
webrtc::CodecInst gcodec;
talk_base::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "ISAC");
@@ -622,7 +628,7 @@
EXPECT_TRUE(voe_.GetPlayout(channel_num1));
// Adding another stream should disable playout on the default channel.
- EXPECT_TRUE(channel_->AddStream(2));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
int channel_num2 = voe_.GetLastChannel();
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kPcmuCodec);
@@ -636,7 +642,7 @@
EXPECT_TRUE(voe_.GetPlayout(channel_num2));
// Adding yet another stream should have stream 2 and 3 enabled for playout.
- EXPECT_TRUE(channel_->AddStream(3));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(3)));
int channel_num3 = voe_.GetLastChannel();
EXPECT_FALSE(voe_.GetPlayout(channel_num1));
EXPECT_TRUE(voe_.GetPlayout(channel_num2));
@@ -663,8 +669,8 @@
// Now remove the new streams and verify that the default channel is
// played out again.
- EXPECT_TRUE(channel_->RemoveStream(3));
- EXPECT_TRUE(channel_->RemoveStream(2));
+ EXPECT_TRUE(channel_->RemoveRecvStream(3));
+ EXPECT_TRUE(channel_->RemoveRecvStream(2));
EXPECT_TRUE(voe_.GetPlayout(channel_num1));
}
@@ -832,29 +838,30 @@
}
// Test that we can set the outgoing SSRC properly.
+// SSRC is set in SetupEngine by calling AddSendStream.
TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
unsigned int send_ssrc;
EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num, send_ssrc));
EXPECT_NE(0U, send_ssrc);
- channel_->SetSendSsrc(0x99);
EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num, send_ssrc));
- EXPECT_EQ(0x99U, send_ssrc);
+ EXPECT_EQ(kSsrc1, send_ssrc);
}
// Test that we can set the outgoing SSRC properly with multiple streams.
+// SSRC is set in SetupEngine by calling AddSendStream.
TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) {
EXPECT_TRUE(SetupEngine());
int channel_num1 = voe_.GetLastChannel();
unsigned int send_ssrc;
- channel_->SetSendSsrc(0x99);
EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num1, send_ssrc));
- EXPECT_EQ(0x99U, send_ssrc);
- EXPECT_TRUE(channel_->AddStream(2));
+ EXPECT_EQ(kSsrc1, send_ssrc);
+
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
int channel_num2 = voe_.GetLastChannel();
EXPECT_EQ(0, voe_.GetLocalSSRC(channel_num2, send_ssrc));
- EXPECT_EQ(0x99U, send_ssrc);
+ EXPECT_EQ(kSsrc1, send_ssrc);
}
// Test that we can properly receive packets.
@@ -869,11 +876,11 @@
// Test that we can properly receive packets on multiple streams.
TEST_F(WebRtcVoiceEngineTestFake, RecvWithMultipleStreams) {
EXPECT_TRUE(SetupEngine());
- EXPECT_TRUE(channel_->AddStream(1));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
int channel_num1 = voe_.GetLastChannel();
- EXPECT_TRUE(channel_->AddStream(2));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
int channel_num2 = voe_.GetLastChannel();
- EXPECT_TRUE(channel_->AddStream(3));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(3)));
int channel_num3 = voe_.GetLastChannel();
// Create packets with the right SSRCs.
char packets[4][sizeof(kPcmuFrame)];
@@ -903,24 +910,24 @@
EXPECT_TRUE(voe_.CheckNoPacket(channel_num2));
EXPECT_TRUE(voe_.CheckPacket(channel_num3, packets[3],
sizeof(packets[3])));
- EXPECT_TRUE(channel_->RemoveStream(3));
- EXPECT_TRUE(channel_->RemoveStream(2));
- EXPECT_TRUE(channel_->RemoveStream(1));
+ EXPECT_TRUE(channel_->RemoveRecvStream(3));
+ EXPECT_TRUE(channel_->RemoveRecvStream(2));
+ EXPECT_TRUE(channel_->RemoveRecvStream(1));
}
// Test that we properly handle failures to add a stream.
TEST_F(WebRtcVoiceEngineTestFake, AddStreamFail) {
EXPECT_TRUE(SetupEngine());
voe_.set_fail_create_channel(true);
- EXPECT_FALSE(channel_->AddStream(2));
+ EXPECT_FALSE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
}
// Test that we properly clean up any streams that were added, even if
// not explicitly removed.
TEST_F(WebRtcVoiceEngineTestFake, StreamCleanup) {
EXPECT_TRUE(SetupEngine());
- EXPECT_TRUE(channel_->AddStream(1));
- EXPECT_TRUE(channel_->AddStream(2));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
EXPECT_EQ(3, voe_.GetNumChannels()); // default channel + 2 added
delete channel_;
channel_ = NULL;
@@ -966,8 +973,8 @@
// Test that we can play a ringback tone properly in a multi-stream call.
TEST_F(WebRtcVoiceEngineTestFake, PlayRingbackWithMultipleStreams) {
EXPECT_TRUE(SetupEngine());
- EXPECT_TRUE(channel_->AddStream(1));
- EXPECT_TRUE(channel_->AddStream(2));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
int channel_num = voe_.GetLastChannel();
EXPECT_EQ(0, voe_.IsPlayingFileLocally(channel_num));
// Check we fail if no ringback tone specified.
@@ -1045,7 +1052,8 @@
// Add another stream and test on that.
++ssrc;
- EXPECT_TRUE(channel_->AddStream(ssrc));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(
+ ssrc)));
listener->Reset();
voe_.TriggerCallbackOnError(voe_.GetLastChannel(),
VE_SATURATION_WARNING);
@@ -1066,8 +1074,8 @@
codecs.push_back(kPcmuCodec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
- EXPECT_TRUE(channel_->AddStream(2));
- EXPECT_TRUE(channel_->AddStream(3));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
+ EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(3)));
EXPECT_TRUE(channel_->SetPlayout(true));
voe_.set_playout_fail_channel(voe_.GetLastChannel() - 1);
EXPECT_TRUE(channel_->SetPlayout(false));
@@ -1079,7 +1087,7 @@
TEST_F(WebRtcVoiceEngineTestFake, RegisterVoiceProcessor) {
EXPECT_TRUE(SetupEngine());
uint32 ssrc = 0;
- voe_.GetLocalSSRC(0,ssrc);
+ voe_.GetLocalSSRC(0, ssrc);
cricket::FakeMediaProcessor vp_1;
cricket::FakeMediaProcessor vp_2;
@@ -1126,7 +1134,7 @@
EXPECT_FALSE(engine_.RegisterProcessor(0,
&vp_1,
cricket::MPD_RX));
- channel_->AddStream(1);
+ channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1));
EXPECT_TRUE(engine_.RegisterProcessor(1,
&vp_1,
cricket::MPD_RX));
@@ -1136,7 +1144,7 @@
EXPECT_FALSE(engine_.RegisterProcessor(1,
&vp_1,
cricket::MPD_TX));
- channel_->RemoveStream(1);
+ channel_->RemoveRecvStream(1);
}
// Tests for the actual WebRtc VoE library.
diff --git a/talk/sound/pulseaudiosoundsystem.cc b/talk/sound/pulseaudiosoundsystem.cc
index 14aa119..4ccedc1 100644
--- a/talk/sound/pulseaudiosoundsystem.cc
+++ b/talk/sound/pulseaudiosoundsystem.cc
@@ -49,13 +49,6 @@
// First PulseAudio protocol version that supports PA_STREAM_ADJUST_LATENCY.
static const uint32_t kAdjustLatencyProtocolVersion = 13;
-// We define this flag if it's missing from our headers, because we want to be
-// able to compile against old headers but still use PA_STREAM_ADJUST_LATENCY
-// if run against a recent version of the library.
-#ifndef PA_STREAM_ADJUST_LATENCY
-#define PA_STREAM_ADJUST_LATENCY 0x2000U
-#endif
-
// Lookup table from the cricket format enum in soundsysteminterface.h to
// Pulse's enums.
static const pa_sample_format_t kCricketFormatToPulseFormatTable[] = {