Update to libjingle 0.6.11
git-svn-id: http://libjingle.googlecode.com/svn/trunk@112 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index 91e65d7..1906641 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -332,13 +332,8 @@
// This test sets up a call between two parties. Both parties send static frames
// to each other. Once the test is finished the number of sent frames is
-// compared to the number of recieved frames.
-// TODO - This unittest is failing when SRTP is enabled in
-// PeerConnection. This is due to race between the media and signaling.
-// When media arrives before signal, VoiceEngine asserts when it fails
-// to decode encrypted RTP packets. Once VoiceEngine is fixed, enable
-// this test case.
-TEST_F(P2PTestConductor, DISABLED_LocalP2PTest) {
+// compared to the number of received frames.
+TEST_F(P2PTestConductor, LocalP2PTest) {
EXPECT_TRUE(StartSession());
const int kMaxWaitForActivationMs = 5000;
EXPECT_TRUE_WAIT(ActivationNotPending(), kMaxWaitForActivationMs);
diff --git a/talk/app/webrtc/peerconnectionimpl_unittest.cc b/talk/app/webrtc/peerconnectionimpl_unittest.cc
index e690b2c..007aedb 100644
--- a/talk/app/webrtc/peerconnectionimpl_unittest.cc
+++ b/talk/app/webrtc/peerconnectionimpl_unittest.cc
@@ -195,7 +195,7 @@
EXPECT_EQ(kStreamLabel1, pc_->remote_streams()->at(0)->label());
}
-TEST_F(PeerConnectionImplTest, DISABLED_UpdateStream) {
+TEST_F(PeerConnectionImplTest, UpdateStream) {
AddStream(kStreamLabel1);
WAIT(PeerConnectionInterface::kNegotiating == observer_.state_, kTimeout);
pc_->ProcessSignalingMessage(CreateAnswerMessage(observer_.last_message_));
diff --git a/talk/app/webrtc/peerconnectionsignaling.cc b/talk/app/webrtc/peerconnectionsignaling.cc
index 9accf05..a3bfb63 100644
--- a/talk/app/webrtc/peerconnectionsignaling.cc
+++ b/talk/app/webrtc/peerconnectionsignaling.cc
@@ -76,13 +76,19 @@
}
// Fills a MediaSessionOptions struct with the MediaTracks we want to sent given
-// the local MediaStreams.
+// the local MediaStreams. |local_streams| can be null if there are no tracks to
+// send.
static void InitMediaSessionOptions(
cricket::MediaSessionOptions* options,
StreamCollectionInterface* local_streams) {
+ if (!VERIFY(options != NULL))
+ return;
// In order to be able to receive video,
// the has_video should always be true even if there are no video tracks.
options->has_video = true;
+ if (local_streams == NULL)
+ return;
+
for (size_t i = 0; i < local_streams->count(); ++i) {
MediaStreamInterface* stream = local_streams->at(i);
@@ -163,13 +169,6 @@
queued_local_streams_.clear();
queued_local_streams_.push_back(local_streams);
- // If we are still Initializing we need to wait before we can handle
- // the offer. Queue it and handle it when the state changes.
- if (state_ == kInitializing) {
- received_pre_offer_ = true;
- break;
- }
-
if (state_ == kWaitingForAnswer) {
// Message received out of order or Glare occurred and the decision was
// to use the incoming offer.
@@ -177,7 +176,26 @@
// Be nice and handle this offer instead of the pending offer.
signaling_thread_->Clear(this, MSG_SEND_QUEUED_OFFER);
}
- // Post a task to handle the answer.
+
+ // Provide the remote session description and the remote candidates from
+ // the parsed ROAP message to the |provider_|.
+ // The session description ownership is transferred from |roap_session_|
+ // to |provider_|.
+ provider_->SetRemoteDescription(roap_session_.ReleaseRemoteDescription(),
+ cricket::CA_OFFER);
+ provider_->SetRemoteCandidates(roap_session_.RemoteCandidates());
+ // Update the known remote MediaStreams.
+ UpdateRemoteStreams(provider_->remote_description());
+
+ // If we are still Initializing we need to wait until we have our local
+ // candidates before we can handle the offer. Queue it and handle it when
+ // the state changes.
+ if (state_ == kInitializing) {
+ received_pre_offer_ = true;
+ break;
+ }
+
+ // Post a task to generate the answer.
signaling_thread_->Post(this, MSG_GENERATE_ANSWER);
ChangeState(kWaitingForOK);
break;
@@ -193,27 +211,29 @@
return;
}
- // Hand over the remote session description and the remote candidates from
- // the parsed ROAP message to the provider_.
- // The session description ownership is transferred from roap_session_ to
- // the provider_;
- const cricket::SessionDescription* remote_desc =
- provider_->SetRemoteSessionDescription(
- roap_session_.ReleaseRemoteDescription(),
- roap_session_.RemoteCandidates());
- // Let the provider now that the negotiation is done and both local and
- // remote session description is now valid.
- provider_->NegotiationDone();
+ talk_base::scoped_ptr<cricket::SessionDescription> remote_desc(
+ roap_session_.ReleaseRemoteDescription());
- // Update the list of known remote MediaStreams.
- UpdateRemoteStreams(remote_desc);
// Pop the first item of queued StreamCollections containing local
// MediaStreams that just have been negotiated.
scoped_refptr<StreamCollectionInterface> streams(
queued_local_streams_.front());
queued_local_streams_.pop_front();
// Update the state of the local MediaStreams.
- UpdateSendingLocalStreams(remote_desc, streams);
+ UpdateSendingLocalStreams(remote_desc.get(), streams);
+
+ // Hand the ownership of the local session description to |provider_|.
+ provider_->SetLocalDescription(local_desc_.release(), cricket::CA_OFFER);
+
+ // Provide the remote session description and the remote candidates from
+ // the parsed ROAP message to the |provider_|.
+ // The session description ownership is transferred from |roap_session_|
+ // to |provider_|.
+ provider_->SetRemoteDescription(remote_desc.release(),
+ cricket::CA_ANSWER);
+ provider_->SetRemoteCandidates(roap_session_.RemoteCandidates());
+ // Update the list of known remote MediaStreams.
+ UpdateRemoteStreams(provider_->remote_description());
// Let the remote peer know we have received the answer.
SignalNewPeerConnectionMessage(roap_session_.CreateOk());
@@ -228,14 +248,15 @@
}
case RoapSession::kOk: {
if (state_ == kWaitingForOK) {
- // Let the provider know the negotiation is done.
- provider_->NegotiationDone();
-
scoped_refptr<StreamCollectionInterface> streams(
queued_local_streams_.front());
queued_local_streams_.pop_front();
// Update the state of the local streams.
- UpdateSendingLocalStreams(local_desc_, streams);
+ UpdateSendingLocalStreams(local_desc_.get(), streams);
+
+ // Hand over the ownership of the local description to the provider.
+ provider_->SetLocalDescription(local_desc_.release(),
+ cricket::CA_ANSWER);
ChangeState(kIdle);
// Check if we have an updated offer waiting in the queue.
if (!queued_local_streams_.empty())
@@ -328,10 +349,8 @@
cricket::MediaSessionOptions options;
InitMediaSessionOptions(&options, local_streams);
- const cricket::SessionDescription* local_desc =
- provider_->ProvideOffer(options);
-
- SignalNewPeerConnectionMessage(roap_session_.CreateOffer(local_desc,
+ local_desc_.reset(provider_->CreateOffer(options));
+ SignalNewPeerConnectionMessage(roap_session_.CreateOffer(local_desc_.get(),
candidates_));
}
@@ -339,19 +358,22 @@
ChangeState(kShutingDown);
signaling_thread_->Clear(this); // Don't send queued offers or answers.
queued_local_streams_.clear();
- provider_->SetRemoteSessionDescription(NULL, cricket::Candidates());
- provider_->NegotiationDone();
+ cricket::MediaSessionOptions options;
+ InitMediaSessionOptions(&options, NULL);
+
+ // Create new empty session descriptions without StreamParams.
+ // By applying these descriptions we don't send or receive any streams.
+ const SessionDescription* local_desc = provider_->CreateOffer(options);
+ SessionDescription* remote_desc = provider_->CreateAnswer(local_desc,
+ options);
+
+ provider_->SetRemoteDescription(remote_desc, cricket::CA_OFFER);
+ provider_->SetLocalDescription(local_desc, cricket::CA_ANSWER);
+
UpdateRemoteStreams(NULL);
}
void PeerConnectionSignaling::CreateAnswer_s() {
- // Let the provider know about the remote offer.
- // The provider takes ownership and return a pointer for us to use.
- const cricket::SessionDescription* remote_desc =
- provider_->SetRemoteSessionDescription(
- roap_session_.ReleaseRemoteDescription(),
- roap_session_.RemoteCandidates());
-
scoped_refptr<StreamCollectionInterface> streams(
queued_local_streams_.back());
// Clean up all queued collections of local streams except the last one.
@@ -364,16 +386,14 @@
cricket::MediaSessionOptions options;
InitMediaSessionOptions(&options, streams);
// Create an local session description based on this.
- local_desc_ = provider_->ProvideAnswer(options);
-
- if (!VerifyAnswer(local_desc_)) {
+ local_desc_.reset(provider_->CreateAnswer(provider_->remote_description(),
+ options));
+ if (!VerifyAnswer(local_desc_.get())) {
SignalNewPeerConnectionMessage(roap_session_.CreateErrorMessage(kRefused));
return;
}
- UpdateRemoteStreams(remote_desc);
- ChangeState(kWaitingForOK);
- SignalNewPeerConnectionMessage(roap_session_.CreateAnswer(local_desc_,
+ SignalNewPeerConnectionMessage(roap_session_.CreateAnswer(local_desc_.get(),
candidates_));
}
diff --git a/talk/app/webrtc/peerconnectionsignaling.h b/talk/app/webrtc/peerconnectionsignaling.h
index 14188a9..9e195ee 100644
--- a/talk/app/webrtc/peerconnectionsignaling.h
+++ b/talk/app/webrtc/peerconnectionsignaling.h
@@ -239,9 +239,9 @@
// Currently known remote MediaStreams.
talk_base::scoped_refptr<StreamCollection> remote_streams_;
- // Weak reference to the local session description of the local MediaStreams
- // being negotiated.
- const cricket::SessionDescription* local_desc_;
+ // The local session description of the local MediaStreams that is being
+ // negotiated.
+ talk_base::scoped_ptr<const cricket::SessionDescription> local_desc_;
// Local MediaStreams being negotiated.
talk_base::scoped_refptr<StreamCollection> local_streams_;
diff --git a/talk/app/webrtc/peerconnectionsignaling_unittest.cc b/talk/app/webrtc/peerconnectionsignaling_unittest.cc
index 7b4d3a0..8980128 100644
--- a/talk/app/webrtc/peerconnectionsignaling_unittest.cc
+++ b/talk/app/webrtc/peerconnectionsignaling_unittest.cc
@@ -136,40 +136,64 @@
cricket::ChannelManager* channel_manager)
: update_session_description_counter_(0),
session_description_factory_(
- new cricket::MediaSessionDescriptionFactory(channel_manager)) {
+ new cricket::MediaSessionDescriptionFactory(channel_manager)),
+ offer_set_(false) {
}
- virtual const cricket::SessionDescription* ProvideOffer(
+ virtual cricket::SessionDescription* CreateOffer(
const cricket::MediaSessionOptions& options) {
- local_desc_.reset(session_description_factory_->CreateOffer(
- options, local_desc_.get()));
+ return session_description_factory_->CreateOffer(options,
+ local_desc_.get());
+ }
+ virtual cricket::SessionDescription* CreateAnswer(
+ const cricket::SessionDescription*offer,
+ const cricket::MediaSessionOptions& options) {
+ return session_description_factory_->CreateAnswer(offer, options,
+ local_desc_.get());
+ }
+ virtual void SetLocalDescription(const cricket::SessionDescription* desc,
+ cricket::ContentAction type) {
+ local_desc_.reset(desc);
+ UpdateNegotiationState(type);
+ }
+ virtual void SetRemoteDescription(
+ cricket::SessionDescription* remote_offer,
+ cricket::ContentAction type) {
+ remote_desc_.reset(remote_offer);
+ UpdateNegotiationState(type);
+ }
+ virtual const cricket::SessionDescription* local_description() const {
return local_desc_.get();
}
-
- virtual const cricket::SessionDescription* SetRemoteSessionDescription(
- const cricket::SessionDescription* remote_offer,
- const cricket::Candidates& remote_candidates) {
- remote_desc_.reset(remote_offer);
+ virtual const cricket::SessionDescription* remote_description() const {
return remote_desc_.get();
}
-
- virtual const cricket::SessionDescription* ProvideAnswer(
- const cricket::MediaSessionOptions& options) {
- local_desc_.reset(session_description_factory_->CreateAnswer(
- remote_desc_.get(), options, local_desc_.get()));
- return local_desc_.get();
+ virtual void SetRemoteCandidates(
+ const std::vector<cricket::Candidate>& remote_candidates) {
}
- virtual void NegotiationDone() {
- ++update_session_description_counter_;
- }
-
+ // |update_session_description_counter_| is the number of successful
+ // negotiations / re-negotiations.
size_t update_session_description_counter_;
protected:
+ void UpdateNegotiationState(cricket::ContentAction type) {
+ if (type == cricket::CA_ANSWER && offer_set_) {
+ // We have received and offer and now we receive an answer.
+ // Negotiation is done. Update the counter to indicate this.
+ ++update_session_description_counter_;
+ offer_set_ = false;
+ } else {
+ // Received an offer when expecting an answer.
+ EXPECT_FALSE(offer_set_);
+ offer_set_ = true;
+ }
+ }
+
talk_base::scoped_ptr<cricket::MediaSessionDescriptionFactory>
session_description_factory_;
talk_base::scoped_ptr<const cricket::SessionDescription> local_desc_;
talk_base::scoped_ptr<const cricket::SessionDescription> remote_desc_;
+ bool offer_set_;
};
// PeerConnectionSignalingTest create two PeerConnectionSignaling instances
diff --git a/talk/app/webrtc/roapmessages.h b/talk/app/webrtc/roapmessages.h
index fe99e1f..7b18010 100644
--- a/talk/app/webrtc/roapmessages.h
+++ b/talk/app/webrtc/roapmessages.h
@@ -103,7 +103,7 @@
// Get remote SessionDescription if the session description has been parsed
// and the ownership is transferred to the caller.
// NULL otherwise.
- const cricket::SessionDescription* ReleaseSessionDescription() {
+ cricket::SessionDescription* ReleaseSessionDescription() {
return parsed_desc_.release();
}
const std::vector<cricket::Candidate>& candidates() const {
@@ -142,7 +142,7 @@
// Get remote SessionDescription if the session description has been parsed
// and the ownership is transferred to the caller.
// NULL otherwise.
- const cricket::SessionDescription* ReleaseSessionDescription() {
+ cricket::SessionDescription* ReleaseSessionDescription() {
return parsed_desc_.release();
}
const std::vector<cricket::Candidate>& candidates() { return candidates_; }
diff --git a/talk/app/webrtc/roapsession.cc b/talk/app/webrtc/roapsession.cc
index 6d76b0c..014539f 100644
--- a/talk/app/webrtc/roapsession.cc
+++ b/talk/app/webrtc/roapsession.cc
@@ -271,7 +271,7 @@
return kError;
}
-const SessionDescription* RoapSession::ReleaseRemoteDescription() {
+SessionDescription* RoapSession::ReleaseRemoteDescription() {
return remote_desc_.release();
}
diff --git a/talk/app/webrtc/roapsession.h b/talk/app/webrtc/roapsession.h
index c5712a8..7a0c27f 100644
--- a/talk/app/webrtc/roapsession.h
+++ b/talk/app/webrtc/roapsession.h
@@ -89,7 +89,7 @@
ParseResult Parse(const std::string& msg);
RoapErrorCode RemoteError();
// Get remote SessionDescription. The ownership is transferred to the caller.
- const SessionDescription* ReleaseRemoteDescription();
+ SessionDescription* ReleaseRemoteDescription();
const std::vector<Candidate>& RemoteCandidates();
private:
@@ -110,7 +110,7 @@
std::string session_token_;
std::string response_token_;
- talk_base::scoped_ptr<const SessionDescription> remote_desc_;
+ talk_base::scoped_ptr<SessionDescription> remote_desc_;
std::vector<Candidate> remote_candidates_;
RoapErrorCode remote_error_;
diff --git a/talk/app/webrtc/sessiondescriptionprovider.h b/talk/app/webrtc/sessiondescriptionprovider.h
index f0a7645..7142cdd 100644
--- a/talk/app/webrtc/sessiondescriptionprovider.h
+++ b/talk/app/webrtc/sessiondescriptionprovider.h
@@ -36,18 +36,32 @@
class SessionDescriptionProvider {
public:
- virtual const cricket::SessionDescription* ProvideOffer(
+ // Creates a new SessionDescription based on |options|.
+ // It does not affect the currently set local or remote SessionDescription.
+ // Caller is owner of the created SessionDescription.
+ virtual cricket::SessionDescription* CreateOffer(
const cricket::MediaSessionOptions& options) = 0;
- // Transfer ownership of remote_offer.
- virtual const cricket::SessionDescription* SetRemoteSessionDescription(
- const cricket::SessionDescription* remote_offer,
+ // Creates a new SessionDescription based on |offer| and |options|.
+ // It does not affect the currently set local or remote SessionDescription.
+ // Caller is owner of the created SessionDescription.
+ virtual cricket::SessionDescription* CreateAnswer(
+ const cricket::SessionDescription* offer,
+ const cricket::MediaSessionOptions& options) = 0;
+
+ // Transfers ownership of session description.
+ virtual void SetLocalDescription(const cricket::SessionDescription* desc,
+ cricket::ContentAction type) = 0;
+ virtual void SetRemoteDescription(cricket::SessionDescription* desc,
+ cricket::ContentAction type) = 0;
+ // Sets all the currently known remote candidates.
+ virtual void SetRemoteCandidates(
const std::vector<cricket::Candidate>& remote_candidates) = 0;
- virtual const cricket::SessionDescription* ProvideAnswer(
- const cricket::MediaSessionOptions& options) = 0;
-
- virtual void NegotiationDone() = 0;
+ // Current local session description.
+ virtual const cricket::SessionDescription* local_description() const = 0;
+ // Current remote session description.
+ virtual const cricket::SessionDescription* remote_description() const = 0;
protected:
virtual ~SessionDescriptionProvider() {}
diff --git a/talk/app/webrtc/webrtcsdp.cc b/talk/app/webrtc/webrtcsdp.cc
index 2fcb959..6986a8b 100644
--- a/talk/app/webrtc/webrtcsdp.cc
+++ b/talk/app/webrtc/webrtcsdp.cc
@@ -110,6 +110,13 @@
static const char kMediaTypeVideo[] = "video";
static const char kMediaTypeAudio[] = "audio";
+// Default Video resolution.
+// TODO: Implement negotiation of video resolution.
+static const int kDefaultVideoWidth = 640;
+static const int kDefaultVideoHeight = 480;
+static const int kDefaultVideoFrameRate = 30;
+static const int kDefaultVideoPreference = 0;
+
static void BuildMediaDescription(const cricket::ContentInfo& content_info,
const std::vector<Candidate>& candidates,
const MediaType media_type,
@@ -689,8 +696,12 @@
if (media_type == cricket::MEDIA_TYPE_VIDEO) {
VideoContentDescription* video_desc =
static_cast<VideoContentDescription*>(media_desc);
+ // TODO: We will send resolution in SDP. For now, use VGA.
video_desc->AddCodec(cricket::VideoCodec(payload_type, encoding_name,
- 0, 0, 0, 0));
+ kDefaultVideoWidth,
+ kDefaultVideoHeight,
+ kDefaultVideoFrameRate,
+ kDefaultVideoPreference));
} else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
AudioContentDescription* audio_desc =
static_cast<AudioContentDescription*>(media_desc);
diff --git a/talk/app/webrtc/webrtcsdp_unittest.cc b/talk/app/webrtc/webrtcsdp_unittest.cc
index 2fd1e6b..7e34d2c 100644
--- a/talk/app/webrtc/webrtcsdp_unittest.cc
+++ b/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -154,7 +154,7 @@
video->AddStream(video_stream3);
video->AddCrypto(CryptoParams(1, "AES_CM_128_HMAC_SHA1_80",
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
- video->AddCodec(VideoCodec(120, "VP8", 352, 288, 30, 0));
+ video->AddCodec(VideoCodec(120, "VP8", 640, 480, 30, 0));
desc_.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP,
video.release());
@@ -224,6 +224,9 @@
const VideoCodec c1 = vcd1->codecs().at(i);
const VideoCodec c2 = vcd2->codecs().at(i);
EXPECT_TRUE(c1.Matches(c2));
+ EXPECT_EQ(c1.width, c2.width);
+ EXPECT_EQ(c1.height, c2.height);
+ EXPECT_EQ(c1.framerate, c2.framerate);
}
// streams
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index 7e8a0a1..f84af03 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -57,6 +57,60 @@
static const char kRtpVideoChannelStr[] = "video_rtp";
static const char kRtcpVideoChannelStr[] = "video_rtcp";
+// Constants for setting the default encoder size.
+// TODO: Implement proper negotiation of video resolution.
+static const int kDefaultVideoCodecId = 100;
+static const int kDefaultVideoCodecFramerate = 30;
+static const char kDefaultVideoCodecName[] = "VP8";
+static const int kDefaultVideoCodecWidth = 640;
+static const int kDefaultVideoCodecHeight = 480;
+
+// MediaSessionDescriptionFactory always creates one StreamParams for
+// legacy reasons even if options don't contain any streams.
+// We need to remove it in that case since here options contains all streams
+// we want to send.
+// TODO: This is placed in the wrong file. Can we solve this problem by
+// adding a method MediaSessionDescriptionFactory::set_add_legacy_streams(false)
+// to prevent it from creating legacy streams.
+static void RemoveLegacyStreams(const cricket::MediaSessionOptions& options,
+ cricket::SessionDescription* description) {
+ bool found_audio_stream = false;
+ bool found_video_stream = false;
+ for (cricket::MediaSessionOptions::Streams::const_iterator it =
+ options.streams.begin();
+ it != options.streams.end(); ++it) {
+ if (it->type == cricket::MEDIA_TYPE_AUDIO)
+ found_audio_stream = true;
+
+ if (it->type == cricket::MEDIA_TYPE_VIDEO)
+ found_video_stream = true;
+ }
+ if (found_audio_stream == false) {
+ const cricket::ContentInfo* audio_info =
+ cricket::GetFirstAudioContent(description);
+ if (audio_info) {
+ const cricket::MediaContentDescription* const_media_desc =
+ static_cast<const cricket::MediaContentDescription*>(
+ audio_info->description);
+ cricket::MediaContentDescription* media_desc =
+ const_cast<cricket::MediaContentDescription*> (const_media_desc);
+ media_desc->mutable_streams().clear();
+ }
+ }
+ if (found_video_stream == false) {
+ const cricket::ContentInfo* video_info =
+ cricket::GetFirstVideoContent(description);
+ if (video_info) {
+ const cricket::MediaContentDescription* const_media_desc =
+ static_cast<const cricket::MediaContentDescription*>(
+ video_info->description);
+ cricket::MediaContentDescription* media_desc =
+ const_cast<cricket::MediaContentDescription*> (const_media_desc);
+ media_desc->mutable_streams().clear();
+ }
+ }
+}
+
WebRtcSession::WebRtcSession(cricket::ChannelManager* channel_manager,
talk_base::Thread* signaling_thread,
talk_base::Thread* worker_thread,
@@ -76,6 +130,13 @@
bool WebRtcSession::Initialize() {
// By default SRTP-SDES is enabled in WebRtc.
set_secure_policy(cricket::SEC_REQUIRED);
+
+ const cricket::VideoCodec default_codec(kDefaultVideoCodecId,
+ kDefaultVideoCodecName, kDefaultVideoCodecWidth, kDefaultVideoCodecHeight,
+ kDefaultVideoCodecFramerate, 0);
+ channel_manager_->SetDefaultVideoEncoderConfig(
+ cricket::VideoEncoderConfig(default_codec));
+
return CreateChannels();
}
@@ -116,52 +177,13 @@
return true;
}
-void WebRtcSession::SetRemoteCandidates(
- const cricket::Candidates& candidates) {
- // First partition the candidates for the proxies. During creation of channels
- // we created CN_AUDIO (audio) and CN_VIDEO (video) proxies.
- cricket::Candidates audio_candidates;
- cricket::Candidates video_candidates;
- for (cricket::Candidates::const_iterator citer = candidates.begin();
- citer != candidates.end(); ++citer) {
- if (((*citer).name().compare(kRtpVideoChannelStr) == 0) ||
- ((*citer).name().compare(kRtcpVideoChannelStr)) == 0) {
- // Candidate names for video rtp and rtcp channel
- video_candidates.push_back(*citer);
- } else {
- // Candidates for audio rtp and rtcp channel
- // Channel name will be "rtp" and "rtcp"
- audio_candidates.push_back(*citer);
- }
- }
+// Enabling voice and video channel.
+void WebRtcSession::EnableChannels() {
+ if (!voice_channel_->enabled())
+ voice_channel_->Enable(true);
- if (!audio_candidates.empty()) {
- cricket::TransportProxy* audio_proxy = GetTransportProxy(cricket::CN_AUDIO);
- if (audio_proxy) {
- // CompleteNegotiation will set actual impl's in Proxy.
- if (!audio_proxy->negotiated())
- audio_proxy->CompleteNegotiation();
- // TODO - Add a interface to TransportProxy to accept
- // remote candidate list.
- audio_proxy->impl()->OnRemoteCandidates(audio_candidates);
- } else {
- LOG(LS_INFO) << "No audio TransportProxy exists";
- }
- }
-
- if (!video_candidates.empty()) {
- cricket::TransportProxy* video_proxy = GetTransportProxy(cricket::CN_VIDEO);
- if (video_proxy) {
- // CompleteNegotiation will set actual impl's in Proxy.
- if (!video_proxy->negotiated())
- video_proxy->CompleteNegotiation();
- // TODO - Add a interface to TransportProxy to accept
- // remote candidate list.
- video_proxy->impl()->OnRemoteCandidates(video_candidates);
- } else {
- LOG(LS_INFO) << "No video TransportProxy exists";
- }
- }
+ if (!video_channel_->enabled())
+ video_channel_->Enable(true);
}
void WebRtcSession::OnTransportRequestSignaling(
@@ -269,19 +291,34 @@
cricket::VideoRenderer* renderer) {
ASSERT(signaling_thread()->IsCurrent());
// TODO: Fix SetLocalRenderer.
- //video_channel_->SetLocalRenderer(0, renderer);
+ // video_channel_->SetLocalRenderer(0, renderer);
}
void WebRtcSession::SetRemoteRenderer(const std::string& name,
cricket::VideoRenderer* renderer) {
ASSERT(signaling_thread()->IsCurrent());
- // TODO: Only the ssrc = 0 is supported at the moment.
- // Only one channel.
- video_channel_->SetRenderer(0, renderer);
+ const cricket::ContentInfo* video_info =
+ cricket::GetFirstVideoContent(remote_description());
+ if (!video_info) {
+ LOG(LS_ERROR) << "Video not received in this call";
+ }
+
+ const cricket::MediaContentDescription* video_content =
+ static_cast<const cricket::MediaContentDescription*>(
+ video_info->description);
+ cricket::StreamParams stream;
+ if (cricket::GetStreamByNickAndName(video_content->streams(), "", name,
+ &stream)) {
+ video_channel_->SetRenderer(stream.first_ssrc(), renderer);
+ } else {
+ // Allow that |stream| does not exist if renderer is null but assert
+ // otherwise.
+ VERIFY(renderer == NULL);
+ }
}
-const cricket::SessionDescription* WebRtcSession::ProvideOffer(
+cricket::SessionDescription* WebRtcSession::CreateOffer(
const cricket::MediaSessionOptions& options) {
if (!options.has_video) {
LOG(LS_WARNING) << "To receive video, has_video flag must be set to true";
@@ -290,65 +327,119 @@
cricket::SessionDescription* offer(
session_desc_factory_.CreateOffer(options, local_description()));
- set_local_description(offer);
+
+ // MediaSessionDescriptionFactory always creates one StreamParams for
+ // legacy reasons even if options don't contain any streams.
+ // We need to remove it in that case since here options contains all streams
+ // we want to send.
+ RemoveLegacyStreams(options, offer);
return offer;
}
-const cricket::SessionDescription* WebRtcSession::SetRemoteSessionDescription(
- const cricket::SessionDescription* remote_offer,
- const std::vector<cricket::Candidate>& remote_candidates) {
- set_remote_description(
- const_cast<cricket::SessionDescription*>(remote_offer));
- SetRemoteCandidates(remote_candidates);
- return remote_offer;
-}
-
-const cricket::SessionDescription* WebRtcSession::ProvideAnswer(
+cricket::SessionDescription* WebRtcSession::CreateAnswer(
+ const cricket::SessionDescription* offer,
const cricket::MediaSessionOptions& options) {
cricket::SessionDescription* answer(
- session_desc_factory_.CreateAnswer(remote_description(), options,
+ session_desc_factory_.CreateAnswer(offer, options,
local_description()));
- set_local_description(answer);
+ // MediaSessionDescriptionFactory always creates one StreamParams for
+ // legacy reasons even if options don't contain any streams.
+ // We need to remove it in that case since here options contains all streams
+ // we want to send.
+ RemoveLegacyStreams(options, answer);
return answer;
}
-void WebRtcSession::NegotiationDone() {
- // SetState of session is called after session receives both local and
- // remote descriptions. State transition will happen only when session
- // is in INIT state.
- if (state() == STATE_INIT) {
+void WebRtcSession::SetLocalDescription(const cricket::SessionDescription* desc,
+ cricket::ContentAction type) {
+ if (!VERIFY((type == cricket::CA_ANSWER &&
+ state() == STATE_RECEIVEDINITIATE) ||
+ (type == cricket::CA_OFFER &&
+ (state() != STATE_RECEIVEDINITIATE &&
+ state() != STATE_SENTINITIATE)))) {
+ LOG(LS_ERROR) << "SetLocalDescription called with action in wrong state, "
+ << "action: " << type << " state: " << state();
+ return;
+ }
+
+ set_local_description(desc);
+ if (type == cricket::CA_ANSWER) {
+ EnableChannels();
+ SetState(STATE_SENTACCEPT);
+ } else {
SetState(STATE_SENTINITIATE);
+ }
+}
+
+void WebRtcSession::SetRemoteDescription(cricket::SessionDescription* desc,
+ cricket::ContentAction type) {
+ if (!VERIFY((type == cricket::CA_ANSWER &&
+ state() == STATE_SENTINITIATE) ||
+ (type == cricket::CA_OFFER &&
+ (state() != STATE_RECEIVEDINITIATE &&
+ state() != STATE_SENTINITIATE)))) {
+ LOG(LS_ERROR) << "SetRemoteDescription called with action in wrong state, "
+ << "action: " << type << " state: " << state();
+ return;
+ }
+ set_remote_description(desc);
+
+ if (type == cricket::CA_ANSWER) {
+ EnableChannels();
SetState(STATE_RECEIVEDACCEPT);
+ } else {
+ SetState(STATE_RECEIVEDINITIATE);
+ }
+}
- // Enabling voice and video channel.
- voice_channel_->Enable(true);
- video_channel_->Enable(true);
+void WebRtcSession::SetRemoteCandidates(
+ const cricket::Candidates& candidates) {
+ // First partition the candidates for the proxies. During creation of channels
+ // we created CN_AUDIO (audio) and CN_VIDEO (video) proxies.
+ cricket::Candidates audio_candidates;
+ cricket::Candidates video_candidates;
+ for (cricket::Candidates::const_iterator citer = candidates.begin();
+ citer != candidates.end(); ++citer) {
+ if (((*citer).name().compare(kRtpVideoChannelStr) == 0) ||
+ ((*citer).name().compare(kRtcpVideoChannelStr)) == 0) {
+ // Candidate names for video rtp and rtcp channel
+ video_candidates.push_back(*citer);
+ } else {
+ // Candidates for audio rtp and rtcp channel
+ // Channel name will be "rtp" and "rtcp"
+ audio_candidates.push_back(*citer);
+ }
}
- const cricket::ContentInfo* audio_info =
- cricket::GetFirstAudioContent(local_description());
- if (audio_info) {
- const cricket::MediaContentDescription* audio_content =
- static_cast<const cricket::MediaContentDescription*>(
- audio_info->description);
- // Since channels are currently not supporting multiple send streams,
- // we can remove stream from a session by muting it.
- // TODO - Change needed when multiple send streams support
- // is available.
- voice_channel_->Mute(audio_content->streams().size() == 0);
+ // TODO: Justins comment:This is bad encapsulation, suggest we add a
+ // helper to BaseSession to allow us to
+ // pass in candidates without touching the transport proxies.
+ if (!audio_candidates.empty()) {
+ cricket::TransportProxy* audio_proxy = GetTransportProxy(cricket::CN_AUDIO);
+ if (audio_proxy) {
+ // CompleteNegotiation will set actual impl's in Proxy.
+ if (!audio_proxy->negotiated())
+ audio_proxy->CompleteNegotiation();
+ // TODO - Add a interface to TransportProxy to accept
+ // remote candidate list.
+ audio_proxy->impl()->OnRemoteCandidates(audio_candidates);
+ } else {
+ LOG(LS_INFO) << "No audio TransportProxy exists";
+ }
}
- const cricket::ContentInfo* video_info =
- cricket::GetFirstVideoContent(local_description());
- if (video_info) {
- const cricket::MediaContentDescription* video_content =
- static_cast<const cricket::MediaContentDescription*>(
- video_info->description);
- // Since channels are currently not supporting multiple send streams,
- // we can remove stream from a session by muting it.
- // TODO - Change needed when multiple send streams support
- // is available.
- video_channel_->Mute(video_content->streams().size() == 0);
+ if (!video_candidates.empty()) {
+ cricket::TransportProxy* video_proxy = GetTransportProxy(cricket::CN_VIDEO);
+ if (video_proxy) {
+ // CompleteNegotiation will set actual impl's in Proxy.
+ if (!video_proxy->negotiated())
+ video_proxy->CompleteNegotiation();
+ // TODO - Add a interface to TransportProxy to accept
+ // remote candidate list.
+ video_proxy->impl()->OnRemoteCandidates(video_candidates);
+ } else {
+ LOG(LS_INFO) << "No video TransportProxy exists";
+ }
}
}
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index f18783b..3206194 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -83,16 +83,24 @@
// TODO - It may be necessary to supply error code as well.
sigslot::signal0<> SignalError;
- protected:
// Implements SessionDescriptionProvider
- virtual const cricket::SessionDescription* ProvideOffer(
+ virtual cricket::SessionDescription* CreateOffer(
const cricket::MediaSessionOptions& options);
- virtual const cricket::SessionDescription* SetRemoteSessionDescription(
- const cricket::SessionDescription* remote_offer,
+ virtual cricket::SessionDescription* CreateAnswer(
+ const cricket::SessionDescription* offer,
+ const cricket::MediaSessionOptions& options);
+ virtual void SetLocalDescription(const cricket::SessionDescription* desc,
+ cricket::ContentAction type);
+ virtual void SetRemoteDescription(cricket::SessionDescription* desc,
+ cricket::ContentAction type);
+ virtual void SetRemoteCandidates(
const std::vector<cricket::Candidate>& remote_candidates);
- virtual const cricket::SessionDescription* ProvideAnswer(
- const cricket::MediaSessionOptions& options);
- virtual void NegotiationDone();
+ virtual const cricket::SessionDescription* local_description() const {
+ return cricket::BaseSession::local_description();
+ }
+ virtual const cricket::SessionDescription* remote_description() const {
+ return cricket::BaseSession::remote_description();
+ }
private:
// Implements MediaProviderInterface.
@@ -115,12 +123,12 @@
// Creates channels for voice and video.
bool CreateChannels();
+ void EnableChannels();
virtual void OnMessage(talk_base::Message* msg);
void InsertTransportCandidates(const cricket::Candidates& candidates);
void Terminate();
// Get candidate from the local candidates list by the name.
bool CheckCandidate(const std::string& name);
- void SetRemoteCandidates(const cricket::Candidates& candidates);
talk_base::scoped_ptr<cricket::VoiceChannel> voice_channel_;
talk_base::scoped_ptr<cricket::VideoChannel> video_channel_;
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index e28df9f..313a35c 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -28,10 +28,21 @@
#include "talk/app/webrtc/webrtcsession.h"
#include "talk/base/thread.h"
#include "talk/base/gunit.h"
+#include "talk/session/phone/fakedevicemanager.h"
+#include "talk/session/phone/fakemediaengine.h"
#include "talk/p2p/client/fakeportallocator.h"
#include "talk/session/phone/channelmanager.h"
#include "talk/session/phone/mediasession.h"
+static const char kStream1[] = "stream1";
+static const char kVideoTrack1[] = "video1";
+static const char kAudioTrack1[] = "audio1";
+
+static const char kStream2[] = "stream2";
+static const char kVideoTrack2[] = "video2";
+static const char kAudioTrack2[] = "audio2";
+
+
class MockWebRtcSessionObserver : public webrtc::WebRtcSessionObserver {
public:
virtual void OnCandidatesReady(
@@ -54,49 +65,40 @@
}
virtual ~WebRtcSessionForTest() {}
- using webrtc::WebRtcSession::ProvideOffer;
- using webrtc::WebRtcSession::SetRemoteSessionDescription;
- using webrtc::WebRtcSession::ProvideAnswer;
- using webrtc::WebRtcSession::NegotiationDone;
+ using webrtc::WebRtcSession::CreateOffer;
+ using webrtc::WebRtcSession::CreateAnswer;
+ using webrtc::WebRtcSession::SetLocalDescription;
+ using webrtc::WebRtcSession::SetRemoteDescription;
+ using webrtc::WebRtcSession::SetRemoteCandidates;
};
class WebRtcSessionTest : public testing::Test {
protected:
virtual void SetUp() {
- channel_manager_.reset(
- new cricket::ChannelManager(talk_base::Thread::Current()));
- port_allocator_.reset(
- new cricket::FakePortAllocator(talk_base::Thread::Current(), NULL));
+ cricket::FakeMediaEngine* media_engine(new cricket::FakeMediaEngine());
+ cricket::FakeDeviceManager* device_manager(
+ new cricket::FakeDeviceManager());
+
+ channel_manager_.reset(new cricket::ChannelManager(
+ media_engine, device_manager, talk_base::Thread::Current()));
+ port_allocator_.reset(new cricket::FakePortAllocator(
+ talk_base::Thread::Current(), NULL));
desc_factory_.reset(
new cricket::MediaSessionDescriptionFactory(channel_manager_.get()));
- }
- bool InitializeSession() {
- return session_.get()->Initialize();
- }
-
- bool CheckChannels() {
- return (session_->voice_channel() != NULL &&
- session_->video_channel() != NULL);
- }
-
- void CheckTransportChannels() {
- EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, "rtp") != NULL);
- EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, "rtcp") != NULL);
- EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, "video_rtp") != NULL);
- EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, "video_rtcp") != NULL);
- }
-
- void Init() {
ASSERT_TRUE(channel_manager_.get() != NULL);
ASSERT_TRUE(session_.get() == NULL);
- EXPECT_TRUE(channel_manager_.get()->Init());
+ ASSERT_TRUE(channel_manager_.get()->Init());
+
session_.reset(new WebRtcSessionForTest(
channel_manager_.get(), talk_base::Thread::Current(),
talk_base::Thread::Current(), port_allocator_.get()));
session_->RegisterObserver(&observer_);
- desc_provider_ = session_.get();
- EXPECT_TRUE(InitializeSession());
+
+ EXPECT_TRUE(session_->Initialize());
+
+ video_channel_ = media_engine->GetVideoChannel(0);
+ voice_channel_ = media_engine->GetVoiceChannel(0);
}
void PopulateFakeCandidates() {
@@ -114,11 +116,62 @@
}
}
- void CreateOffer() {
+ // Create a session description based on options. Used for testing but don't
+ // test WebRtcSession.
+ cricket::SessionDescription* CreateTestOffer(
+ const cricket::MediaSessionOptions& options) {
+ desc_factory_->set_secure(cricket::SEC_REQUIRED);
+ return desc_factory_->CreateOffer(options, NULL);
+ }
+
+ // Create a session description based on options. Used for testing but don't
+ // test WebRtcSession.
+ cricket::SessionDescription* CreateTestAnswer(
+ const cricket::SessionDescription* offer,
+ const cricket::MediaSessionOptions& options) {
+ desc_factory_->set_secure(cricket::SEC_REQUIRED);
+ return desc_factory_->CreateAnswer(offer, options, NULL);
+ }
+
+ cricket::MediaSessionOptions OptionsWithStream1() {
+ cricket::MediaSessionOptions options;
+ options.AddStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack1, kStream1);
+ options.AddStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack1, kStream1);
+ return options;
+ }
+
+ cricket::MediaSessionOptions OptionsWithStream2() {
+ cricket::MediaSessionOptions options;
+ options.AddStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack2, kStream2);
+ options.AddStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack2, kStream2);
+ return options;
+ }
+
+ cricket::MediaSessionOptions OptionsWithStream1And2() {
+ cricket::MediaSessionOptions options;
+ options.AddStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack1, kStream1);
+ options.AddStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack1, kStream1);
+ options.AddStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack2, kStream2);
+ options.AddStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack2, kStream2);
+ return options;
+ }
+
+ cricket::MediaSessionOptions OptionsReceiveOnly() {
cricket::MediaSessionOptions options;
options.has_video = true;
- session_->ProvideOffer(options);
- ASSERT_TRUE(session_->local_description() != NULL);
+ return options;
+ }
+
+ bool ChannelsExist() {
+ return (session_->voice_channel() != NULL &&
+ session_->video_channel() != NULL);
+ }
+
+ void CheckTransportChannels() {
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, "rtp") != NULL);
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_AUDIO, "rtcp") != NULL);
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, "video_rtp") != NULL);
+ EXPECT_TRUE(session_->GetChannel(cricket::CN_VIDEO, "video_rtcp") != NULL);
}
void VerifyCryptoParams(const cricket::SessionDescription* sdp,
@@ -186,12 +239,8 @@
desc_factory_->CreateOffer(options, NULL);
ASSERT_TRUE(offer != NULL);
VerifyNoCryptoParams(offer);
- // Change security parameter to SEC_REQUIRED.
- desc_factory_->set_secure(cricket::SEC_REQUIRED);
- PopulateFakeCandidates();
- session_->SetRemoteSessionDescription(offer, candidates_);
const cricket::SessionDescription* answer =
- session_->ProvideAnswer(options);
+ session_->CreateAnswer(offer, options);
// Answer should be NULL as no crypto params in offer.
ASSERT_TRUE(answer == NULL);
}
@@ -204,63 +253,130 @@
desc_factory_->CreateOffer(options, NULL);
ASSERT_TRUE(offer != NULL);
VerifyCryptoParams(offer, true);
- PopulateFakeCandidates();
- session_->SetRemoteSessionDescription(offer, candidates_);
const cricket::SessionDescription* answer =
- session_->ProvideAnswer(options);
+ session_->CreateAnswer(offer, options);
ASSERT_TRUE(answer != NULL);
VerifyCryptoParams(answer, false);
}
talk_base::scoped_ptr<cricket::PortAllocator> port_allocator_;
- webrtc::SessionDescriptionProvider* desc_provider_;
talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
talk_base::scoped_ptr<cricket::MediaSessionDescriptionFactory> desc_factory_;
talk_base::scoped_ptr<WebRtcSessionForTest> session_;
MockWebRtcSessionObserver observer_;
std::vector<cricket::Candidate> candidates_;
+ cricket::FakeVideoMediaChannel* video_channel_;
+ cricket::FakeVoiceMediaChannel* voice_channel_;
};
TEST_F(WebRtcSessionTest, TestInitialize) {
- WebRtcSessionTest::Init();
- EXPECT_TRUE(CheckChannels());
+ EXPECT_TRUE(ChannelsExist());
CheckTransportChannels();
talk_base::Thread::Current()->ProcessMessages(1000);
EXPECT_EQ(4u, observer_.candidates_.size());
}
-// TODO - Adding test cases for session.
-TEST_F(WebRtcSessionTest, DISABLE_TestOfferAnswer) {
- WebRtcSessionTest::Init();
- EXPECT_TRUE(CheckChannels());
- CheckTransportChannels();
- talk_base::Thread::Current()->ProcessMessages(1);
+// Test creating offers and receive answers and make sure the
+// media engine creates the expected send and receive streams.
+TEST_F(WebRtcSessionTest, TestCreateOfferReceiveAnswer) {
+ cricket::MediaSessionOptions options = OptionsWithStream1();
+ cricket::SessionDescription* offer = session_->CreateOffer(options);
+
+ cricket::MediaSessionOptions options2 = OptionsWithStream2();
+ cricket::SessionDescription* answer = CreateTestAnswer(offer, options2);
+
+ session_->SetLocalDescription(offer, cricket::CA_OFFER);
+ session_->SetRemoteDescription(answer, cricket::CA_ANSWER);
+
+ ASSERT_EQ(1u, video_channel_->recv_streams().size());
+ cricket::StreamParams recv_video_stream =
+ video_channel_->recv_streams()[0];
+ EXPECT_TRUE(kVideoTrack2 == recv_video_stream.name);
+
+ ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+ cricket::StreamParams recv_audio_stream =
+ voice_channel_->recv_streams()[0];
+ EXPECT_TRUE(kAudioTrack2 == recv_audio_stream.name);
+
+ ASSERT_EQ(1u, video_channel_->send_streams().size());
+ EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].name);
+ ASSERT_EQ(1u, voice_channel_->send_streams().size());
+ EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].name);
+
+ // Create new offer without send streams.
+ offer = session_->CreateOffer(OptionsReceiveOnly());
+ // Test with same answer.
+ session_->SetLocalDescription(offer, cricket::CA_OFFER);
+ session_->SetRemoteDescription(answer, cricket::CA_ANSWER);
+
+ EXPECT_EQ(0u, video_channel_->send_streams().size());
+ EXPECT_EQ(0u, voice_channel_->send_streams().size());
+
+ // Make sure the receive streams have not changed.
+ ASSERT_EQ(1u, video_channel_->recv_streams().size());
+ EXPECT_EQ(recv_video_stream, video_channel_->recv_streams()[0]);
+ ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+ EXPECT_EQ(recv_audio_stream, voice_channel_->recv_streams()[0]);
+}
+
+// Test receiving offers and creating answers and make sure the
+// media engine creates the expected send and receive streams.
+TEST_F(WebRtcSessionTest, TestReceiveOfferCreateAnswer) {
+ cricket::SessionDescription* offer = CreateTestOffer(OptionsWithStream2());
+
+ cricket::MediaSessionOptions answer_options = OptionsWithStream1();
+ cricket::SessionDescription* answer =
+ session_->CreateAnswer(offer, answer_options);
+ session_->SetRemoteDescription(offer, cricket::CA_OFFER);
+ session_->SetLocalDescription(answer, cricket::CA_ANSWER);
+
+ ASSERT_EQ(1u, video_channel_->recv_streams().size());
+ EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].name);
+
+ ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+ EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].name);
+
+ ASSERT_EQ(1u, video_channel_->send_streams().size());
+ EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].name);
+ ASSERT_EQ(1u, voice_channel_->send_streams().size());
+ EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].name);
+
+ offer = CreateTestOffer(OptionsWithStream1And2());
+
+ // Answer by turning off all send streams.
+ answer = session_->CreateAnswer(offer, OptionsReceiveOnly());
+ session_->SetRemoteDescription(offer, cricket::CA_OFFER);
+ session_->SetLocalDescription(answer, cricket::CA_ANSWER);
+
+ ASSERT_EQ(2u, video_channel_->recv_streams().size());
+ EXPECT_TRUE(kVideoTrack1 == video_channel_->recv_streams()[0].name);
+ EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[1].name);
+ ASSERT_EQ(2u, voice_channel_->recv_streams().size());
+ EXPECT_TRUE(kAudioTrack1 == voice_channel_->recv_streams()[0].name);
+ EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[1].name);
+
+ // Make we have no send streams.
+ EXPECT_EQ(0u, video_channel_->send_streams().size());
+ EXPECT_EQ(0u, voice_channel_->send_streams().size());
}
TEST_F(WebRtcSessionTest, TestDefaultSetSecurePolicy) {
- WebRtcSessionTest::Init();
EXPECT_EQ(cricket::SEC_REQUIRED, session_->secure_policy());
}
TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) {
- WebRtcSessionTest::Init();
- CreateOffer();
- VerifyCryptoParams(session_->local_description(), true);
+ VerifyCryptoParams(session_->CreateOffer(OptionsWithStream1()), true);
}
TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) {
- WebRtcSessionTest::Init();
session_->set_secure_policy(cricket::SEC_DISABLED);
- CreateOffer();
- VerifyNoCryptoParams(session_->local_description());
+ VerifyNoCryptoParams(session_->CreateOffer(OptionsWithStream1()));
}
TEST_F(WebRtcSessionTest, VerifyAnswerFromNonCryptoOffer) {
- WebRtcSessionTest::Init();
VerifyAnswerFromNonCryptoOffer();
}
TEST_F(WebRtcSessionTest, VerifyAnswerFromCryptoOffer) {
- WebRtcSessionTest::Init();
VerifyAnswerFromCryptoOffer();
}
diff --git a/talk/session/phone/fakewebrtcvoiceengine.h b/talk/session/phone/fakewebrtcvoiceengine.h
index 29735f8..568d408 100644
--- a/talk/session/phone/fakewebrtcvoiceengine.h
+++ b/talk/session/phone/fakewebrtcvoiceengine.h
@@ -182,7 +182,7 @@
void TriggerProcessPacket(MediaProcessorDirection direction) {
webrtc::ProcessingTypes pt =
(direction == cricket::MPD_TX) ?
- webrtc::kRecordingPerChannel : webrtc::kPlaybackAllChannelsMixed;
+ webrtc::kRecordingPerChannel : webrtc::kPlaybackPerChannel;
if (media_processor_ != NULL) {
media_processor_->Process(0,
pt,
diff --git a/talk/session/phone/webrtcvideoframe_unittest.cc b/talk/session/phone/webrtcvideoframe_unittest.cc
index ea47a72..903827e 100644
--- a/talk/session/phone/webrtcvideoframe_unittest.cc
+++ b/talk/session/phone/webrtcvideoframe_unittest.cc
@@ -86,12 +86,48 @@
TEST_WEBRTCVIDEOFRAME(ConvertToRGB565Buffer)
TEST_WEBRTCVIDEOFRAME(ConvertToRGB565BufferStride)
TEST_WEBRTCVIDEOFRAME(ConvertToRGB565BufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertToBayerBGGRBuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertToBayerBGGRBufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertToBayerBGGRBufferInverted)
TEST_WEBRTCVIDEOFRAME(ConvertToYUY2Buffer)
TEST_WEBRTCVIDEOFRAME(ConvertToYUY2BufferStride)
TEST_WEBRTCVIDEOFRAME(ConvertToYUY2BufferInverted)
TEST_WEBRTCVIDEOFRAME(ConvertToUYVYBuffer)
TEST_WEBRTCVIDEOFRAME(ConvertToUYVYBufferStride)
TEST_WEBRTCVIDEOFRAME(ConvertToUYVYBufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromABGRBuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromABGRBufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromABGRBufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGB1555Buffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGB1555BufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGB1555BufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGB4444Buffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGB4444BufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGB4444BufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGBBuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGBBufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromARGBBufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromBGRABuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromBGRABufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromBGRABufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRAWBuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRAWBufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRAWBufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRGB24Buffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRGB24BufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRGB24BufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRGB565Buffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRGB565BufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromRGB565BufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromBayerBGGRBuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromBayerBGGRBufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromBayerBGGRBufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromYUY2Buffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromYUY2BufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromYUY2BufferInverted)
+TEST_WEBRTCVIDEOFRAME(ConvertFromUYVYBuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertFromUYVYBufferStride)
+TEST_WEBRTCVIDEOFRAME(ConvertFromUYVYBufferInverted)
//TEST_WEBRTCVIDEOFRAME(ConvertToI422Buffer)
TEST_WEBRTCVIDEOFRAME(ConvertARGBToBayerGRBG)
TEST_WEBRTCVIDEOFRAME(ConvertARGBToBayerGBRG)
diff --git a/talk/session/phone/webrtcvoiceengine.cc b/talk/session/phone/webrtcvoiceengine.cc
index 58706f9..9d44fce 100644
--- a/talk/session/phone/webrtcvoiceengine.cc
+++ b/talk/session/phone/webrtcvoiceengine.cc
@@ -940,13 +940,14 @@
it != channels_.end(); ++it) {
ASSERT(*it != NULL);
uint32 local_ssrc;
- if (voe()->rtp()->GetLocalSSRC((*it)->voe_channel(), local_ssrc) != -1) {
- if (ssrc == local_ssrc) {
- *channel_num = (*it)->voe_channel();
- }
- }
- if (*channel_num == -1 && (direction & MPD_RX) != 0) {
+ if ((direction & MPD_RX) != 0) {
*channel_num = (*it)->GetChannelNum(ssrc);
+ } else {
+ if (voe()->rtp()->GetLocalSSRC((*it)->voe_channel(), local_ssrc) != -1) {
+ if (ssrc == local_ssrc) {
+ *channel_num = (*it)->voe_channel();
+ }
+ }
}
if (*channel_num != -1) {
return true;
@@ -1079,7 +1080,7 @@
talk_base::CritScope cs(&signal_media_critical_);
webrtc::ProcessingTypes processing_type;
if (direction == MPD_RX) {
- processing_type = webrtc::kPlaybackAllChannelsMixed;
+ processing_type = webrtc::kPlaybackPerChannel;
if (SignalRxMediaFrame.is_empty()) {
register_with_webrtc = true;
}
@@ -1134,13 +1135,13 @@
SignalRxMediaFrame.disconnect(voice_processor);
if (SignalRxMediaFrame.is_empty()) {
if (voe()->media()->DeRegisterExternalMediaProcessing(channel_id,
- webrtc::kPlaybackAllChannelsMixed) != -1) {
+ webrtc::kPlaybackPerChannel) != -1) {
LOG(LS_INFO) << "Media Processing DeRegistration Succeeded. channel:"
<< channel_id;
} else {
LOG_RTCERR2(DeRegisterExternalMediaProcessing,
channel_id,
- webrtc::kPlaybackAllChannelsMixed);
+ webrtc::kPlaybackPerChannel);
success = false;
}
}
@@ -1176,7 +1177,7 @@
if (FindChannelAndSsrc(channel, &media_channel, &ssrc)) {
talk_base::CritScope cs(&signal_media_critical_);
AudioFrame frame(audio10ms, length, sampling_freq, is_stereo);
- if (type == webrtc::kPlaybackAllChannelsMixed) {
+ if (type == webrtc::kPlaybackPerChannel) {
SignalRxMediaFrame(ssrc, &frame);
} else if (type == webrtc::kRecordingPerChannel) {
SignalTxMediaFrame(ssrc, &frame);
@@ -1192,6 +1193,7 @@
: WebRtcMediaChannel<VoiceMediaChannel, WebRtcVoiceEngine>(
engine,
engine->voe()->base()->CreateChannel()),
+ recv_codecs_set_(false),
channel_options_(0),
agc_adjusted_(false),
dtmf_allowed_(false),
@@ -1272,12 +1274,21 @@
LOG_RTCERR2(SetRecPayloadType, voe_channel(), ToString(voe_codec));
ret = false;
}
+ // Set the receive codecs on all receiving channels.
+ for (ChannelMap::iterator it = mux_channels_.begin();
+ it != mux_channels_.end() && ret; ++it) {
+ if (engine()->voe()->codec()->SetRecPayloadType(
+ it->second, voe_codec) == -1) {
+ LOG_RTCERR2(SetRecPayloadType, it->second, ToString(voe_codec));
+ ret = false;
+ }
+ }
} else {
LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
ret = false;
}
}
-
+ recv_codecs_set_ = ret;
return ret;
}
@@ -1652,17 +1663,19 @@
// Use the same recv payload types as our default channel.
ResetRecvCodecs(channel);
- int ncodecs = engine()->voe()->codec()->NumOfCodecs();
- for (int i = 0; i < ncodecs; ++i) {
- webrtc::CodecInst voe_codec;
- if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
- voe_codec.rate = 0; // Needed to make GetRecPayloadType work for ISAC
- if (engine()->voe()->codec()->GetRecPayloadType(
- voe_channel(), voe_codec) != -1) {
- if (engine()->voe()->codec()->SetRecPayloadType(
- channel, voe_codec) == -1) {
- LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
- return false;
+ if (recv_codecs_set_) {
+ int ncodecs = engine()->voe()->codec()->NumOfCodecs();
+ for (int i = 0; i < ncodecs; ++i) {
+ webrtc::CodecInst voe_codec;
+ if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
+ voe_codec.rate = 0; // Needed to make GetRecPayloadType work for ISAC
+ if (engine()->voe()->codec()->GetRecPayloadType(
+ voe_channel(), voe_codec) != -1) {
+ if (engine()->voe()->codec()->SetRecPayloadType(
+ channel, voe_codec) == -1) {
+ LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
+ return false;
+ }
}
}
}
diff --git a/talk/session/phone/webrtcvoiceengine.h b/talk/session/phone/webrtcvoiceengine.h
index dfb9023..7cc148a 100644
--- a/talk/session/phone/webrtcvoiceengine.h
+++ b/talk/session/phone/webrtcvoiceengine.h
@@ -347,6 +347,7 @@
typedef std::map<uint32, int> ChannelMap;
talk_base::scoped_ptr<WebRtcSoundclipStream> ringback_tone_;
std::set<int> ringback_channels_; // channels playing ringback
+ bool recv_codecs_set_;
talk_base::scoped_ptr<webrtc::CodecInst> send_codec_;
int channel_options_;
bool agc_adjusted_;
@@ -355,6 +356,7 @@
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
diff --git a/talk/session/phone/webrtcvoiceengine_unittest.cc b/talk/session/phone/webrtcvoiceengine_unittest.cc
index 82838d1..9b4df86 100644
--- a/talk/session/phone/webrtcvoiceengine_unittest.cc
+++ b/talk/session/phone/webrtcvoiceengine_unittest.cc
@@ -277,6 +277,25 @@
EXPECT_STREQ("telephone-event", gcodec.plname);
}
+TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsAfterAddingStreams) {
+ EXPECT_TRUE(SetupEngine());
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kIsacCodec);
+ codecs[0].id = 106; // collide with existing telephone-event
+
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc1)));
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+
+ int channel_num2 = voe_.GetLastChannel();
+ webrtc::CodecInst gcodec;
+ talk_base::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "ISAC");
+ gcodec.plfreq = 16000;
+ EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec));
+ EXPECT_EQ(106, gcodec.pltype);
+ EXPECT_STREQ("ISAC", gcodec.plname);
+}
+
// Test that we apply codecs properly.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecs) {
EXPECT_TRUE(SetupEngine());
@@ -1086,6 +1105,8 @@
// webrtcvoiceengine works as expected
TEST_F(WebRtcVoiceEngineTestFake, RegisterVoiceProcessor) {
EXPECT_TRUE(SetupEngine());
+ channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc1));
uint32 ssrc = 0;
voe_.GetLocalSSRC(0, ssrc);
cricket::FakeMediaProcessor vp_1;