diff options
author | pthatcher@webrtc.org <pthatcher@webrtc.org> | 2014-12-19 22:29:55 +0000 |
---|---|---|
committer | pthatcher@webrtc.org <pthatcher@webrtc.org> | 2014-12-19 22:29:55 +0000 |
commit | 4c0544ab07987fa080a832123bee5e61750fd815 (patch) | |
tree | c580014d84b99397167bc8522e3633c3c0ff96e5 /talk | |
parent | ed1a48b0cd405b0e6c76450f422e1a1c8b95421f (diff) | |
download | webrtc-4c0544ab07987fa080a832123bee5e61750fd815.tar.gz |
Move Jingle-specific files from talk/session/media to webrtc/libjingle/session/media. This is part of an ongoing effort to remove Jingle-specific files from the WebRTC repository.
Also, fix the includes and header guards of examples/call.
R=juberti@webrtc.org, pbos@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/34559004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7972 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'talk')
-rwxr-xr-x | talk/libjingle.gyp | 7 | ||||
-rwxr-xr-x | talk/libjingle_tests.gyp | 2 | ||||
-rw-r--r-- | talk/session/media/call.cc | 1132 | ||||
-rw-r--r-- | talk/session/media/call.h | 307 | ||||
-rw-r--r-- | talk/session/media/currentspeakermonitor_unittest.cc | 51 | ||||
-rw-r--r-- | talk/session/media/mediamessages.cc | 333 | ||||
-rw-r--r-- | talk/session/media/mediamessages.h | 98 | ||||
-rw-r--r-- | talk/session/media/mediamessages_unittest.cc | 363 | ||||
-rw-r--r-- | talk/session/media/mediasessionclient.cc | 1161 | ||||
-rw-r--r-- | talk/session/media/mediasessionclient.h | 175 | ||||
-rw-r--r-- | talk/session/media/mediasessionclient_unittest.cc | 3324 |
11 files changed, 22 insertions, 6931 deletions
diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index d12affbf45..56d29af12e 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp @@ -575,7 +575,6 @@ '<(DEPTH)/third_party/libsrtp/libsrtp.gyp:libsrtp', 'libjingle', 'libjingle_media', - '<(webrtc_root)/libjingle/libjingle.gyp:jingle_session', ], 'include_dirs': [ '<(DEPTH)/testing/gtest/include', @@ -590,24 +589,18 @@ 'session/media/audiomonitor.h', 'session/media/bundlefilter.cc', 'session/media/bundlefilter.h', - 'session/media/call.cc', - 'session/media/call.h', 'session/media/channel.cc', 'session/media/channel.h', 'session/media/channelmanager.cc', 'session/media/channelmanager.h', 'session/media/currentspeakermonitor.cc', 'session/media/currentspeakermonitor.h', - 'session/media/mediamessages.cc', - 'session/media/mediamessages.h', 'session/media/mediamonitor.cc', 'session/media/mediamonitor.h', 'session/media/mediarecorder.cc', 'session/media/mediarecorder.h', 'session/media/mediasession.cc', 'session/media/mediasession.h', - 'session/media/mediasessionclient.cc', - 'session/media/mediasessionclient.h', 'session/media/mediasink.h', 'session/media/rtcpmuxfilter.cc', 'session/media/rtcpmuxfilter.h', diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp index 3410737788..b59a7ef463 100755 --- a/talk/libjingle_tests.gyp +++ b/talk/libjingle_tests.gyp @@ -167,9 +167,7 @@ 'session/media/channelmanager_unittest.cc', 'session/media/currentspeakermonitor_unittest.cc', 'session/media/mediarecorder_unittest.cc', - 'session/media/mediamessages_unittest.cc', 'session/media/mediasession_unittest.cc', - 'session/media/mediasessionclient_unittest.cc', 'session/media/rtcpmuxfilter_unittest.cc', 'session/media/srtpfilter_unittest.cc', ], diff --git a/talk/session/media/call.cc b/talk/session/media/call.cc deleted file mode 100644 index 784be9422c..0000000000 --- a/talk/session/media/call.cc +++ /dev/null @@ -1,1132 +0,0 @@ -/* - * libjingle - * 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: - * - * 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 <string> -#include "talk/media/base/constants.h" -#include "talk/media/base/screencastid.h" -#include "webrtc/p2p/base/parsing.h" -#include "talk/session/media/call.h" -#include "talk/session/media/currentspeakermonitor.h" -#include "talk/session/media/mediasessionclient.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/window.h" - -namespace cricket { - -const uint32 MSG_CHECKAUTODESTROY = 1; -const uint32 MSG_TERMINATECALL = 2; -const uint32 MSG_PLAYDTMF = 3; - -namespace { -const int kDTMFDelay = 300; // msec -const size_t kMaxDTMFDigits = 30; -const int kSendToVoicemailTimeout = 1000*20; -const int kNoVoicemailTimeout = 1000*180; -const int kMediaMonitorInterval = 1000*15; -// In order to be the same as the server-side switching, this must be 100. -const int kAudioMonitorPollPeriodMillis = 100; - -// V is a pointer type. -template<class K, class V> -V FindOrNull(const std::map<K, V>& map, - const K& key) { - typename std::map<K, V>::const_iterator it = map.find(key); - return (it != map.end()) ? it->second : NULL; -} - - -bool ContentContainsCrypto(const cricket::ContentInfo* content) { - if (content != NULL) { - const cricket::MediaContentDescription* desc = - static_cast<const cricket::MediaContentDescription*>( - content->description); - if (!desc || desc->cryptos().empty()) { - return false; - } - } - return true; -} - -} - -AudioSourceProxy::AudioSourceProxy(Call* call) - : call_(call) { - call_->SignalAudioMonitor.connect(this, &AudioSourceProxy::OnAudioMonitor); - call_->SignalMediaStreamsUpdate.connect( - this, &AudioSourceProxy::OnMediaStreamsUpdate); -} - -void AudioSourceProxy::OnAudioMonitor(Call* call, const AudioInfo& info) { - SignalAudioMonitor(this, info); -} - -void AudioSourceProxy::OnMediaStreamsUpdate(Call* call, Session* session, - const MediaStreams& added, const MediaStreams& removed) { - SignalMediaStreamsUpdate(this, session, added, removed); -} - -Call::Call(MediaSessionClient* session_client) - : id_(rtc::CreateRandomId()), - session_client_(session_client), - has_video_(false), - has_data_(false), - muted_(false), - video_muted_(false), - send_to_voicemail_(true), - playing_dtmf_(false) { - audio_source_proxy_.reset(new AudioSourceProxy(this)); -} - -Call::~Call() { - while (media_session_map_.begin() != media_session_map_.end()) { - Session* session = media_session_map_.begin()->second.session; - RemoveSession(session); - session_client_->session_manager()->DestroySession(session); - } - rtc::Thread::Current()->Clear(this); -} - -Session* Call::InitiateSession(const buzz::Jid& to, - const buzz::Jid& initiator, - const CallOptions& options) { - std::string id; - std::string initiator_name = initiator.Str(); - return InternalInitiateSession(id, to, initiator_name, options); -} - -Session *Call::InitiateSession(const std::string& id, - const buzz::Jid& to, - const CallOptions& options) { - std::string initiator_name; - return InternalInitiateSession(id, to, initiator_name, options); -} - -void Call::IncomingSession(Session* session, const SessionDescription* offer) { - AddSession(session, offer); - - // Make sure the session knows about the incoming ssrcs. This needs to be done - // prior to the SignalSessionState call, because that may trigger handling of - // these new SSRCs, so they need to be registered before then. - UpdateRemoteMediaStreams(session, offer->contents(), false); - - // Missed the first state, the initiate, which is needed by - // call_client. - SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE); -} - -void Call::AcceptSession(Session* session, - const cricket::CallOptions& options) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it != media_session_map_.end()) { - const SessionDescription* answer = session_client_->CreateAnswer( - session->remote_description(), options); - it->second.session->Accept(answer); - } -} - -void Call::RejectSession(Session* session) { - // Assume polite decline. - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it != media_session_map_.end()) - it->second.session->Reject(STR_TERMINATE_DECLINE); -} - -void Call::TerminateSession(Session* session) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it != media_session_map_.end()) { - // Assume polite terminations. - it->second.session->Terminate(); - } -} - -void Call::Terminate() { - // Copy the list so that we can iterate over it in a stable way - std::vector<Session*> sessions = this->sessions(); - - // There may be more than one session to terminate - std::vector<Session*>::iterator it; - for (it = sessions.begin(); it != sessions.end(); ++it) { - TerminateSession(*it); - } -} - -bool Call::SendViewRequest(Session* session, - const ViewRequest& view_request) { - StaticVideoViews::const_iterator it; - for (it = view_request.static_video_views.begin(); - it != view_request.static_video_views.end(); ++it) { - StreamParams found_stream; - bool found = false; - MediaStreams* recv_streams = GetMediaStreams(session); - if (recv_streams) - found = recv_streams->GetVideoStream(it->selector, &found_stream); - if (!found) { - LOG(LS_WARNING) << "Trying to send view request for (" - << it->selector.ssrc << ", '" - << it->selector.groupid << "', '" - << it->selector.streamid << "'" - << ") is not in the local streams."; - return false; - } - } - - XmlElements elems; - WriteError error; - if (!WriteJingleViewRequest(CN_VIDEO, view_request, &elems, &error)) { - LOG(LS_ERROR) << "Couldn't write out view request: " << error.text; - return false; - } - - return session->SendInfoMessage(elems, session->remote_name()); -} - -void Call::SetVideoRenderer(Session* session, uint32 ssrc, - VideoRenderer* renderer) { - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel) { - video_channel->SetRenderer(ssrc, renderer); - LOG(LS_INFO) << "Set renderer of ssrc " << ssrc - << " to " << renderer << "."; - } else { - LOG(LS_INFO) << "Failed to set renderer of ssrc " << ssrc << "."; - } -} - -void Call::OnMessage(rtc::Message* message) { - switch (message->message_id) { - case MSG_CHECKAUTODESTROY: - // If no more sessions for this call, delete it - if (media_session_map_.empty()) - session_client_->DestroyCall(this); - break; - case MSG_TERMINATECALL: - // Signal to the user that a timeout has happened and the call should - // be sent to voicemail. - if (send_to_voicemail_) { - SignalSetupToCallVoicemail(); - } - - // Callee didn't answer - terminate call - Terminate(); - break; - case MSG_PLAYDTMF: - ContinuePlayDTMF(); - } -} - -std::vector<Session*> Call::sessions() { - std::vector<Session*> sessions; - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) - sessions.push_back(it->second.session); - - return sessions; -} - -bool Call::AddSession(Session* session, const SessionDescription* offer) { - bool succeeded = true; - MediaSession media_session; - media_session.session = session; - media_session.voice_channel = NULL; - media_session.video_channel = NULL; - media_session.data_channel = NULL; - media_session.recv_streams = NULL; - - const ContentInfo* audio_offer = GetFirstAudioContent(offer); - const ContentInfo* video_offer = GetFirstVideoContent(offer); - const ContentInfo* data_offer = GetFirstDataContent(offer); - has_video_ = (video_offer != NULL); - has_data_ = (data_offer != NULL); - - ASSERT(audio_offer != NULL); - // Create voice channel and start a media monitor. - media_session.voice_channel = - session_client_->channel_manager()->CreateVoiceChannel( - session, audio_offer->name, has_video_); - // voice_channel can be NULL in case of NullVoiceEngine. - if (media_session.voice_channel) { - media_session.voice_channel->SignalMediaMonitor.connect( - this, &Call::OnMediaMonitor); - media_session.voice_channel->StartMediaMonitor(kMediaMonitorInterval); - } else { - succeeded = false; - } - - // If desired, create video channel and start a media monitor. - if (has_video_ && succeeded) { - media_session.video_channel = - session_client_->channel_manager()->CreateVideoChannel( - session, - video_offer->name, - true, - VideoOptions(), - media_session.voice_channel); - // video_channel can be NULL in case of NullVideoEngine. - if (media_session.video_channel) { - media_session.video_channel->SignalMediaMonitor.connect( - this, &Call::OnMediaMonitor); - media_session.video_channel->StartMediaMonitor(kMediaMonitorInterval); - } else { - succeeded = false; - } - } - - // If desired, create data channel. - if (has_data_ && succeeded) { - const DataContentDescription* data = GetFirstDataContentDescription(offer); - if (data == NULL) { - succeeded = false; - } else { - DataChannelType data_channel_type = DCT_RTP; - if ((data->protocol() == kMediaProtocolSctp) || - (data->protocol() == kMediaProtocolDtlsSctp)) { - data_channel_type = DCT_SCTP; - } - - bool rtcp = false; - media_session.data_channel = - session_client_->channel_manager()->CreateDataChannel( - session, data_offer->name, rtcp, data_channel_type); - if (media_session.data_channel) { - media_session.data_channel->SignalDataReceived.connect( - this, &Call::OnDataReceived); - } else { - succeeded = false; - } - } - } - - if (succeeded) { - // Add session to list, create channels for this session. - media_session.recv_streams = new MediaStreams; - media_session_map_[session->id()] = media_session; - session->SignalState.connect(this, &Call::OnSessionState); - session->SignalError.connect(this, &Call::OnSessionError); - session->SignalInfoMessage.connect( - this, &Call::OnSessionInfoMessage); - session->SignalRemoteDescriptionUpdate.connect( - this, &Call::OnRemoteDescriptionUpdate); - session->SignalReceivedTerminateReason - .connect(this, &Call::OnReceivedTerminateReason); - - // If this call has the focus, enable this session's channels. - if (session_client_->GetFocus() == this) { - EnableSessionChannels(session, true); - } - - // Signal client. - SignalAddSession(this, session); - } - - return succeeded; -} - -void Call::RemoveSession(Session* session) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) - return; - - // Remove all the screencasts, if they haven't been already. - while (!it->second.started_screencasts.empty()) { - uint32 ssrc = it->second.started_screencasts.begin()->first; - if (!StopScreencastWithoutSendingUpdate(it->second.session, ssrc)) { - LOG(LS_ERROR) << "Unable to stop screencast with ssrc " << ssrc; - ASSERT(false); - } - } - - // Destroy video channel - VideoChannel* video_channel = it->second.video_channel; - if (video_channel != NULL) - session_client_->channel_manager()->DestroyVideoChannel(video_channel); - - // Destroy voice channel - VoiceChannel* voice_channel = it->second.voice_channel; - if (voice_channel != NULL) - session_client_->channel_manager()->DestroyVoiceChannel(voice_channel); - - // Destroy data channel - DataChannel* data_channel = it->second.data_channel; - if (data_channel != NULL) - session_client_->channel_manager()->DestroyDataChannel(data_channel); - - delete it->second.recv_streams; - media_session_map_.erase(it); - - // Destroy speaker monitor - StopSpeakerMonitor(session); - - // Signal client - SignalRemoveSession(this, session); - - // The call auto destroys when the last session is removed - rtc::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY); -} - -VoiceChannel* Call::GetVoiceChannel(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.voice_channel : NULL; -} - -VideoChannel* Call::GetVideoChannel(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.video_channel : NULL; -} - -DataChannel* Call::GetDataChannel(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.data_channel : NULL; -} - -MediaStreams* Call::GetMediaStreams(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.recv_streams : NULL; -} - -void Call::EnableChannels(bool enable) { - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - EnableSessionChannels(it->second.session, enable); - } -} - -void Call::EnableSessionChannels(Session* session, bool enable) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) - return; - - VoiceChannel* voice_channel = it->second.voice_channel; - VideoChannel* video_channel = it->second.video_channel; - DataChannel* data_channel = it->second.data_channel; - if (voice_channel != NULL) - voice_channel->Enable(enable); - if (video_channel != NULL) - video_channel->Enable(enable); - if (data_channel != NULL) - data_channel->Enable(enable); -} - -void Call::Mute(bool mute) { - muted_ = mute; - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - if (it->second.voice_channel != NULL) - it->second.voice_channel->MuteStream(0, mute); - } -} - -void Call::MuteVideo(bool mute) { - video_muted_ = mute; - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - if (it->second.video_channel != NULL) - it->second.video_channel->MuteStream(0, mute); - } -} - -bool Call::SendData(Session* session, - const SendDataParams& params, - const rtc::Buffer& payload, - SendDataResult* result) { - DataChannel* data_channel = GetDataChannel(session); - if (!data_channel) { - LOG(LS_WARNING) << "Could not send data: no data channel."; - return false; - } - - return data_channel->SendData(params, payload, result); -} - -void Call::PressDTMF(int event) { - // Queue up this digit - if (queued_dtmf_.size() < kMaxDTMFDigits) { - LOG(LS_INFO) << "Call::PressDTMF(" << event << ")"; - - queued_dtmf_.push_back(event); - - if (!playing_dtmf_) { - ContinuePlayDTMF(); - } - } -} - -cricket::VideoFormat ScreencastFormatFromFps(int fps) { - // The capturer pretty much ignore this, but just in case we give it - // a resolution big enough to cover any expected desktop. In any - // case, it can't be 0x0, or the CaptureManager will fail to use it. - return cricket::VideoFormat( - 1, 1, - cricket::VideoFormat::FpsToInterval(fps), - cricket::FOURCC_ANY); -} - -bool Call::StartScreencast(Session* session, - const std::string& streamid, uint32 ssrc, - const ScreencastId& screenid, int fps) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) { - return false; - } - - VideoChannel *video_channel = GetVideoChannel(session); - if (!video_channel) { - LOG(LS_WARNING) << "Cannot add screencast" - << " because there is no video channel."; - return false; - } - - VideoCapturer* capturer = session_client_->channel_manager()-> - CreateScreenCapturer(screenid); - if (!capturer) { - LOG(LS_WARNING) << "Could not create screencast capturer."; - return false; - } - - if (!video_channel->AddScreencast(ssrc, capturer)) { - delete capturer; - LOG(LS_WARNING) << "Could not add screencast capturer."; - return false; - } - - VideoFormat format = ScreencastFormatFromFps(fps); - if (!session_client_->channel_manager()->StartVideoCapture( - capturer, format)) { - LOG(LS_WARNING) << "Could not start video capture."; - video_channel->RemoveScreencast(ssrc); - return false; - } - - if (!video_channel->SetCapturer(ssrc, capturer)) { - LOG(LS_WARNING) << "Could not start sending screencast."; - session_client_->channel_manager()->StopVideoCapture( - capturer, ScreencastFormatFromFps(fps)); - video_channel->RemoveScreencast(ssrc); - } - - // TODO(pthatcher): Once the CaptureManager has a nicer interface - // for removing captures (such as having StartCapture return a - // handle), remove this StartedCapture stuff. - it->second.started_screencasts.insert( - std::make_pair(ssrc, StartedCapture(capturer, format))); - - // TODO(pthatcher): Verify we aren't re-using an existing id or - // ssrc. - StreamParams stream; - stream.id = streamid; - stream.ssrcs.push_back(ssrc); - VideoContentDescription* video = CreateVideoStreamUpdate(stream); - - // TODO(pthatcher): Wait until view request before sending video. - video_channel->SetLocalContent(video, CA_UPDATE, NULL); - SendVideoStreamUpdate(session, video); - return true; -} - -bool Call::StopScreencast(Session* session, - const std::string& streamid, uint32 ssrc) { - if (!StopScreencastWithoutSendingUpdate(session, ssrc)) { - return false; - } - - VideoChannel *video_channel = GetVideoChannel(session); - if (!video_channel) { - LOG(LS_WARNING) << "Cannot add screencast" - << " because there is no video channel."; - return false; - } - - StreamParams stream; - stream.id = streamid; - // No ssrcs - VideoContentDescription* video = CreateVideoStreamUpdate(stream); - - video_channel->SetLocalContent(video, CA_UPDATE, NULL); - SendVideoStreamUpdate(session, video); - return true; -} - -bool Call::StopScreencastWithoutSendingUpdate( - Session* session, uint32 ssrc) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) { - return false; - } - - VideoChannel *video_channel = GetVideoChannel(session); - if (!video_channel) { - LOG(LS_WARNING) << "Cannot remove screencast" - << " because there is no video channel."; - return false; - } - - StartedScreencastMap::const_iterator screencast_iter = - it->second.started_screencasts.find(ssrc); - if (screencast_iter == it->second.started_screencasts.end()) { - LOG(LS_WARNING) << "Could not stop screencast " << ssrc - << " because there is no capturer."; - return false; - } - - VideoCapturer* capturer = screencast_iter->second.capturer; - VideoFormat format = screencast_iter->second.format; - video_channel->SetCapturer(ssrc, NULL); - if (!session_client_->channel_manager()->StopVideoCapture( - capturer, format)) { - LOG(LS_WARNING) << "Could not stop screencast " << ssrc - << " because could not stop capture."; - return false; - } - video_channel->RemoveScreencast(ssrc); - it->second.started_screencasts.erase(ssrc); - return true; -} - -VideoContentDescription* Call::CreateVideoStreamUpdate( - const StreamParams& stream) { - VideoContentDescription* video = new VideoContentDescription(); - video->set_multistream(true); - video->set_partial(true); - video->AddStream(stream); - return video; -} - -void Call::SendVideoStreamUpdate( - Session* session, VideoContentDescription* video) { - // Takes the ownership of |video|. - rtc::scoped_ptr<VideoContentDescription> description(video); - const ContentInfo* video_info = - GetFirstVideoContent(session->local_description()); - if (video_info == NULL) { - LOG(LS_WARNING) << "Cannot send stream update for video."; - return; - } - - std::vector<ContentInfo> contents; - contents.push_back( - ContentInfo(video_info->name, video_info->type, description.get())); - - session->SendDescriptionInfoMessage(contents); -} - -void Call::ContinuePlayDTMF() { - playing_dtmf_ = false; - - // Check to see if we have a queued tone - if (queued_dtmf_.size() > 0) { - playing_dtmf_ = true; - - int tone = queued_dtmf_.front(); - queued_dtmf_.pop_front(); - - LOG(LS_INFO) << "Call::ContinuePlayDTMF(" << tone << ")"; - for (MediaSessionMap::iterator it = media_session_map_.begin(); - it != media_session_map_.end(); ++it) { - if (it->second.voice_channel != NULL) { - it->second.voice_channel->PressDTMF(tone, true); - } - } - - // Post a message to play the next tone or at least clear the playing_dtmf_ - // bit. - rtc::Thread::Current()->PostDelayed(kDTMFDelay, this, MSG_PLAYDTMF); - } -} - -void Call::Join(Call* call, bool enable) { - for (MediaSessionMap::iterator it = call->media_session_map_.begin(); - it != call->media_session_map_.end(); ++it) { - // Shouldn't already exist. - ASSERT(media_session_map_.find(it->first) == media_session_map_.end()); - media_session_map_[it->first] = it->second; - - it->second.session->SignalState.connect(this, &Call::OnSessionState); - it->second.session->SignalError.connect(this, &Call::OnSessionError); - it->second.session->SignalReceivedTerminateReason - .connect(this, &Call::OnReceivedTerminateReason); - - EnableSessionChannels(it->second.session, enable); - } - - // Moved all the sessions over, so the other call should no longer have any. - call->media_session_map_.clear(); -} - -void Call::StartConnectionMonitor(Session* session, int cms) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->SignalConnectionMonitor.connect(this, - &Call::OnConnectionMonitor); - voice_channel->StartConnectionMonitor(cms); - } - - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel) { - video_channel->SignalConnectionMonitor.connect(this, - &Call::OnConnectionMonitor); - video_channel->StartConnectionMonitor(cms); - } -} - -void Call::StopConnectionMonitor(Session* session) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->StopConnectionMonitor(); - voice_channel->SignalConnectionMonitor.disconnect(this); - } - - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel) { - video_channel->StopConnectionMonitor(); - video_channel->SignalConnectionMonitor.disconnect(this); - } -} - -void Call::StartAudioMonitor(Session* session, int cms) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor); - voice_channel->StartAudioMonitor(cms); - } -} - -void Call::StopAudioMonitor(Session* session) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->StopAudioMonitor(); - voice_channel->SignalAudioMonitor.disconnect(this); - } -} - -bool Call::IsAudioMonitorRunning(Session* session) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - return voice_channel->IsAudioMonitorRunning(); - } else { - return false; - } -} - -void Call::StartSpeakerMonitor(Session* session) { - if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) { - if (!IsAudioMonitorRunning(session)) { - StartAudioMonitor(session, kAudioMonitorPollPeriodMillis); - } - CurrentSpeakerMonitor* speaker_monitor = - new cricket::CurrentSpeakerMonitor( - audio_source_proxy_.get(), session); - speaker_monitor->SignalUpdate.connect(this, &Call::OnSpeakerMonitor); - speaker_monitor->Start(); - speaker_monitor_map_[session->id()] = speaker_monitor; - } else { - LOG(LS_WARNING) << "Already started speaker monitor for session " - << session->id() << "."; - } -} - -void Call::StopSpeakerMonitor(Session* session) { - if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) { - LOG(LS_WARNING) << "Speaker monitor for session " - << session->id() << " already stopped."; - } else { - CurrentSpeakerMonitor* monitor = speaker_monitor_map_[session->id()]; - monitor->Stop(); - speaker_monitor_map_.erase(session->id()); - delete monitor; - } -} - -void Call::OnConnectionMonitor(VoiceChannel* channel, - const std::vector<ConnectionInfo> &infos) { - SignalConnectionMonitor(this, infos); -} - -void Call::OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info) { - last_voice_media_info_ = info; - SignalMediaMonitor(this, info); -} - -void Call::OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info) { - SignalAudioMonitor(this, info); -} - -void Call::OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc) { - Session* session = static_cast<Session*>(monitor->session()); - MediaStreams* recv_streams = GetMediaStreams(session); - if (recv_streams) { - StreamParams stream; - recv_streams->GetAudioStream(StreamSelector(ssrc), &stream); - SignalSpeakerMonitor(this, session, stream); - } -} - -void Call::OnConnectionMonitor(VideoChannel* channel, - const std::vector<ConnectionInfo> &infos) { - SignalVideoConnectionMonitor(this, infos); -} - -void Call::OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info) { - SignalVideoMediaMonitor(this, info); -} - -void Call::OnDataReceived(DataChannel* channel, - const ReceiveDataParams& params, - const rtc::Buffer& payload) { - SignalDataReceived(this, params, payload); -} - -uint32 Call::id() { - return id_; -} - -void Call::OnSessionState(BaseSession* base_session, BaseSession::State state) { - Session* session = static_cast<Session*>(base_session); - switch (state) { - case Session::STATE_RECEIVEDACCEPT: - UpdateRemoteMediaStreams(session, - session->remote_description()->contents(), false); - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - break; - case Session::STATE_RECEIVEDREJECT: - case Session::STATE_RECEIVEDTERMINATE: - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - break; - default: - break; - } - SignalSessionState(this, session, state); -} - -void Call::OnSessionError(BaseSession* base_session, Session::Error error) { - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - SignalSessionError(this, static_cast<Session*>(base_session), error); -} - -void Call::OnSessionInfoMessage(Session* session, - const buzz::XmlElement* action_elem) { - if (!IsJingleViewRequest(action_elem)) { - return; - } - - ViewRequest view_request; - ParseError error; - if (!ParseJingleViewRequest(action_elem, &view_request, &error)) { - LOG(LS_WARNING) << "Failed to parse view request: " << error.text; - return; - } - - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel == NULL) { - LOG(LS_WARNING) << "Ignore view request since we have no video channel."; - return; - } - - if (!video_channel->ApplyViewRequest(view_request)) { - LOG(LS_WARNING) << "Failed to ApplyViewRequest."; - } -} - -void Call::OnRemoteDescriptionUpdate(BaseSession* base_session, - const ContentInfos& updated_contents) { - Session* session = static_cast<Session*>(base_session); - - const ContentInfo* audio_content = GetFirstAudioContent(updated_contents); - if (audio_content) { - const AudioContentDescription* audio_update = - static_cast<const AudioContentDescription*>(audio_content->description); - if (!audio_update->codecs().empty()) { - UpdateVoiceChannelRemoteContent(session, audio_update); - } - } - - const ContentInfo* video_content = GetFirstVideoContent(updated_contents); - if (video_content) { - const VideoContentDescription* video_update = - static_cast<const VideoContentDescription*>(video_content->description); - if (!video_update->codecs().empty()) { - UpdateVideoChannelRemoteContent(session, video_update); - } - } - - const ContentInfo* data_content = GetFirstDataContent(updated_contents); - if (data_content) { - const DataContentDescription* data_update = - static_cast<const DataContentDescription*>(data_content->description); - if (!data_update->codecs().empty()) { - UpdateDataChannelRemoteContent(session, data_update); - } - } - - UpdateRemoteMediaStreams(session, updated_contents, true); -} - -bool Call::UpdateVoiceChannelRemoteContent( - Session* session, const AudioContentDescription* audio) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (!voice_channel->SetRemoteContent(audio, CA_UPDATE, NULL)) { - const std::string error_desc = - "Failure in audio SetRemoteContent with CA_UPDATE"; - LOG(LS_ERROR) << error_desc; - session->SetError(BaseSession::ERROR_CONTENT, error_desc); - return false; - } - return true; -} - -bool Call::UpdateVideoChannelRemoteContent( - Session* session, const VideoContentDescription* video) { - VideoChannel* video_channel = GetVideoChannel(session); - if (!video_channel->SetRemoteContent(video, CA_UPDATE, NULL)) { - const std::string error_desc = - "Failure in video SetRemoteContent with CA_UPDATE"; - LOG(LS_ERROR) << error_desc; - session->SetError(BaseSession::ERROR_CONTENT, error_desc); - return false; - } - return true; -} - -bool Call::UpdateDataChannelRemoteContent( - Session* session, const DataContentDescription* data) { - DataChannel* data_channel = GetDataChannel(session); - if (!data_channel->SetRemoteContent(data, CA_UPDATE, NULL)) { - const std::string error_desc = - "Failure in data SetRemoteContent with CA_UPDATE"; - LOG(LS_ERROR) << error_desc; - session->SetError(BaseSession::ERROR_CONTENT, error_desc); - return false; - } - return true; -} - -void Call::UpdateRemoteMediaStreams(Session* session, - const ContentInfos& updated_contents, - bool update_channels) { - MediaStreams* recv_streams = GetMediaStreams(session); - if (!recv_streams) - return; - - cricket::MediaStreams added_streams; - cricket::MediaStreams removed_streams; - - const ContentInfo* audio_content = GetFirstAudioContent(updated_contents); - if (audio_content) { - const AudioContentDescription* audio_update = - static_cast<const AudioContentDescription*>(audio_content->description); - UpdateRecvStreams(audio_update->streams(), - update_channels ? GetVoiceChannel(session) : NULL, - recv_streams->mutable_audio(), - added_streams.mutable_audio(), - removed_streams.mutable_audio()); - } - - const ContentInfo* video_content = GetFirstVideoContent(updated_contents); - if (video_content) { - const VideoContentDescription* video_update = - static_cast<const VideoContentDescription*>(video_content->description); - UpdateRecvStreams(video_update->streams(), - update_channels ? GetVideoChannel(session) : NULL, - recv_streams->mutable_video(), - added_streams.mutable_video(), - removed_streams.mutable_video()); - } - - const ContentInfo* data_content = GetFirstDataContent(updated_contents); - if (data_content) { - const DataContentDescription* data_update = - static_cast<const DataContentDescription*>(data_content->description); - UpdateRecvStreams(data_update->streams(), - update_channels ? GetDataChannel(session) : NULL, - recv_streams->mutable_data(), - added_streams.mutable_data(), - removed_streams.mutable_data()); - } - - if (!added_streams.empty() || !removed_streams.empty()) { - SignalMediaStreamsUpdate(this, session, added_streams, removed_streams); - } -} - -void FindStreamChanges(const std::vector<StreamParams>& streams, - const std::vector<StreamParams>& updates, - std::vector<StreamParams>* added_streams, - std::vector<StreamParams>* removed_streams) { - for (std::vector<StreamParams>::const_iterator update = updates.begin(); - update != updates.end(); ++update) { - StreamParams stream; - if (GetStreamByIds(streams, update->groupid, update->id, &stream)) { - if (!update->has_ssrcs()) { - removed_streams->push_back(stream); - } - } else { - // There's a bug on reflector that will send <stream>s even - // though there is not ssrc (which means there isn't really a - // stream). To work around it, we simply ignore new <stream>s - // that don't have any ssrcs. - if (update->has_ssrcs()) { - added_streams->push_back(*update); - } - } - } -} - -void Call::UpdateRecvStreams(const std::vector<StreamParams>& update_streams, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams, - std::vector<StreamParams>* added_streams, - std::vector<StreamParams>* removed_streams) { - FindStreamChanges(*recv_streams, - update_streams, added_streams, removed_streams); - AddRecvStreams(*added_streams, - channel, recv_streams); - RemoveRecvStreams(*removed_streams, - channel, recv_streams); -} - -void Call::AddRecvStreams(const std::vector<StreamParams>& added_streams, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams) { - std::vector<StreamParams>::const_iterator stream; - for (stream = added_streams.begin(); - stream != added_streams.end(); - ++stream) { - AddRecvStream(*stream, channel, recv_streams); - } -} - -void Call::AddRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams) { - if (channel && stream.has_ssrcs()) { - channel->AddRecvStream(stream); - } - recv_streams->push_back(stream); -} - -void Call::RemoveRecvStreams(const std::vector<StreamParams>& removed_streams, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams) { - std::vector<StreamParams>::const_iterator stream; - for (stream = removed_streams.begin(); - stream != removed_streams.end(); - ++stream) { - RemoveRecvStream(*stream, channel, recv_streams); - } -} - -void Call::RemoveRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams) { - if (channel && stream.has_ssrcs()) { - // TODO(pthatcher): Change RemoveRecvStream to take a stream argument. - channel->RemoveRecvStream(stream.first_ssrc()); - } - RemoveStreamByIds(recv_streams, stream.groupid, stream.id); -} - -void Call::OnReceivedTerminateReason(Session* session, - const std::string& reason) { - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - SignalReceivedTerminateReason(this, session, reason); -} - -// TODO(mdodd): Get ride of this method since all Hangouts are using a secure -// connection. -bool Call::secure() const { - if (session_client_->secure() == SEC_DISABLED) { - return false; - } - - bool ret = true; - int i = 0; - - MediaSessionMap::const_iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - LOG_F(LS_VERBOSE) << "session[" << i - << "], check local and remote descriptions"; - i++; - - if (!SessionDescriptionContainsCrypto( - it->second.session->local_description()) || - !SessionDescriptionContainsCrypto( - it->second.session->remote_description())) { - ret = false; - break; - } - } - - LOG_F(LS_VERBOSE) << "secure=" << ret; - return ret; -} - -bool Call::SessionDescriptionContainsCrypto( - const SessionDescription* sdesc) const { - if (sdesc == NULL) { - LOG_F(LS_VERBOSE) << "sessionDescription is NULL"; - return false; - } - - return ContentContainsCrypto(sdesc->GetContentByName(CN_AUDIO)) && - ContentContainsCrypto(sdesc->GetContentByName(CN_VIDEO)); -} - -Session* Call::InternalInitiateSession(const std::string& id, - const buzz::Jid& to, - const std::string& initiator_name, - const CallOptions& options) { - const SessionDescription* offer = session_client_->CreateOffer(options); - - Session* session = session_client_->CreateSession(id, this); - // Only override the initiator_name if it was manually supplied. Otherwise, - // session_client_ will supply the local jid as initiator in CreateOffer. - if (!initiator_name.empty()) { - session->set_initiator_name(initiator_name); - } - - AddSession(session, offer); - session->Initiate(to.Str(), offer); - - // After this timeout, terminate the call because the callee isn't - // answering - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - session_client_->session_manager()->signaling_thread()->PostDelayed( - send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout, - this, MSG_TERMINATECALL); - return session; -} - -AudioSourceProxy* Call::GetAudioSourceProxy() { - return audio_source_proxy_.get(); -} - -} // namespace cricket diff --git a/talk/session/media/call.h b/talk/session/media/call.h deleted file mode 100644 index 6f682b2e81..0000000000 --- a/talk/session/media/call.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * libjingle - * 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: - * - * 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. - */ - -#ifndef TALK_SESSION_MEDIA_CALL_H_ -#define TALK_SESSION_MEDIA_CALL_H_ - -#include <deque> -#include <map> -#include <string> -#include <vector> - -#include "talk/media/base/mediachannel.h" -#include "talk/media/base/screencastid.h" -#include "talk/media/base/streamparams.h" -#include "talk/media/base/videocommon.h" -#include "talk/session/media/audiomonitor.h" -#include "talk/session/media/currentspeakermonitor.h" -#include "talk/session/media/mediamessages.h" -#include "talk/session/media/mediasession.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/p2p/client/socketmonitor.h" - -namespace cricket { - -struct AudioInfo; -class Call; -class MediaSessionClient; -class BaseChannel; -class VoiceChannel; -class VideoChannel; -class DataChannel; - -// Can't typedef this easily since it's forward declared as struct elsewhere. -struct CallOptions : public MediaSessionOptions { -}; - -// CurrentSpeakerMonitor used to have a dependency on Call. To remove this -// dependency, we create AudioSourceContext. CurrentSpeakerMonitor depends on -// AudioSourceContext. -// AudioSourceProxy acts as a proxy so that when SignalAudioMonitor -// in Call is triggered, SignalAudioMonitor in AudioSourceContext is triggered. -// Likewise, when OnMediaStreamsUpdate in Call is triggered, -// OnMediaStreamsUpdate in AudioSourceContext is triggered. -class AudioSourceProxy: public AudioSourceContext, public sigslot::has_slots<> { - public: - explicit AudioSourceProxy(Call* call); - - private: - void OnAudioMonitor(Call* call, const AudioInfo& info); - void OnMediaStreamsUpdate(Call* call, cricket::Session*, - const cricket::MediaStreams&, const cricket::MediaStreams&); - - Call* call_; -}; - -class Call : public rtc::MessageHandler, public sigslot::has_slots<> { - public: - explicit Call(MediaSessionClient* session_client); - ~Call(); - - // |initiator| can be empty. - Session* InitiateSession(const buzz::Jid& to, const buzz::Jid& initiator, - const CallOptions& options); - Session* InitiateSession(const std::string& id, const buzz::Jid& to, - const CallOptions& options); - void AcceptSession(Session* session, const CallOptions& options); - void RejectSession(Session* session); - void TerminateSession(Session* session); - void Terminate(); - bool SendViewRequest(Session* session, - const ViewRequest& view_request); - void SetVideoRenderer(Session* session, uint32 ssrc, - VideoRenderer* renderer); - void StartConnectionMonitor(Session* session, int cms); - void StopConnectionMonitor(Session* session); - void StartAudioMonitor(Session* session, int cms); - void StopAudioMonitor(Session* session); - bool IsAudioMonitorRunning(Session* session); - void StartSpeakerMonitor(Session* session); - void StopSpeakerMonitor(Session* session); - void Mute(bool mute); - void MuteVideo(bool mute); - bool SendData(Session* session, - const SendDataParams& params, - const rtc::Buffer& payload, - SendDataResult* result); - void PressDTMF(int event); - bool StartScreencast(Session* session, - const std::string& stream_name, uint32 ssrc, - const ScreencastId& screenid, int fps); - bool StopScreencast(Session* session, - const std::string& stream_name, uint32 ssrc); - - std::vector<Session*> sessions(); - uint32 id(); - bool has_video() const { return has_video_; } - bool has_data() const { return has_data_; } - bool muted() const { return muted_; } - bool video() const { return has_video_; } - bool secure() const; - bool video_muted() const { return video_muted_; } - const std::vector<StreamParams>* GetDataRecvStreams(Session* session) const { - MediaStreams* recv_streams = GetMediaStreams(session); - return recv_streams ? &recv_streams->data() : NULL; - } - const std::vector<StreamParams>* GetVideoRecvStreams(Session* session) const { - MediaStreams* recv_streams = GetMediaStreams(session); - return recv_streams ? &recv_streams->video() : NULL; - } - const std::vector<StreamParams>* GetAudioRecvStreams(Session* session) const { - MediaStreams* recv_streams = GetMediaStreams(session); - return recv_streams ? &recv_streams->audio() : NULL; - } - VoiceChannel* GetVoiceChannel(Session* session) const; - VideoChannel* GetVideoChannel(Session* session) const; - DataChannel* GetDataChannel(Session* session) const; - // Public just for unit tests - VideoContentDescription* CreateVideoStreamUpdate(const StreamParams& stream); - // Takes ownership of video. - void SendVideoStreamUpdate(Session* session, VideoContentDescription* video); - - // Setting this to false will cause the call to have a longer timeout and - // for the SignalSetupToCallVoicemail to never fire. - void set_send_to_voicemail(bool send_to_voicemail) { - send_to_voicemail_ = send_to_voicemail; - } - bool send_to_voicemail() { return send_to_voicemail_; } - const VoiceMediaInfo& last_voice_media_info() const { - return last_voice_media_info_; - } - - // Sets a flag on the chatapp that will redirect the call to voicemail once - // the call has been terminated - sigslot::signal0<> SignalSetupToCallVoicemail; - sigslot::signal2<Call*, Session*> SignalAddSession; - sigslot::signal2<Call*, Session*> SignalRemoveSession; - sigslot::signal3<Call*, Session*, Session::State> - SignalSessionState; - sigslot::signal3<Call*, Session*, Session::Error> - SignalSessionError; - sigslot::signal3<Call*, Session*, const std::string &> - SignalReceivedTerminateReason; - sigslot::signal2<Call*, const std::vector<ConnectionInfo> &> - SignalConnectionMonitor; - sigslot::signal2<Call*, const VoiceMediaInfo&> SignalMediaMonitor; - sigslot::signal2<Call*, const AudioInfo&> SignalAudioMonitor; - // Empty nick on StreamParams means "unknown". - // No ssrcs in StreamParams means "no current speaker". - sigslot::signal3<Call*, - Session*, - const StreamParams&> SignalSpeakerMonitor; - sigslot::signal2<Call*, const std::vector<ConnectionInfo> &> - SignalVideoConnectionMonitor; - sigslot::signal2<Call*, const VideoMediaInfo&> SignalVideoMediaMonitor; - // Gives added streams and removed streams, in that order. - sigslot::signal4<Call*, - Session*, - const MediaStreams&, - const MediaStreams&> SignalMediaStreamsUpdate; - sigslot::signal3<Call*, - const ReceiveDataParams&, - const rtc::Buffer&> SignalDataReceived; - - AudioSourceProxy* GetAudioSourceProxy(); - - private: - void OnMessage(rtc::Message* message); - void OnSessionState(BaseSession* base_session, BaseSession::State state); - void OnSessionError(BaseSession* base_session, BaseSession::Error error); - void OnSessionInfoMessage( - Session* session, const buzz::XmlElement* action_elem); - void OnViewRequest( - Session* session, const ViewRequest& view_request); - void OnRemoteDescriptionUpdate( - BaseSession* base_session, const ContentInfos& updated_contents); - void OnReceivedTerminateReason(Session* session, const std::string &reason); - void IncomingSession(Session* session, const SessionDescription* offer); - // Returns true on success. - bool AddSession(Session* session, const SessionDescription* offer); - void RemoveSession(Session* session); - void EnableChannels(bool enable); - void EnableSessionChannels(Session* session, bool enable); - void Join(Call* call, bool enable); - void OnConnectionMonitor(VoiceChannel* channel, - const std::vector<ConnectionInfo> &infos); - void OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info); - void OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info); - void OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc); - void OnConnectionMonitor(VideoChannel* channel, - const std::vector<ConnectionInfo> &infos); - void OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info); - void OnDataReceived(DataChannel* channel, - const ReceiveDataParams& params, - const rtc::Buffer& payload); - MediaStreams* GetMediaStreams(Session* session) const; - void UpdateRemoteMediaStreams(Session* session, - const ContentInfos& updated_contents, - bool update_channels); - bool UpdateVoiceChannelRemoteContent(Session* session, - const AudioContentDescription* audio); - bool UpdateVideoChannelRemoteContent(Session* session, - const VideoContentDescription* video); - bool UpdateDataChannelRemoteContent(Session* session, - const DataContentDescription* data); - void UpdateRecvStreams(const std::vector<StreamParams>& update_streams, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams, - std::vector<StreamParams>* added_streams, - std::vector<StreamParams>* removed_streams); - void AddRecvStreams(const std::vector<StreamParams>& added_streams, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams); - void AddRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams); - void RemoveRecvStreams(const std::vector<StreamParams>& removed_streams, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams); - void RemoveRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector<StreamParams>* recv_streams); - void ContinuePlayDTMF(); - bool StopScreencastWithoutSendingUpdate(Session* session, uint32 ssrc); - bool StopAllScreencastsWithoutSendingUpdate(Session* session); - bool SessionDescriptionContainsCrypto(const SessionDescription* sdesc) const; - Session* InternalInitiateSession(const std::string& id, - const buzz::Jid& to, - const std::string& initiator_name, - const CallOptions& options); - - uint32 id_; - MediaSessionClient* session_client_; - - struct StartedCapture { - StartedCapture(cricket::VideoCapturer* capturer, - const cricket::VideoFormat& format) : - capturer(capturer), - format(format) { - } - cricket::VideoCapturer* capturer; - cricket::VideoFormat format; - }; - typedef std::map<uint32, StartedCapture> StartedScreencastMap; - - struct MediaSession { - Session* session; - VoiceChannel* voice_channel; - VideoChannel* video_channel; - DataChannel* data_channel; - MediaStreams* recv_streams; - StartedScreencastMap started_screencasts; - }; - - // Create a map of media sessions, keyed off session->id(). - typedef std::map<std::string, MediaSession> MediaSessionMap; - MediaSessionMap media_session_map_; - - std::map<std::string, CurrentSpeakerMonitor*> speaker_monitor_map_; - bool has_video_; - bool has_data_; - bool muted_; - bool video_muted_; - bool send_to_voicemail_; - - // DTMF tones have to be queued up so that we don't flood the call. We - // keep a deque (doubely ended queue) of them around. While one is playing we - // set the playing_dtmf_ bit and schedule a message in XX msec to clear that - // bit or start the next tone playing. - std::deque<int> queued_dtmf_; - bool playing_dtmf_; - - VoiceMediaInfo last_voice_media_info_; - - rtc::scoped_ptr<AudioSourceProxy> audio_source_proxy_; - - friend class MediaSessionClient; -}; - -} // namespace cricket - -#endif // TALK_SESSION_MEDIA_CALL_H_ diff --git a/talk/session/media/currentspeakermonitor_unittest.cc b/talk/session/media/currentspeakermonitor_unittest.cc index 63676f982e..6a99973f96 100644 --- a/talk/session/media/currentspeakermonitor_unittest.cc +++ b/talk/session/media/currentspeakermonitor_unittest.cc @@ -25,7 +25,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "talk/session/media/call.h" +#include "talk/session/media/audiomonitor.h" #include "talk/session/media/currentspeakermonitor.h" #include "webrtc/base/gunit.h" #include "webrtc/base/thread.h" @@ -42,21 +42,11 @@ static const uint32 kMinTimeBetweenSwitches = 10; // I am assuming system clocks do not have a coarser resolution than 90 ms. static const uint32 kSleepTimeBetweenSwitches = 100; -class MockCall : public Call { - public: - MockCall() : Call(NULL) {} - - void EmitAudioMonitor(const AudioInfo& info) { - GetAudioSourceProxy()->SignalAudioMonitor(GetAudioSourceProxy(), info); - } -}; - class CurrentSpeakerMonitorTest : public testing::Test, public sigslot::has_slots<> { public: CurrentSpeakerMonitorTest() { - call_ = new MockCall(); - monitor_ = new CurrentSpeakerMonitor(call_->GetAudioSourceProxy(), NULL); + monitor_ = new CurrentSpeakerMonitor(&source_, NULL); // Shrink the minimum time betweeen switches to 10 ms so we don't have to // slow down our tests. monitor_->set_min_time_between_switches(kMinTimeBetweenSwitches); @@ -68,11 +58,14 @@ class CurrentSpeakerMonitorTest : public testing::Test, ~CurrentSpeakerMonitorTest() { delete monitor_; - delete call_; + } + + void SignalAudioMonitor(const AudioInfo& info) { + source_.SignalAudioMonitor(&source_, info); } protected: - MockCall* call_; + AudioSourceContext source_; CurrentSpeakerMonitor* monitor_; int num_changes_; uint32 current_speaker_; @@ -91,7 +84,7 @@ static void InitAudioInfo(AudioInfo* info, int input_level, int output_level) { TEST_F(CurrentSpeakerMonitorTest, NoActiveStreams) { AudioInfo info; InitAudioInfo(&info, 0, 0); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, 0U); EXPECT_EQ(num_changes_, 0); @@ -103,7 +96,7 @@ TEST_F(CurrentSpeakerMonitorTest, MultipleActiveStreams) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); // No speaker recognized because the initial sample is treated as possibly // just noise and disregarded. @@ -112,7 +105,7 @@ TEST_F(CurrentSpeakerMonitorTest, MultipleActiveStreams) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, kSsrc2); EXPECT_EQ(num_changes_, 1); @@ -125,21 +118,21 @@ TEST_F(CurrentSpeakerMonitorTest, DISABLED_RapidSpeakerChange) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, 0U); EXPECT_EQ(num_changes_, 0); info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, kSsrc2); EXPECT_EQ(num_changes_, 1); info.active_streams.push_back(std::make_pair(kSsrc1, 9)); info.active_streams.push_back(std::make_pair(kSsrc2, 1)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); // We expect no speaker change because of the rapid change. EXPECT_EQ(current_speaker_, kSsrc2); @@ -152,14 +145,14 @@ TEST_F(CurrentSpeakerMonitorTest, SpeakerChange) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, 0U); EXPECT_EQ(num_changes_, 0); info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, kSsrc2); EXPECT_EQ(num_changes_, 1); @@ -169,7 +162,7 @@ TEST_F(CurrentSpeakerMonitorTest, SpeakerChange) { info.active_streams.push_back(std::make_pair(kSsrc1, 9)); info.active_streams.push_back(std::make_pair(kSsrc2, 1)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, kSsrc1); EXPECT_EQ(num_changes_, 2); @@ -181,21 +174,21 @@ TEST_F(CurrentSpeakerMonitorTest, InterwordSilence) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, 0U); EXPECT_EQ(num_changes_, 0); info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, kSsrc2); EXPECT_EQ(num_changes_, 1); info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 7)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); EXPECT_EQ(current_speaker_, kSsrc2); EXPECT_EQ(num_changes_, 1); @@ -205,7 +198,7 @@ TEST_F(CurrentSpeakerMonitorTest, InterwordSilence) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 0)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); // Current speaker shouldn't have changed because we treat this as an inter- // word silence. @@ -214,7 +207,7 @@ TEST_F(CurrentSpeakerMonitorTest, InterwordSilence) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 0)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); // Current speaker shouldn't have changed because we treat this as an inter- // word silence. @@ -223,7 +216,7 @@ TEST_F(CurrentSpeakerMonitorTest, InterwordSilence) { info.active_streams.push_back(std::make_pair(kSsrc1, 3)); info.active_streams.push_back(std::make_pair(kSsrc2, 0)); - call_->EmitAudioMonitor(info); + SignalAudioMonitor(info); // At this point, we should have concluded that SSRC2 stopped speaking. EXPECT_EQ(current_speaker_, kSsrc1); diff --git a/talk/session/media/mediamessages.cc b/talk/session/media/mediamessages.cc deleted file mode 100644 index 455a8d84fa..0000000000 --- a/talk/session/media/mediamessages.cc +++ /dev/null @@ -1,333 +0,0 @@ -/* - * libjingle - * Copyright 2010 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. - */ - -/* - * Documentation is in mediamessages.h. - */ - -#include "talk/session/media/mediamessages.h" - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/parsing.h" -#include "talk/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/stringencode.h" - -namespace cricket { - -namespace { - -bool ParseSsrc(const std::string& string, uint32* ssrc) { - return rtc::FromString(string, ssrc); -} - -// Builds a <view> element according to the following spec: -// goto/jinglemuc -buzz::XmlElement* CreateViewElem(const std::string& name, - const std::string& type) { - buzz::XmlElement* view_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_VIEW, true); - view_elem->AddAttr(QN_NAME, name); - view_elem->SetAttr(QN_TYPE, type); - return view_elem; -} - -buzz::XmlElement* CreateVideoViewElem(const std::string& content_name, - const std::string& type) { - return CreateViewElem(content_name, type); -} - -buzz::XmlElement* CreateNoneVideoViewElem(const std::string& content_name) { - return CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_NONE); -} - -buzz::XmlElement* CreateStaticVideoViewElem(const std::string& content_name, - const StaticVideoView& view) { - buzz::XmlElement* view_elem = - CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_STATIC); - AddXmlAttr(view_elem, QN_SSRC, view.selector.ssrc); - - buzz::XmlElement* params_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_PARAMS); - AddXmlAttr(params_elem, QN_WIDTH, view.width); - AddXmlAttr(params_elem, QN_HEIGHT, view.height); - AddXmlAttr(params_elem, QN_FRAMERATE, view.framerate); - AddXmlAttr(params_elem, QN_PREFERENCE, view.preference); - view_elem->AddElement(params_elem); - - return view_elem; -} - -} // namespace - -bool IsJingleViewRequest(const buzz::XmlElement* action_elem) { - return action_elem->FirstNamed(QN_JINGLE_DRAFT_VIEW) != NULL; -} - -bool ParseStaticVideoView(const buzz::XmlElement* view_elem, - StaticVideoView* view, - ParseError* error) { - uint32 ssrc; - if (!ParseSsrc(view_elem->Attr(QN_SSRC), &ssrc)) { - return BadParse("Invalid or missing view ssrc.", error); - } - view->selector = StreamSelector(ssrc); - - const buzz::XmlElement* params_elem = - view_elem->FirstNamed(QN_JINGLE_DRAFT_PARAMS); - if (params_elem) { - view->width = GetXmlAttr(params_elem, QN_WIDTH, 0); - view->height = GetXmlAttr(params_elem, QN_HEIGHT, 0); - view->framerate = GetXmlAttr(params_elem, QN_FRAMERATE, 0); - view->preference = GetXmlAttr(params_elem, QN_PREFERENCE, 0); - } else { - return BadParse("Missing view params.", error); - } - - return true; -} - -bool ParseJingleViewRequest(const buzz::XmlElement* action_elem, - ViewRequest* view_request, - ParseError* error) { - for (const buzz::XmlElement* view_elem = - action_elem->FirstNamed(QN_JINGLE_DRAFT_VIEW); - view_elem != NULL; - view_elem = view_elem->NextNamed(QN_JINGLE_DRAFT_VIEW)) { - std::string type = view_elem->Attr(QN_TYPE); - if (STR_JINGLE_DRAFT_VIEW_TYPE_NONE == type) { - view_request->static_video_views.clear(); - return true; - } else if (STR_JINGLE_DRAFT_VIEW_TYPE_STATIC == type) { - StaticVideoView static_video_view(StreamSelector(0), 0, 0, 0); - if (!ParseStaticVideoView(view_elem, &static_video_view, error)) { - return false; - } - view_request->static_video_views.push_back(static_video_view); - } else { - LOG(LS_INFO) << "Ingnoring unknown view type: " << type; - } - } - return true; -} - -bool WriteJingleViewRequest(const std::string& content_name, - const ViewRequest& request, - XmlElements* elems, - WriteError* error) { - if (request.static_video_views.empty()) { - elems->push_back(CreateNoneVideoViewElem(content_name)); - } else { - for (StaticVideoViews::const_iterator view = - request.static_video_views.begin(); - view != request.static_video_views.end(); ++view) { - elems->push_back(CreateStaticVideoViewElem(content_name, *view)); - } - } - return true; -} - -bool ParseSsrcAsLegacyStream(const buzz::XmlElement* desc_elem, - std::vector<StreamParams>* streams, - ParseError* error) { - const std::string ssrc_str = desc_elem->Attr(QN_SSRC); - if (!ssrc_str.empty()) { - uint32 ssrc; - if (!ParseSsrc(ssrc_str, &ssrc)) { - return BadParse("Missing or invalid ssrc.", error); - } - - streams->push_back(StreamParams::CreateLegacy(ssrc)); - } - return true; -} - -bool ParseSsrcs(const buzz::XmlElement* parent_elem, - std::vector<uint32>* ssrcs, - ParseError* error) { - for (const buzz::XmlElement* ssrc_elem = - parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC); - ssrc_elem != NULL; - ssrc_elem = ssrc_elem->NextNamed(QN_JINGLE_DRAFT_SSRC)) { - uint32 ssrc; - if (!ParseSsrc(ssrc_elem->BodyText(), &ssrc)) { - return BadParse("Missing or invalid ssrc.", error); - } - - ssrcs->push_back(ssrc); - } - return true; -} - -bool ParseSsrcGroups(const buzz::XmlElement* parent_elem, - std::vector<SsrcGroup>* ssrc_groups, - ParseError* error) { - for (const buzz::XmlElement* group_elem = - parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC_GROUP); - group_elem != NULL; - group_elem = group_elem->NextNamed(QN_JINGLE_DRAFT_SSRC_GROUP)) { - std::string semantics = group_elem->Attr(QN_SEMANTICS); - std::vector<uint32> ssrcs; - if (!ParseSsrcs(group_elem, &ssrcs, error)) { - return false; - } - ssrc_groups->push_back(SsrcGroup(semantics, ssrcs)); - } - return true; -} - -bool ParseJingleStream(const buzz::XmlElement* stream_elem, - std::vector<StreamParams>* streams, - ParseError* error) { - StreamParams stream; - // We treat the nick as a stream groupid. - stream.groupid = stream_elem->Attr(QN_NICK); - stream.id = stream_elem->Attr(QN_NAME); - stream.type = stream_elem->Attr(QN_TYPE); - stream.display = stream_elem->Attr(QN_DISPLAY); - stream.cname = stream_elem->Attr(QN_CNAME); - if (!ParseSsrcs(stream_elem, &(stream.ssrcs), error)) { - return false; - } - std::vector<SsrcGroup> ssrc_groups; - if (!ParseSsrcGroups(stream_elem, &(stream.ssrc_groups), error)) { - return false; - } - streams->push_back(stream); - return true; -} - -bool ParseJingleRtpHeaderExtensions(const buzz::XmlElement* parent_elem, - std::vector<RtpHeaderExtension>* hdrexts, - ParseError* error) { - for (const buzz::XmlElement* hdrext_elem = - parent_elem->FirstNamed(QN_JINGLE_RTP_HDREXT); - hdrext_elem != NULL; - hdrext_elem = hdrext_elem->NextNamed(QN_JINGLE_RTP_HDREXT)) { - std::string uri = hdrext_elem->Attr(QN_URI); - int id = GetXmlAttr(hdrext_elem, QN_ID, 0); - if (id <= 0) { - return BadParse("Invalid RTP header extension id.", error); - } - hdrexts->push_back(RtpHeaderExtension(uri, id)); - } - return true; -} - -bool HasJingleStreams(const buzz::XmlElement* desc_elem) { - const buzz::XmlElement* streams_elem = - desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS); - return (streams_elem != NULL); -} - -bool ParseJingleStreams(const buzz::XmlElement* desc_elem, - std::vector<StreamParams>* streams, - ParseError* error) { - const buzz::XmlElement* streams_elem = - desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS); - if (streams_elem == NULL) { - return BadParse("Missing streams element.", error); - } - for (const buzz::XmlElement* stream_elem = - streams_elem->FirstNamed(QN_JINGLE_DRAFT_STREAM); - stream_elem != NULL; - stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_STREAM)) { - if (!ParseJingleStream(stream_elem, streams, error)) { - return false; - } - } - return true; -} - -void WriteSsrcs(const std::vector<uint32>& ssrcs, - buzz::XmlElement* parent_elem) { - for (std::vector<uint32>::const_iterator ssrc = ssrcs.begin(); - ssrc != ssrcs.end(); ++ssrc) { - buzz::XmlElement* ssrc_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC, false); - SetXmlBody(ssrc_elem, *ssrc); - - parent_elem->AddElement(ssrc_elem); - } -} - -void WriteSsrcGroups(const std::vector<SsrcGroup>& groups, - buzz::XmlElement* parent_elem) { - for (std::vector<SsrcGroup>::const_iterator group = groups.begin(); - group != groups.end(); ++group) { - buzz::XmlElement* group_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC_GROUP, false); - AddXmlAttrIfNonEmpty(group_elem, QN_SEMANTICS, group->semantics); - WriteSsrcs(group->ssrcs, group_elem); - - parent_elem->AddElement(group_elem); - } -} - -void WriteJingleStream(const StreamParams& stream, - buzz::XmlElement* parent_elem) { - buzz::XmlElement* stream_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_STREAM, false); - // We treat the nick as a stream groupid. - AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream.groupid); - AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream.id); - AddXmlAttrIfNonEmpty(stream_elem, QN_TYPE, stream.type); - AddXmlAttrIfNonEmpty(stream_elem, QN_DISPLAY, stream.display); - AddXmlAttrIfNonEmpty(stream_elem, QN_CNAME, stream.cname); - WriteSsrcs(stream.ssrcs, stream_elem); - WriteSsrcGroups(stream.ssrc_groups, stream_elem); - - parent_elem->AddElement(stream_elem); -} - -void WriteJingleStreams(const std::vector<StreamParams>& streams, - buzz::XmlElement* parent_elem) { - buzz::XmlElement* streams_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_STREAMS, true); - for (std::vector<StreamParams>::const_iterator stream = streams.begin(); - stream != streams.end(); ++stream) { - WriteJingleStream(*stream, streams_elem); - } - - parent_elem->AddElement(streams_elem); -} - -void WriteJingleRtpHeaderExtensions( - const std::vector<RtpHeaderExtension>& hdrexts, - buzz::XmlElement* parent_elem) { - for (std::vector<RtpHeaderExtension>::const_iterator hdrext = hdrexts.begin(); - hdrext != hdrexts.end(); ++hdrext) { - buzz::XmlElement* hdrext_elem = - new buzz::XmlElement(QN_JINGLE_RTP_HDREXT, false); - AddXmlAttr(hdrext_elem, QN_URI, hdrext->uri); - AddXmlAttr(hdrext_elem, QN_ID, hdrext->id); - parent_elem->AddElement(hdrext_elem); - } -} - - -} // namespace cricket diff --git a/talk/session/media/mediamessages.h b/talk/session/media/mediamessages.h deleted file mode 100644 index e64eaef4fc..0000000000 --- a/talk/session/media/mediamessages.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * libjingle - * Copyright 2010 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. - */ - -/* - * A collection of functions and types for serializing and - * deserializing Jingle session messages related to media. - * Specificially, the <notify> and <view> messages. They are not yet - * standardized, but their current documentation can be found at: - * goto/jinglemuc - */ - -#ifndef TALK_SESSION_MEDIA_MEDIAMESSAGES_H_ -#define TALK_SESSION_MEDIA_MEDIAMESSAGES_H_ - -#include <string> -#include <vector> - -#include "talk/media/base/mediachannel.h" // For RtpHeaderExtension -#include "talk/media/base/streamparams.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/sessiondescription.h" -#include "webrtc/base/basictypes.h" - -namespace cricket { - -// If the parent element (usually <jingle>) is a jingle view. -bool IsJingleViewRequest(const buzz::XmlElement* action_elem); - -// Parses a view request from the parent element (usually -// <jingle>). If it fails, it returns false and fills an error -// message. -bool ParseJingleViewRequest(const buzz::XmlElement* action_elem, - ViewRequest* view_request, - ParseError* error); - -// Serializes a view request to XML. If it fails, returns false and -// fills in an error message. -bool WriteJingleViewRequest(const std::string& content_name, - const ViewRequest& view, - XmlElements* elems, - WriteError* error); - -// TODO(pthatcher): Get rid of legacy source notify and replace with -// description-info as soon as reflector is capable of sending it. -bool IsSourcesNotify(const buzz::XmlElement* action_elem); - -// If the given elem has <streams>. -bool HasJingleStreams(const buzz::XmlElement* desc_elem); - -// Parses streams from a jingle <description>. If it fails, returns -// false and fills an error message. -bool ParseJingleStreams(const buzz::XmlElement* desc_elem, - std::vector<StreamParams>* streams, - ParseError* error); - -// Write a <streams> element to the parent_elem. -void WriteJingleStreams(const std::vector<StreamParams>& streams, - buzz::XmlElement* parent_elem); - -// Parses rtp header extensions from a jingle <description>. If it -// fails, returns false and fills an error message. -bool ParseJingleRtpHeaderExtensions( - const buzz::XmlElement* desc_elem, - std::vector<RtpHeaderExtension>* hdrexts, - ParseError* error); - -// Writes <rtp-hdrext> elements to the parent_elem. -void WriteJingleRtpHeaderExtensions( - const std::vector<RtpHeaderExtension>& hdrexts, - buzz::XmlElement* parent_elem); - -} // namespace cricket - -#endif // TALK_SESSION_MEDIA_MEDIAMESSAGES_H_ diff --git a/talk/session/media/mediamessages_unittest.cc b/talk/session/media/mediamessages_unittest.cc deleted file mode 100644 index a9f00e47d9..0000000000 --- a/talk/session/media/mediamessages_unittest.cc +++ /dev/null @@ -1,363 +0,0 @@ -/* - * libjingle - * 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: - * - * 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/media/mediamessages.h" - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/constants.h" -#include "talk/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/scoped_ptr.h" - -// Unit tests for mediamessages.cc. - -namespace cricket { - -namespace { - -static const char kViewVideoNoneXml[] = - "<view xmlns='google:jingle'" - " name='video1'" - " type='none'" - "/>"; - -class MediaMessagesTest : public testing::Test { - public: - // CreateMediaSessionDescription uses a static variable cricket::NS_JINGLE_RTP - // defined in another file and cannot be used to initialize another static - // variable (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14) - MediaMessagesTest() - : remote_description_(CreateMediaSessionDescription("audio1", "video1")) { - } - - protected: - static std::string ViewVideoStaticVgaXml(const std::string& ssrc) { - return "<view xmlns='google:jingle'" - " name='video1'" - " type='static'" - " ssrc='" + ssrc + "'" - ">" - "<params" - " width='640'" - " height='480'" - " framerate='30'" - " preference='0'" - " />" - "</view>"; - } - - static cricket::StreamParams CreateStream(const std::string& nick, - const std::string& name, - uint32 ssrc1, - uint32 ssrc2, - const std::string& semantics, - const std::string& type, - const std::string& display) { - StreamParams stream; - stream.groupid = nick; - stream.id = name; - stream.ssrcs.push_back(ssrc1); - stream.ssrcs.push_back(ssrc2); - stream.ssrc_groups.push_back( - cricket::SsrcGroup(semantics, stream.ssrcs)); - stream.type = type; - stream.display = display; - return stream; - } - - static std::string StreamsXml(const std::string& stream1, - const std::string& stream2) { - return "<streams xmlns='google:jingle'>" - + stream1 - + stream2 + - "</streams>"; - } - - - static std::string StreamXml(const std::string& nick, - const std::string& name, - const std::string& ssrc1, - const std::string& ssrc2, - const std::string& semantics, - const std::string& type, - const std::string& display) { - return "<stream" - " nick='" + nick + "'" - " name='" + name + "'" - " type='" + type + "'" - " display='" + display + "'" - ">" - "<ssrc>" + ssrc1 + "</ssrc>" - "<ssrc>" + ssrc2 + "</ssrc>" - "<ssrc-group" - " semantics='" + semantics + "'" - ">" - "<ssrc>" + ssrc1 + "</ssrc>" - "<ssrc>" + ssrc2 + "</ssrc>" - "</ssrc-group>" - "</stream>"; - } - - static std::string HeaderExtensionsXml(const std::string& hdrext1, - const std::string& hdrext2) { - return "<rtp:description xmlns:rtp=\"urn:xmpp:jingle:apps:rtp:1\">" - + hdrext1 - + hdrext2 + - "</rtp:description>"; - } - - static std::string HeaderExtensionXml(const std::string& uri, - const std::string& id) { - return "<rtp:rtp-hdrext" - " uri='" + uri + "'" - " id='" + id + "'" - "/>"; - } - - static cricket::SessionDescription* CreateMediaSessionDescription( - const std::string& audio_content_name, - const std::string& video_content_name) { - cricket::SessionDescription* desc = new cricket::SessionDescription(); - desc->AddContent(audio_content_name, cricket::NS_JINGLE_RTP, - new cricket::AudioContentDescription()); - desc->AddContent(video_content_name, cricket::NS_JINGLE_RTP, - new cricket::VideoContentDescription()); - return desc; - } - - size_t ClearXmlElements(cricket::XmlElements* elements) { - size_t size = elements->size(); - for (size_t i = 0; i < size; i++) { - delete elements->at(i); - } - elements->clear(); - return size; - } - - rtc::scoped_ptr<cricket::SessionDescription> remote_description_; -}; - -} // anonymous namespace - -// Test serializing/deserializing an empty <view> message. -TEST_F(MediaMessagesTest, ViewNoneToFromXml) { - buzz::XmlElement* expected_view_elem = - buzz::XmlElement::ForStr(kViewVideoNoneXml); - rtc::scoped_ptr<buzz::XmlElement> action_elem( - new buzz::XmlElement(QN_JINGLE)); - - EXPECT_FALSE(cricket::IsJingleViewRequest(action_elem.get())); - action_elem->AddElement(expected_view_elem); - EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get())); - - cricket::ViewRequest view_request; - cricket::XmlElements actual_view_elems; - cricket::WriteError error; - - ASSERT_TRUE(cricket::WriteJingleViewRequest( - "video1", view_request, &actual_view_elems, &error)); - - ASSERT_EQ(1U, actual_view_elems.size()); - EXPECT_EQ(expected_view_elem->Str(), actual_view_elems[0]->Str()); - ClearXmlElements(&actual_view_elems); - - cricket::ParseError parse_error; - EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get())); - ASSERT_TRUE(cricket::ParseJingleViewRequest( - action_elem.get(), &view_request, &parse_error)); - EXPECT_EQ(0U, view_request.static_video_views.size()); -} - -// Test serializing/deserializing an a simple vga <view> message. -TEST_F(MediaMessagesTest, ViewVgaToFromXml) { - rtc::scoped_ptr<buzz::XmlElement> action_elem( - new buzz::XmlElement(QN_JINGLE)); - buzz::XmlElement* expected_view_elem1 = - buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("1234")); - buzz::XmlElement* expected_view_elem2 = - buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("2468")); - action_elem->AddElement(expected_view_elem1); - action_elem->AddElement(expected_view_elem2); - - cricket::ViewRequest view_request; - cricket::XmlElements actual_view_elems; - cricket::WriteError error; - - view_request.static_video_views.push_back(cricket::StaticVideoView( - cricket::StreamSelector(1234), 640, 480, 30)); - view_request.static_video_views.push_back(cricket::StaticVideoView( - cricket::StreamSelector(2468), 640, 480, 30)); - - ASSERT_TRUE(cricket::WriteJingleViewRequest( - "video1", view_request, &actual_view_elems, &error)); - - ASSERT_EQ(2U, actual_view_elems.size()); - EXPECT_EQ(expected_view_elem1->Str(), actual_view_elems[0]->Str()); - EXPECT_EQ(expected_view_elem2->Str(), actual_view_elems[1]->Str()); - ClearXmlElements(&actual_view_elems); - - view_request.static_video_views.clear(); - cricket::ParseError parse_error; - EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get())); - ASSERT_TRUE(cricket::ParseJingleViewRequest( - action_elem.get(), &view_request, &parse_error)); - EXPECT_EQ(2U, view_request.static_video_views.size()); - EXPECT_EQ(1234U, view_request.static_video_views[0].selector.ssrc); - EXPECT_EQ(640, view_request.static_video_views[0].width); - EXPECT_EQ(480, view_request.static_video_views[0].height); - EXPECT_EQ(30, view_request.static_video_views[0].framerate); - EXPECT_EQ(2468U, view_request.static_video_views[1].selector.ssrc); -} - -// Test deserializing bad view XML. -TEST_F(MediaMessagesTest, ParseBadViewXml) { - rtc::scoped_ptr<buzz::XmlElement> action_elem( - new buzz::XmlElement(QN_JINGLE)); - buzz::XmlElement* view_elem = - buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("not-an-ssrc")); - action_elem->AddElement(view_elem); - - cricket::ViewRequest view_request; - cricket::ParseError parse_error; - ASSERT_FALSE(cricket::ParseJingleViewRequest( - action_elem.get(), &view_request, &parse_error)); -} - - -// Test serializing/deserializing typical streams xml. -TEST_F(MediaMessagesTest, StreamsToFromXml) { - rtc::scoped_ptr<buzz::XmlElement> expected_streams_elem( - buzz::XmlElement::ForStr( - StreamsXml( - StreamXml("nick1", "stream1", "101", "102", - "semantics1", "type1", "display1"), - StreamXml("nick2", "stream2", "201", "202", - "semantics2", "type2", "display2")))); - - std::vector<cricket::StreamParams> expected_streams; - expected_streams.push_back(CreateStream("nick1", "stream1", 101U, 102U, - "semantics1", "type1", "display1")); - expected_streams.push_back(CreateStream("nick2", "stream2", 201U, 202U, - "semantics2", "type2", "display2")); - - rtc::scoped_ptr<buzz::XmlElement> actual_desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - cricket::WriteJingleStreams(expected_streams, actual_desc_elem.get()); - - const buzz::XmlElement* actual_streams_elem = - actual_desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS); - ASSERT_TRUE(actual_streams_elem != NULL); - EXPECT_EQ(expected_streams_elem->Str(), actual_streams_elem->Str()); - - rtc::scoped_ptr<buzz::XmlElement> expected_desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - expected_desc_elem->AddElement(new buzz::XmlElement( - *expected_streams_elem)); - std::vector<cricket::StreamParams> actual_streams; - cricket::ParseError parse_error; - - EXPECT_TRUE(cricket::HasJingleStreams(expected_desc_elem.get())); - ASSERT_TRUE(cricket::ParseJingleStreams( - expected_desc_elem.get(), &actual_streams, &parse_error)); - EXPECT_EQ(2U, actual_streams.size()); - EXPECT_EQ(expected_streams[0], actual_streams[0]); - EXPECT_EQ(expected_streams[1], actual_streams[1]); -} - -// Test deserializing bad streams xml. -TEST_F(MediaMessagesTest, StreamsFromBadXml) { - rtc::scoped_ptr<buzz::XmlElement> streams_elem( - buzz::XmlElement::ForStr( - StreamsXml( - StreamXml("nick1", "name1", "101", "not-an-ssrc", - "semantics1", "type1", "display1"), - StreamXml("nick2", "name2", "202", "not-an-ssrc", - "semantics2", "type2", "display2")))); - rtc::scoped_ptr<buzz::XmlElement> desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - desc_elem->AddElement(new buzz::XmlElement(*streams_elem)); - - std::vector<cricket::StreamParams> actual_streams; - cricket::ParseError parse_error; - ASSERT_FALSE(cricket::ParseJingleStreams( - desc_elem.get(), &actual_streams, &parse_error)); -} - -// Test serializing/deserializing typical RTP Header Extension xml. -TEST_F(MediaMessagesTest, HeaderExtensionsToFromXml) { - rtc::scoped_ptr<buzz::XmlElement> expected_desc_elem( - buzz::XmlElement::ForStr( - HeaderExtensionsXml( - HeaderExtensionXml("abc", "123"), - HeaderExtensionXml("def", "456")))); - - std::vector<cricket::RtpHeaderExtension> expected_hdrexts; - expected_hdrexts.push_back(RtpHeaderExtension("abc", 123)); - expected_hdrexts.push_back(RtpHeaderExtension("def", 456)); - - rtc::scoped_ptr<buzz::XmlElement> actual_desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - cricket::WriteJingleRtpHeaderExtensions(expected_hdrexts, actual_desc_elem.get()); - - ASSERT_TRUE(actual_desc_elem != NULL); - EXPECT_EQ(expected_desc_elem->Str(), actual_desc_elem->Str()); - - std::vector<cricket::RtpHeaderExtension> actual_hdrexts; - cricket::ParseError parse_error; - ASSERT_TRUE(cricket::ParseJingleRtpHeaderExtensions( - expected_desc_elem.get(), &actual_hdrexts, &parse_error)); - EXPECT_EQ(2U, actual_hdrexts.size()); - EXPECT_EQ(expected_hdrexts[0], actual_hdrexts[0]); - EXPECT_EQ(expected_hdrexts[1], actual_hdrexts[1]); -} - -// Test deserializing bad RTP header extension xml. -TEST_F(MediaMessagesTest, HeaderExtensionsFromBadXml) { - std::vector<cricket::RtpHeaderExtension> actual_hdrexts; - cricket::ParseError parse_error; - - rtc::scoped_ptr<buzz::XmlElement> desc_elem( - buzz::XmlElement::ForStr( - HeaderExtensionsXml( - HeaderExtensionXml("abc", "123"), - HeaderExtensionXml("def", "not-an-id")))); - ASSERT_FALSE(cricket::ParseJingleRtpHeaderExtensions( - desc_elem.get(), &actual_hdrexts, &parse_error)); - - desc_elem.reset( - buzz::XmlElement::ForStr( - HeaderExtensionsXml( - HeaderExtensionXml("abc", "123"), - HeaderExtensionXml("def", "-1")))); - ASSERT_FALSE(cricket::ParseJingleRtpHeaderExtensions( - desc_elem.get(), &actual_hdrexts, &parse_error)); -} - -} // namespace cricket diff --git a/talk/session/media/mediasessionclient.cc b/talk/session/media/mediasessionclient.cc deleted file mode 100644 index 5cb79175d8..0000000000 --- a/talk/session/media/mediasessionclient.cc +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * libjingle - * 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: - * - * 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 <string> - -#include "talk/session/media/mediasessionclient.h" - -#include "talk/media/base/capturemanager.h" -#include "talk/media/base/cryptoparams.h" -#include "talk/media/sctp/sctpdataengine.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/parsing.h" -#include "talk/session/media/mediamessages.h" -#include "talk/session/media/srtpfilter.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlconstants.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/stringutils.h" - -namespace cricket { - -#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) -MediaSessionClient::MediaSessionClient( - const buzz::Jid& jid, SessionManager *manager) - : jid_(jid), - session_manager_(manager), - focus_call_(NULL), - channel_manager_(new ChannelManager(session_manager_->worker_thread())), - desc_factory_(channel_manager_, - session_manager_->transport_desc_factory()), - multisession_enabled_(false) { - Construct(); -} -#endif - -MediaSessionClient::MediaSessionClient( - const buzz::Jid& jid, SessionManager *manager, - MediaEngineInterface* media_engine, - DataEngineInterface* data_media_engine, - DeviceManagerInterface* device_manager) - : jid_(jid), - session_manager_(manager), - focus_call_(NULL), - channel_manager_(new ChannelManager( - media_engine, data_media_engine, - device_manager, new CaptureManager(), - session_manager_->worker_thread())), - desc_factory_(channel_manager_, - session_manager_->transport_desc_factory()), - multisession_enabled_(false) { - Construct(); -} - -void MediaSessionClient::Construct() { - // Register ourselves as the handler of audio and video sessions. - session_manager_->AddClient(NS_JINGLE_RTP, this); - // Forward device notifications. - SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange); - // Bring up the channel manager. - // In previous versions of ChannelManager, this was done automatically - // in the constructor. - channel_manager_->Init(); -} - -MediaSessionClient::~MediaSessionClient() { - // Destroy all calls - std::map<uint32, Call *>::iterator it; - while (calls_.begin() != calls_.end()) { - std::map<uint32, Call *>::iterator it = calls_.begin(); - DestroyCall((*it).second); - } - - // Delete channel manager. This will wait for the channels to exit - delete channel_manager_; - - // Remove ourselves from the client map. - session_manager_->RemoveClient(NS_JINGLE_RTP); -} - -Call *MediaSessionClient::CreateCall() { - Call *call = new Call(this); - calls_[call->id()] = call; - SignalCallCreate(call); - return call; -} - -void MediaSessionClient::OnSessionCreate(Session *session, - bool received_initiate) { - if (received_initiate) { - session->SignalState.connect(this, &MediaSessionClient::OnSessionState); - } -} - -void MediaSessionClient::OnSessionState(BaseSession* base_session, - BaseSession::State state) { - // MediaSessionClient can only be used with a Session*, so it's - // safe to cast here. - Session* session = static_cast<Session*>(base_session); - - if (state == Session::STATE_RECEIVEDINITIATE) { - // The creation of the call must happen after the session has - // processed the initiate message because we need the - // remote_description to know what content names to use in the - // call. - - // If our accept would have no codecs, then we must reject this call. - const SessionDescription* offer = session->remote_description(); - const SessionDescription* accept = CreateAnswer(offer, CallOptions()); - const ContentInfo* audio_content = GetFirstAudioContent(accept); - bool audio_rejected = (!audio_content) ? true : audio_content->rejected; - const AudioContentDescription* audio_desc = (!audio_content) ? NULL : - static_cast<const AudioContentDescription*>(audio_content->description); - - // For some reason, we need a call even if we reject. So, either find a - // matching call or create a new one. - // The matching of existing calls is used to support the multi-session mode - // required for p2p handoffs: ie. once a MUC call is established, a new - // session may be established for the same call but is direct between the - // clients. To indicate that this is the case, the initiator of the incoming - // session is set to be the same as the remote name of the MUC for the - // existing session, thus the client can know that this is a new session for - // the existing call, rather than a whole new call. - Call* call = NULL; - if (multisession_enabled_) { - call = FindCallByRemoteName(session->initiator_name()); - } - - if (call == NULL) { - // Could not find a matching call, so create a new one. - call = CreateCall(); - } - - session_map_[session->id()] = call; - call->IncomingSession(session, offer); - - if (audio_rejected || !audio_desc || audio_desc->codecs().size() == 0) { - session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS); - } - delete accept; - } -} - -void MediaSessionClient::DestroyCall(Call *call) { - // Change focus away, signal destruction - - if (call == focus_call_) - SetFocus(NULL); - SignalCallDestroy(call); - - // Remove it from calls_ map and delete - - std::map<uint32, Call *>::iterator it = calls_.find(call->id()); - if (it != calls_.end()) - calls_.erase(it); - - delete call; -} - -void MediaSessionClient::OnSessionDestroy(Session *session) { - // Find the call this session is in, remove it - SessionMap::iterator it = session_map_.find(session->id()); - ASSERT(it != session_map_.end()); - if (it != session_map_.end()) { - Call *call = (*it).second; - session_map_.erase(it); - call->RemoveSession(session); - } -} - -Call *MediaSessionClient::GetFocus() { - return focus_call_; -} - -void MediaSessionClient::SetFocus(Call *call) { - Call *old_focus_call = focus_call_; - if (focus_call_ != call) { - if (focus_call_ != NULL) - focus_call_->EnableChannels(false); - focus_call_ = call; - if (focus_call_ != NULL) - focus_call_->EnableChannels(true); - SignalFocus(focus_call_, old_focus_call); - } -} - -void MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) { - // Move all sessions from call to call_to_join, delete call. - // If call_to_join has focus, added sessions should have enabled channels. - - if (focus_call_ == call) - SetFocus(NULL); - call_to_join->Join(call, focus_call_ == call_to_join); - DestroyCall(call); -} - -Session *MediaSessionClient::CreateSession(Call *call) { - std::string id; - return CreateSession(id, call); -} - -Session *MediaSessionClient::CreateSession(const std::string& id, Call* call) { - const std::string& type = NS_JINGLE_RTP; - Session *session = session_manager_->CreateSession(id, jid().Str(), type); - session_map_[session->id()] = call; - return session; -} - -Call *MediaSessionClient::FindCallByRemoteName(const std::string &remote_name) { - SessionMap::const_iterator call; - for (call = session_map_.begin(); call != session_map_.end(); ++call) { - std::vector<Session *> sessions = call->second->sessions(); - std::vector<Session *>::const_iterator session; - for (session = sessions.begin(); session != sessions.end(); ++session) { - if (remote_name == (*session)->remote_name()) { - return call->second; - } - } - } - - return NULL; -} - -// TODO(pthatcher): Move all of the parsing and writing functions into -// mediamessages.cc, with unit tests. -bool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) { - int id = GetXmlAttr(element, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY); - int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0); - int bitrate = GetXmlAttr(element, QN_BITRATE, 0); - int channels = GetXmlAttr(element, QN_CHANNELS, 1); - *out = AudioCodec(id, name, clockrate, bitrate, channels, 0); - return true; -} - -bool ParseGingleVideoCodec(const buzz::XmlElement* element, VideoCodec* out) { - int id = GetXmlAttr(element, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY); - int width = GetXmlAttr(element, QN_WIDTH, 0); - int height = GetXmlAttr(element, QN_HEIGHT, 0); - int framerate = GetXmlAttr(element, QN_FRAMERATE, 0); - - *out = VideoCodec(id, name, width, height, framerate, 0); - return true; -} - -// Parses an ssrc string as a legacy stream. If it fails, returns -// false and fills an error message. -bool ParseSsrcAsLegacyStream(const std::string& ssrc_str, - std::vector<StreamParams>* streams, - ParseError* error) { - if (!ssrc_str.empty()) { - uint32 ssrc; - if (!rtc::FromString(ssrc_str, &ssrc)) { - return BadParse("Missing or invalid ssrc.", error); - } - - streams->push_back(StreamParams::CreateLegacy(ssrc)); - } - return true; -} - -void ParseGingleSsrc(const buzz::XmlElement* parent_elem, - const buzz::QName& name, - MediaContentDescription* media) { - const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name); - if (ssrc_elem) { - ParseError error; - ParseSsrcAsLegacyStream( - ssrc_elem->BodyText(), &(media->mutable_streams()), &error); - } -} - -bool ParseCryptoParams(const buzz::XmlElement* element, - CryptoParams* out, - ParseError* error) { - if (!element->HasAttr(QN_CRYPTO_SUITE)) { - return BadParse("crypto: crypto-suite attribute missing ", error); - } else if (!element->HasAttr(QN_CRYPTO_KEY_PARAMS)) { - return BadParse("crypto: key-params attribute missing ", error); - } else if (!element->HasAttr(QN_CRYPTO_TAG)) { - return BadParse("crypto: tag attribute missing ", error); - } - - const std::string& crypto_suite = element->Attr(QN_CRYPTO_SUITE); - const std::string& key_params = element->Attr(QN_CRYPTO_KEY_PARAMS); - const int tag = GetXmlAttr(element, QN_CRYPTO_TAG, 0); - const std::string& session_params = - element->Attr(QN_CRYPTO_SESSION_PARAMS); // Optional. - - *out = CryptoParams(tag, crypto_suite, key_params, session_params); - return true; -} - - -// Parse the first encryption element found with a matching 'usage' -// element. -// <usage/> is specific to Gingle. In Jingle, <crypto/> is already -// scoped to a content. -// Return false if there was an encryption element and it could not be -// parsed. -bool ParseGingleEncryption(const buzz::XmlElement* desc, - const buzz::QName& usage, - MediaContentDescription* media, - ParseError* error) { - for (const buzz::XmlElement* encryption = desc->FirstNamed(QN_ENCRYPTION); - encryption != NULL; - encryption = encryption->NextNamed(QN_ENCRYPTION)) { - if (encryption->FirstNamed(usage) != NULL) { - if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) { - media->set_crypto_required(CT_SDES); - } - for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO); - crypto != NULL; - crypto = crypto->NextNamed(QN_CRYPTO)) { - CryptoParams params; - if (!ParseCryptoParams(crypto, ¶ms, error)) { - return false; - } - media->AddCrypto(params); - } - break; - } - } - return true; -} - -void ParseBandwidth(const buzz::XmlElement* parent_elem, - MediaContentDescription* media) { - const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH); - int bandwidth_kbps = -1; - if (bw_elem && rtc::FromString(bw_elem->BodyText(), &bandwidth_kbps)) { - if (bandwidth_kbps >= 0) { - media->set_bandwidth(bandwidth_kbps * 1000); - } - } -} - -bool ParseGingleAudioContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - AudioContentDescription* audio = new AudioContentDescription(); - - int preference = kMaxPayloadId; - if (content_elem->FirstElement()) { - for (const buzz::XmlElement* codec_elem = - content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE); - codec_elem != NULL; - codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) { - AudioCodec codec; - if (ParseGingleAudioCodec(codec_elem, &codec)) { - codec.preference = preference--; - audio->AddCodec(codec); - } - } - } else { - // For backward compatibility, we can assume the other client is - // an old version of Talk if it has no audio payload types at all. - audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1)); - audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0)); - } - - ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio); - - if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE, - audio, error)) { - return false; - } - - *content = audio; - return true; -} - -bool ParseGingleVideoContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - VideoContentDescription* video = new VideoContentDescription(); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* codec_elem = - content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE); - codec_elem != NULL; - codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) { - VideoCodec codec; - if (ParseGingleVideoCodec(codec_elem, &codec)) { - codec.preference = preference--; - video->AddCodec(codec); - } - } - - ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, video); - ParseBandwidth(content_elem, video); - - if (!ParseGingleEncryption(content_elem, QN_GINGLE_VIDEO_CRYPTO_USAGE, - video, error)) { - return false; - } - - *content = video; - return true; -} - -void ParsePayloadTypeParameters(const buzz::XmlElement* element, - std::map<std::string, std::string>* paramap) { - for (const buzz::XmlElement* param = element->FirstNamed(QN_PARAMETER); - param != NULL; param = param->NextNamed(QN_PARAMETER)) { - std::string name = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_NAME, - buzz::STR_EMPTY); - std::string value = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_VALUE, - buzz::STR_EMPTY); - if (!name.empty() && !value.empty()) { - paramap->insert(make_pair(name, value)); - } - } -} - -void ParseFeedbackParams(const buzz::XmlElement* element, - FeedbackParams* params) { - for (const buzz::XmlElement* param = element->FirstNamed(QN_JINGLE_RTCP_FB); - param != NULL; param = param->NextNamed(QN_JINGLE_RTCP_FB)) { - std::string type = GetXmlAttr(param, QN_TYPE, buzz::STR_EMPTY); - std::string subtype = GetXmlAttr(param, QN_SUBTYPE, buzz::STR_EMPTY); - if (!type.empty()) { - params->Add(FeedbackParam(type, subtype)); - } - } -} - -void AddFeedbackParams(const FeedbackParams& additional_params, - FeedbackParams* params) { - for (size_t i = 0; i < additional_params.params().size(); ++i) { - params->Add(additional_params.params()[i]); - } -} - -int FindWithDefault(const std::map<std::string, std::string>& map, - const std::string& key, const int def) { - std::map<std::string, std::string>::const_iterator iter = map.find(key); - return (iter == map.end()) ? def : atoi(iter->second.c_str()); -} - - -// Parse the first encryption element found. -// Return false if there was an encryption element and it could not be -// parsed. -bool ParseJingleEncryption(const buzz::XmlElement* content_elem, - MediaContentDescription* media, - ParseError* error) { - const buzz::XmlElement* encryption = - content_elem->FirstNamed(QN_ENCRYPTION); - if (encryption == NULL) { - return true; - } - - if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) { - media->set_crypto_required(CT_SDES); - } - - for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO); - crypto != NULL; - crypto = crypto->NextNamed(QN_CRYPTO)) { - CryptoParams params; - if (!ParseCryptoParams(crypto, ¶ms, error)) { - return false; - } - media->AddCrypto(params); - } - return true; -} - -bool ParseJingleAudioCodec(const buzz::XmlElement* elem, AudioCodec* codec) { - int id = GetXmlAttr(elem, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); - int clockrate = GetXmlAttr(elem, QN_CLOCKRATE, 0); - int channels = GetXmlAttr(elem, QN_CHANNELS, 1); - - std::map<std::string, std::string> paramap; - ParsePayloadTypeParameters(elem, ¶map); - int bitrate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_BITRATE, 0); - - *codec = AudioCodec(id, name, clockrate, bitrate, channels, 0); - ParseFeedbackParams(elem, &codec->feedback_params); - return true; -} - -bool ParseJingleVideoCodec(const buzz::XmlElement* elem, VideoCodec* codec) { - int id = GetXmlAttr(elem, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); - - std::map<std::string, std::string> paramap; - ParsePayloadTypeParameters(elem, ¶map); - int width = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_WIDTH, 0); - int height = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_HEIGHT, 0); - int framerate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_FRAMERATE, 0); - - *codec = VideoCodec(id, name, width, height, framerate, 0); - codec->params = paramap; - ParseFeedbackParams(elem, &codec->feedback_params); - return true; -} - -bool ParseJingleDataCodec(const buzz::XmlElement* elem, DataCodec* codec) { - int id = GetXmlAttr(elem, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); - - *codec = DataCodec(id, name, 0); - ParseFeedbackParams(elem, &codec->feedback_params); - return true; -} - -bool ParseJingleStreamsOrLegacySsrc(const buzz::XmlElement* desc_elem, - MediaContentDescription* media, - ParseError* error) { - if (HasJingleStreams(desc_elem)) { - if (!ParseJingleStreams(desc_elem, &(media->mutable_streams()), error)) { - return false; - } - } else { - const std::string ssrc_str = desc_elem->Attr(QN_SSRC); - if (!ParseSsrcAsLegacyStream( - ssrc_str, &(media->mutable_streams()), error)) { - return false; - } - } - return true; -} - -bool ParseJingleAudioContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - rtc::scoped_ptr<AudioContentDescription> audio( - new AudioContentDescription()); - - FeedbackParams content_feedback_params; - ParseFeedbackParams(content_elem, &content_feedback_params); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* payload_elem = - content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); - payload_elem != NULL; - payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { - AudioCodec codec; - if (ParseJingleAudioCodec(payload_elem, &codec)) { - AddFeedbackParams(content_feedback_params, &codec.feedback_params); - codec.preference = preference--; - audio->AddCodec(codec); - } - } - - if (!ParseJingleStreamsOrLegacySsrc(content_elem, audio.get(), error)) { - return false; - } - - if (!ParseJingleEncryption(content_elem, audio.get(), error)) { - return false; - } - - audio->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); - - RtpHeaderExtensions hdrexts; - if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) { - return false; - } - audio->set_rtp_header_extensions(hdrexts); - - *content = audio.release(); - return true; -} - -bool ParseJingleVideoContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - rtc::scoped_ptr<VideoContentDescription> video( - new VideoContentDescription()); - - FeedbackParams content_feedback_params; - ParseFeedbackParams(content_elem, &content_feedback_params); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* payload_elem = - content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); - payload_elem != NULL; - payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { - VideoCodec codec; - if (ParseJingleVideoCodec(payload_elem, &codec)) { - AddFeedbackParams(content_feedback_params, &codec.feedback_params); - codec.preference = preference--; - video->AddCodec(codec); - } - } - - if (!ParseJingleStreamsOrLegacySsrc(content_elem, video.get(), error)) { - return false; - } - ParseBandwidth(content_elem, video.get()); - - if (!ParseJingleEncryption(content_elem, video.get(), error)) { - return false; - } - - video->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); - - RtpHeaderExtensions hdrexts; - if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) { - return false; - } - video->set_rtp_header_extensions(hdrexts); - - *content = video.release(); - return true; -} - -bool ParseJingleSctpDataContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - rtc::scoped_ptr<DataContentDescription> data( - new DataContentDescription()); - data->set_protocol(kMediaProtocolSctp); - - for (const buzz::XmlElement* stream_elem = - content_elem->FirstNamed(QN_JINGLE_DRAFT_SCTP_STREAM); - stream_elem != NULL; - stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_SCTP_STREAM)) { - StreamParams stream; - stream.groupid = stream_elem->Attr(QN_NICK); - stream.id = stream_elem->Attr(QN_NAME); - uint32 sid; - if (!rtc::FromString(stream_elem->Attr(QN_SID), &sid)) { - return BadParse("Missing or invalid sid.", error); - } - if (sid > kMaxSctpSid) { - return BadParse("SID is greater than max value.", error); - } - - stream.ssrcs.push_back(sid); - data->mutable_streams().push_back(stream); - } - - *content = data.release(); - return true; -} - -bool ParseJingleRtpDataContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - DataContentDescription* data = new DataContentDescription(); - - FeedbackParams content_feedback_params; - ParseFeedbackParams(content_elem, &content_feedback_params); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* payload_elem = - content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); - payload_elem != NULL; - payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { - DataCodec codec; - if (ParseJingleDataCodec(payload_elem, &codec)) { - AddFeedbackParams(content_feedback_params, &codec.feedback_params); - codec.preference = preference--; - data->AddCodec(codec); - } - } - - if (!ParseJingleStreamsOrLegacySsrc(content_elem, data, error)) { - return false; - } - ParseBandwidth(content_elem, data); - - if (!ParseJingleEncryption(content_elem, data, error)) { - return false; - } - - data->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); - - *content = data; - return true; -} - -bool MediaSessionClient::ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - if (protocol == PROTOCOL_GINGLE) { - const std::string& content_type = content_elem->Name().Namespace(); - if (NS_GINGLE_AUDIO == content_type) { - return ParseGingleAudioContent(content_elem, content, error); - } else if (NS_GINGLE_VIDEO == content_type) { - return ParseGingleVideoContent(content_elem, content, error); - } else { - return BadParse("Unknown content type: " + content_type, error); - } - } else { - const std::string& content_type = content_elem->Name().Namespace(); - // We use the XMLNS of the <description> element to determine if - // it's RTP or SCTP. - if (content_type == NS_JINGLE_DRAFT_SCTP) { - return ParseJingleSctpDataContent(content_elem, content, error); - } - - std::string media; - if (!RequireXmlAttr(content_elem, QN_JINGLE_CONTENT_MEDIA, &media, error)) - return false; - - if (media == JINGLE_CONTENT_MEDIA_AUDIO) { - return ParseJingleAudioContent(content_elem, content, error); - } else if (media == JINGLE_CONTENT_MEDIA_VIDEO) { - return ParseJingleVideoContent(content_elem, content, error); - } else if (media == JINGLE_CONTENT_MEDIA_DATA) { - return ParseJingleRtpDataContent(content_elem, content, error); - } else { - return BadParse("Unknown media: " + media, error); - } - } -} - -buzz::XmlElement* CreateGingleAudioCodecElem(const AudioCodec& codec) { - buzz::XmlElement* payload_type = - new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true); - AddXmlAttr(payload_type, QN_ID, codec.id); - payload_type->AddAttr(QN_NAME, codec.name); - if (codec.clockrate > 0) - AddXmlAttr(payload_type, QN_CLOCKRATE, codec.clockrate); - if (codec.bitrate > 0) - AddXmlAttr(payload_type, QN_BITRATE, codec.bitrate); - if (codec.channels > 1) - AddXmlAttr(payload_type, QN_CHANNELS, codec.channels); - return payload_type; -} - -buzz::XmlElement* CreateGingleVideoCodecElem(const VideoCodec& codec) { - buzz::XmlElement* payload_type = - new buzz::XmlElement(QN_GINGLE_VIDEO_PAYLOADTYPE, true); - AddXmlAttr(payload_type, QN_ID, codec.id); - payload_type->AddAttr(QN_NAME, codec.name); - AddXmlAttr(payload_type, QN_WIDTH, codec.width); - AddXmlAttr(payload_type, QN_HEIGHT, codec.height); - AddXmlAttr(payload_type, QN_FRAMERATE, codec.framerate); - return payload_type; -} - -buzz::XmlElement* CreateGingleSsrcElem(const buzz::QName& name, uint32 ssrc) { - buzz::XmlElement* elem = new buzz::XmlElement(name, true); - if (ssrc) { - SetXmlBody(elem, ssrc); - } - return elem; -} - -buzz::XmlElement* CreateBandwidthElem(const buzz::QName& name, int bps) { - int kbps = bps / 1000; - buzz::XmlElement* elem = new buzz::XmlElement(name); - elem->AddAttr(buzz::QN_TYPE, "AS"); - SetXmlBody(elem, kbps); - return elem; -} - -// For Jingle, usage_qname is empty. -buzz::XmlElement* CreateJingleEncryptionElem(const CryptoParamsVec& cryptos, - bool required) { - buzz::XmlElement* encryption_elem = new buzz::XmlElement(QN_ENCRYPTION); - - if (required) { - encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true"); - } - - for (CryptoParamsVec::const_iterator i = cryptos.begin(); - i != cryptos.end(); - ++i) { - buzz::XmlElement* crypto_elem = new buzz::XmlElement(QN_CRYPTO); - - AddXmlAttr(crypto_elem, QN_CRYPTO_TAG, i->tag); - crypto_elem->AddAttr(QN_CRYPTO_SUITE, i->cipher_suite); - crypto_elem->AddAttr(QN_CRYPTO_KEY_PARAMS, i->key_params); - if (!i->session_params.empty()) { - crypto_elem->AddAttr(QN_CRYPTO_SESSION_PARAMS, i->session_params); - } - encryption_elem->AddElement(crypto_elem); - } - return encryption_elem; -} - -buzz::XmlElement* CreateGingleEncryptionElem(const CryptoParamsVec& cryptos, - const buzz::QName& usage_qname, - bool required) { - buzz::XmlElement* encryption_elem = - CreateJingleEncryptionElem(cryptos, required); - - if (required) { - encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true"); - } - - buzz::XmlElement* usage_elem = new buzz::XmlElement(usage_qname); - encryption_elem->AddElement(usage_elem); - - return encryption_elem; -} - -buzz::XmlElement* CreateGingleAudioContentElem( - const AudioContentDescription* audio, - bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true); - - for (AudioCodecs::const_iterator codec = audio->codecs().begin(); - codec != audio->codecs().end(); ++codec) { - elem->AddElement(CreateGingleAudioCodecElem(*codec)); - } - if (audio->has_ssrcs()) { - elem->AddElement(CreateGingleSsrcElem( - QN_GINGLE_AUDIO_SRCID, audio->first_ssrc())); - } - - const CryptoParamsVec& cryptos = audio->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateGingleEncryptionElem(cryptos, - QN_GINGLE_AUDIO_CRYPTO_USAGE, - crypto_required)); - } - return elem; -} - -buzz::XmlElement* CreateGingleVideoContentElem( - const VideoContentDescription* video, - bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true); - - for (VideoCodecs::const_iterator codec = video->codecs().begin(); - codec != video->codecs().end(); ++codec) { - elem->AddElement(CreateGingleVideoCodecElem(*codec)); - } - if (video->has_ssrcs()) { - elem->AddElement(CreateGingleSsrcElem( - QN_GINGLE_VIDEO_SRCID, video->first_ssrc())); - } - if (video->bandwidth() != kAutoBandwidth) { - elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH, - video->bandwidth())); - } - - const CryptoParamsVec& cryptos = video->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateGingleEncryptionElem(cryptos, - QN_GINGLE_VIDEO_CRYPTO_USAGE, - crypto_required)); - } - - return elem; -} - -template <class T> -buzz::XmlElement* CreatePayloadTypeParameterElem( - const std::string& name, T value) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_PARAMETER); - - elem->AddAttr(QN_PAYLOADTYPE_PARAMETER_NAME, name); - AddXmlAttr(elem, QN_PAYLOADTYPE_PARAMETER_VALUE, value); - - return elem; -} - -void AddRtcpFeedbackElem(buzz::XmlElement* elem, - const FeedbackParams& feedback_params) { - std::vector<FeedbackParam>::const_iterator it; - for (it = feedback_params.params().begin(); - it != feedback_params.params().end(); ++it) { - buzz::XmlElement* fb_elem = new buzz::XmlElement(QN_JINGLE_RTCP_FB); - fb_elem->AddAttr(QN_TYPE, it->id()); - fb_elem->AddAttr(QN_SUBTYPE, it->param()); - elem->AddElement(fb_elem); - } -} - -buzz::XmlElement* CreateJingleAudioCodecElem(const AudioCodec& codec) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); - - AddXmlAttr(elem, QN_ID, codec.id); - elem->AddAttr(QN_NAME, codec.name); - if (codec.clockrate > 0) { - AddXmlAttr(elem, QN_CLOCKRATE, codec.clockrate); - } - if (codec.bitrate > 0) { - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_BITRATE, codec.bitrate)); - } - if (codec.channels > 1) { - AddXmlAttr(elem, QN_CHANNELS, codec.channels); - } - - AddRtcpFeedbackElem(elem, codec.feedback_params); - - return elem; -} - -buzz::XmlElement* CreateJingleVideoCodecElem(const VideoCodec& codec) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); - - AddXmlAttr(elem, QN_ID, codec.id); - elem->AddAttr(QN_NAME, codec.name); - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_WIDTH, codec.width)); - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_HEIGHT, codec.height)); - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_FRAMERATE, codec.framerate)); - - AddRtcpFeedbackElem(elem, codec.feedback_params); - - CodecParameterMap::const_iterator param_iter; - for (param_iter = codec.params.begin(); param_iter != codec.params.end(); - ++param_iter) { - elem->AddElement(CreatePayloadTypeParameterElem(param_iter->first, - param_iter->second)); - } - - return elem; -} - -buzz::XmlElement* CreateJingleDataCodecElem(const DataCodec& codec) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); - - AddXmlAttr(elem, QN_ID, codec.id); - elem->AddAttr(QN_NAME, codec.name); - - AddRtcpFeedbackElem(elem, codec.feedback_params); - - return elem; -} - -void WriteLegacyJingleSsrc(const MediaContentDescription* media, - buzz::XmlElement* elem) { - if (media->has_ssrcs()) { - AddXmlAttr(elem, QN_SSRC, media->first_ssrc()); - } -} - -void WriteJingleStreamsOrLegacySsrc(const MediaContentDescription* media, - buzz::XmlElement* desc_elem) { - if (!media->multistream()) { - WriteLegacyJingleSsrc(media, desc_elem); - } else { - WriteJingleStreams(media->streams(), desc_elem); - } -} - -buzz::XmlElement* CreateJingleAudioContentElem( - const AudioContentDescription* audio, bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); - - elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO); - WriteJingleStreamsOrLegacySsrc(audio, elem); - - for (AudioCodecs::const_iterator codec = audio->codecs().begin(); - codec != audio->codecs().end(); ++codec) { - elem->AddElement(CreateJingleAudioCodecElem(*codec)); - } - - const CryptoParamsVec& cryptos = audio->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); - } - - if (audio->rtcp_mux()) { - elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); - } - - WriteJingleRtpHeaderExtensions(audio->rtp_header_extensions(), elem); - - return elem; -} - -buzz::XmlElement* CreateJingleVideoContentElem( - const VideoContentDescription* video, bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); - - elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO); - WriteJingleStreamsOrLegacySsrc(video, elem); - - for (VideoCodecs::const_iterator codec = video->codecs().begin(); - codec != video->codecs().end(); ++codec) { - elem->AddElement(CreateJingleVideoCodecElem(*codec)); - } - - const CryptoParamsVec& cryptos = video->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); - } - - if (video->rtcp_mux()) { - elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); - } - - if (video->bandwidth() != kAutoBandwidth) { - elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH, - video->bandwidth())); - } - - WriteJingleRtpHeaderExtensions(video->rtp_header_extensions(), elem); - - return elem; -} - -buzz::XmlElement* CreateJingleSctpDataContentElem( - const DataContentDescription* data) { - buzz::XmlElement* content_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_CONTENT, true); - for (std::vector<StreamParams>::const_iterator - stream = data->streams().begin(); - stream != data->streams().end(); ++stream) { - buzz::XmlElement* stream_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_STREAM, false); - AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream->groupid); - AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream->id); - if (!stream->ssrcs.empty()) { - AddXmlAttr(stream_elem, QN_SID, stream->ssrcs[0]); - } - content_elem->AddElement(stream_elem); - } - return content_elem;; -} - -buzz::XmlElement* CreateJingleRtpDataContentElem( - const DataContentDescription* data, bool crypto_required) { - - buzz::XmlElement* elem = - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); - - elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_DATA); - WriteJingleStreamsOrLegacySsrc(data, elem); - - for (DataCodecs::const_iterator codec = data->codecs().begin(); - codec != data->codecs().end(); ++codec) { - elem->AddElement(CreateJingleDataCodecElem(*codec)); - } - - const CryptoParamsVec& cryptos = data->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); - } - - if (data->rtcp_mux()) { - elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); - } - - if (data->bandwidth() != kAutoBandwidth) { - elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH, - data->bandwidth())); - } - - return elem; -} - -bool IsSctp(const DataContentDescription* data) { - return (data->protocol() == kMediaProtocolSctp || - data->protocol() == kMediaProtocolDtlsSctp); -} - -buzz::XmlElement* CreateJingleDataContentElem( - const DataContentDescription* data, bool crypto_required) { - if (IsSctp(data)) { - return CreateJingleSctpDataContentElem(data); - } else { - return CreateJingleRtpDataContentElem(data, crypto_required); - } -} - -bool MediaSessionClient::IsWritable(SignalingProtocol protocol, - const ContentDescription* content) { - const MediaContentDescription* media = - static_cast<const MediaContentDescription*>(content); - if (protocol == PROTOCOL_GINGLE && - media->type() == MEDIA_TYPE_DATA) { - return false; - } - return true; -} - -bool MediaSessionClient::WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error) { - const MediaContentDescription* media = - static_cast<const MediaContentDescription*>(content); - bool crypto_required = secure() == SEC_REQUIRED; - - if (media->type() == MEDIA_TYPE_AUDIO) { - const AudioContentDescription* audio = - static_cast<const AudioContentDescription*>(media); - if (protocol == PROTOCOL_GINGLE) { - *elem = CreateGingleAudioContentElem(audio, crypto_required); - } else { - *elem = CreateJingleAudioContentElem(audio, crypto_required); - } - } else if (media->type() == MEDIA_TYPE_VIDEO) { - const VideoContentDescription* video = - static_cast<const VideoContentDescription*>(media); - if (protocol == PROTOCOL_GINGLE) { - *elem = CreateGingleVideoContentElem(video, crypto_required); - } else { - *elem = CreateJingleVideoContentElem(video, crypto_required); - } - } else if (media->type() == MEDIA_TYPE_DATA) { - const DataContentDescription* data = - static_cast<const DataContentDescription*>(media); - if (protocol == PROTOCOL_GINGLE) { - return BadWrite("Data channel not supported with Gingle.", error); - } else { - *elem = CreateJingleDataContentElem(data, crypto_required); - } - } else { - return BadWrite("Unknown content type: " + - rtc::ToString<int>(media->type()), error); - } - - return true; -} - -} // namespace cricket diff --git a/talk/session/media/mediasessionclient.h b/talk/session/media/mediasessionclient.h deleted file mode 100644 index 4d29987a16..0000000000 --- a/talk/session/media/mediasessionclient.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * libjingle - * 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: - * - * 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. - */ - -#ifndef TALK_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ -#define TALK_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ - -#include <algorithm> -#include <map> -#include <string> -#include <vector> -#include "talk/media/base/cryptoparams.h" -#include "talk/session/media/call.h" -#include "talk/session/media/channelmanager.h" -#include "talk/session/media/mediasession.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sigslotrepeater.h" -#include "webrtc/base/thread.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/p2p/base/session.h" -#include "webrtc/p2p/base/sessionclient.h" -#include "webrtc/p2p/base/sessiondescription.h" - -namespace cricket { - -class Call; - -class MediaSessionClient : public SessionClient, public sigslot::has_slots<> { - public: -#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) - MediaSessionClient(const buzz::Jid& jid, SessionManager *manager); -#endif - // Alternative constructor, allowing injection of media_engine - // and device_manager. - MediaSessionClient(const buzz::Jid& jid, SessionManager *manager, - MediaEngineInterface* media_engine, - DataEngineInterface* data_media_engine, - DeviceManagerInterface* device_manager); - ~MediaSessionClient(); - - const buzz::Jid &jid() const { return jid_; } - SessionManager* session_manager() const { return session_manager_; } - ChannelManager* channel_manager() const { return channel_manager_; } - - // Return mapping of call ids to Calls. - const std::map<uint32, Call *>& calls() const { return calls_; } - - // The settings below combine with the settings on SessionManager to choose - - // whether SDES-SRTP, DTLS-SRTP, or no security should be used. The possible - // combinations are shown in the following table. Note that where either DTLS - // or SDES is possible, DTLS is preferred. Thus to require either SDES or - // DTLS, but not mandate DTLS, set SDES to require and DTLS to enable. - // - // | SDES:Disable | SDES:Enable | SDES:Require | - // ----------------------------------------------------------------| - // DTLS:Disable | No SRTP | SDES Optional | SDES Mandatory | - // DTLS:Enable | DTLS Optional | DTLS/SDES Opt | DTLS/SDES Mand | - // DTLS:Require | DTLS Mandatory | DTLS Mandatory | DTLS Mandatory | - - // Control use of SDES-SRTP. - SecurePolicy secure() const { return desc_factory_.secure(); } - void set_secure(SecurePolicy s) { desc_factory_.set_secure(s); } - - // Control use of multiple sessions in a call. - void set_multisession_enabled(bool multisession_enabled) { - multisession_enabled_ = multisession_enabled; - } - - int GetCapabilities() { return channel_manager_->GetCapabilities(); } - - Call *CreateCall(); - void DestroyCall(Call *call); - - Call *GetFocus(); - void SetFocus(Call *call); - - void JoinCalls(Call *call_to_join, Call *call); - - bool GetAudioInputDevices(std::vector<std::string>* names) { - return channel_manager_->GetAudioInputDevices(names); - } - bool GetAudioOutputDevices(std::vector<std::string>* names) { - return channel_manager_->GetAudioOutputDevices(names); - } - bool GetVideoCaptureDevices(std::vector<std::string>* names) { - return channel_manager_->GetVideoCaptureDevices(names); - } - - bool SetAudioOptions(const std::string& in_name, const std::string& out_name, - const AudioOptions& options) { - return channel_manager_->SetAudioOptions(in_name, out_name, options); - } - bool SetOutputVolume(int level) { - return channel_manager_->SetOutputVolume(level); - } - bool SetCaptureDevice(const std::string& cam_device) { - return channel_manager_->SetCaptureDevice(cam_device); - } - - SessionDescription* CreateOffer(const CallOptions& options) { - return desc_factory_.CreateOffer(options, NULL); - } - SessionDescription* CreateAnswer(const SessionDescription* offer, - const CallOptions& options) { - return desc_factory_.CreateAnswer(offer, options, NULL); - } - - sigslot::signal2<Call *, Call *> SignalFocus; - sigslot::signal1<Call *> SignalCallCreate; - sigslot::signal1<Call *> SignalCallDestroy; - sigslot::repeater0<> SignalDevicesChange; - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error); - virtual bool IsWritable(SignalingProtocol protocol, - const ContentDescription* content); - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error); - - private: - void Construct(); - void OnSessionCreate(Session *session, bool received_initiate); - void OnSessionState(BaseSession *session, BaseSession::State state); - void OnSessionDestroy(Session *session); - Session *CreateSession(Call *call); - Session *CreateSession(const std::string& id, Call* call); - Call *FindCallByRemoteName(const std::string &remote_name); - - buzz::Jid jid_; - SessionManager* session_manager_; - Call *focus_call_; - ChannelManager *channel_manager_; - MediaSessionDescriptionFactory desc_factory_; - bool multisession_enabled_; - std::map<uint32, Call *> calls_; - - // Maintain a mapping of session id to call. - typedef std::map<std::string, Call *> SessionMap; - SessionMap session_map_; - - friend class Call; -}; - -} // namespace cricket - -#endif // TALK_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ diff --git a/talk/session/media/mediasessionclient_unittest.cc b/talk/session/media/mediasessionclient_unittest.cc deleted file mode 100644 index eb052ef86a..0000000000 --- a/talk/session/media/mediasessionclient_unittest.cc +++ /dev/null @@ -1,3324 +0,0 @@ -/* - * libjingle - * 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: - * - * 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 <string> -#include <vector> - -#include "talk/media/base/fakemediaengine.h" -#include "talk/media/base/testutils.h" -#include "talk/media/devices/fakedevicemanager.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "talk/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmllite/xmlbuilder.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmllite/xmlprinter.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/ssladapter.h" - -using cricket::AudioCodec; -using cricket::AudioContentDescription; -using cricket::Codec; -using cricket::DataCodec; -using cricket::DataContentDescription; -using cricket::FeedbackParam; -using cricket::FeedbackParams; -using cricket::VideoCodec; -using cricket::VideoContentDescription; - -// The codecs that our FakeMediaEngine will support. Order is important, since -// the tests check that our messages have codecs in the correct order. -static const cricket::AudioCodec kAudioCodecs[] = { - cricket::AudioCodec(103, "ISAC", 16000, -1, 1, 18), - cricket::AudioCodec(104, "ISAC", 32000, -1, 1, 17), - cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16), - cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15), - cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14), - cricket::AudioCodec(9, "G722", 8000, 64000, 1, 13), - cricket::AudioCodec(102, "iLBC", 8000, 13300, 1, 12), - cricket::AudioCodec(98, "speex", 8000, 11000, 1, 11), - cricket::AudioCodec(3, "GSM", 8000, 13000, 1, 10), - cricket::AudioCodec(100, "EG711U", 8000, 64000, 1, 9), - cricket::AudioCodec(101, "EG711A", 8000, 64000, 1, 8), - cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 7), - cricket::AudioCodec(8, "PCMA", 8000, 64000, 1, 6), - cricket::AudioCodec(126, "CN", 32000, 0, 1, 5), - cricket::AudioCodec(105, "CN", 16000, 0, 1, 4), - cricket::AudioCodec(13, "CN", 8000, 0, 1, 3), - cricket::AudioCodec(117, "red", 8000, 0, 1, 2), - cricket::AudioCodec(106, "telephone-event", 8000, 0, 1, 1) -}; - -// The codecs that our FakeMediaEngine will support with a different order of -// supported codecs. -static const cricket::AudioCodec kAudioCodecsDifferentPreference[] = { - cricket::AudioCodec(104, "ISAC", 32000, -1, 1, 17), - cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14), - cricket::AudioCodec(9, "G722", 8000, 64000, 1, 13), - cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16), - cricket::AudioCodec(103, "ISAC", 16000, -1, 1, 18), - cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15), - cricket::AudioCodec(100, "EG711U", 8000, 64000, 1, 9), - cricket::AudioCodec(101, "EG711A", 8000, 64000, 1, 8), - cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 7), - cricket::AudioCodec(8, "PCMA", 8000, 64000, 1, 6), - cricket::AudioCodec(102, "iLBC", 8000, 13300, 1, 12), - cricket::AudioCodec(3, "GSM", 8000, 13000, 1, 10), - cricket::AudioCodec(98, "speex", 8000, 11000, 1, 11), - cricket::AudioCodec(126, "CN", 32000, 0, 1, 5), - cricket::AudioCodec(105, "CN", 16000, 0, 1, 4), - cricket::AudioCodec(13, "CN", 8000, 0, 1, 3), - cricket::AudioCodec(117, "red", 8000, 0, 1, 2), - cricket::AudioCodec(106, "telephone-event", 8000, 0, 1, 1) -}; - -static const cricket::VideoCodec kVideoCodecs[] = { - cricket::VideoCodec(96, "H264-SVC", 320, 200, 30, 1) -}; - -static const cricket::DataCodec kDataCodecs[] = { - cricket::DataCodec(127, "google-data", 0) -}; - -const std::string kGingleCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1'> " \ - " <usage/> " \ - " <rtp:crypto tag='145' crypto-suite='AES_CM_128_HMAC_SHA1_32'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='AES_CM_128_HMAC_SHA1_80'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - -// Jingle offer does not have any <usage> element. -const std::string kJingleCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1'> " \ - " <rtp:crypto tag='145' crypto-suite='AES_CM_128_HMAC_SHA1_32'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='AES_CM_128_HMAC_SHA1_80'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - - -const std::string kGingleRequiredCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1' required='true'> "\ - " <usage/> " \ - " <rtp:crypto tag='145' crypto-suite='AES_CM_128_HMAC_SHA1_32'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='AES_CM_128_HMAC_SHA1_80'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - -const std::string kJingleRequiredCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1' required='true'> "\ - " <rtp:crypto tag='145' crypto-suite='AES_CM_128_HMAC_SHA1_32'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='AES_CM_128_HMAC_SHA1_80'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - - -const std::string kGingleUnsupportedCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1'> " \ - " <usage/> " \ - " <rtp:crypto tag='145' crypto-suite='NOT_SUPPORTED_1'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='NOT_SUPPORTED_2'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - -const std::string kJingleUnsupportedCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1'> " \ - " <rtp:crypto tag='145' crypto-suite='NOT_SUPPORTED_1'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='NOT_SUPPORTED_2'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - - -// With unsupported but with required="true" -const std::string kGingleRequiredUnsupportedCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1' required='true'>" \ - " <usage/> " \ - " <rtp:crypto tag='145' crypto-suite='NOT_SUPPORTED_1'" \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/>" \ - " <rtp:crypto tag='51' crypto-suite='NOT_SUPPORTED_2'" \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - -const std::string kJingleRequiredUnsupportedCryptoOffer = \ - "<rtp:encryption xmlns:rtp='urn:xmpp:jingle:apps:rtp:1' required='true'>" \ - " <rtp:crypto tag='145' crypto-suite='NOT_SUPPORTED_1' " \ - " key-params='inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9'/> " \ - " <rtp:crypto tag='51' crypto-suite='NOT_SUPPORTED_2' " \ - " key-params='inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy'/>" \ - "</rtp:encryption> "; - -const std::string kGingleInitiate( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' clockrate='16000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='104' name='ISAC' clockrate='32000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='119' name='ISACLC' clockrate='16000' bitrate='40000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='99' name='speex' clockrate='16000' bitrate='22000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='97' name='IPCMWB' clockrate='16000' bitrate='80000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='9' name='G722' clockrate='8000' bitrate='64000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='102' name='iLBC' clockrate='8000' bitrate='13300' />" \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='98' name='speex' clockrate='8000' bitrate='11000' />" \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='3' name='GSM' clockrate='8000' bitrate='13000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='100' name='EG711U' clockrate='8000' bitrate='64000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='101' name='EG711A' clockrate='8000' bitrate='64000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='0' name='PCMU' clockrate='8000' bitrate='64000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='8' name='PCMA' clockrate='8000' bitrate='64000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='126' name='CN' clockrate='32000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='105' name='CN' clockrate='16000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='13' name='CN' clockrate='8000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='117' name='red' clockrate='8000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='106' name='telephone-event' clockrate='8000' /> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiate( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " <payload-type id='104' name='ISAC' clockrate='32000'/> " \ - " <payload-type " \ - " id='119' name='ISACLC' clockrate='16000'> " \ - " <parameter name='bitrate' value='40000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='99' name='speex' clockrate='16000'> " \ - " <parameter name='bitrate' value='22000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='97' name='IPCMWB' clockrate='16000'> " \ - " <parameter name='bitrate' value='80000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='9' name='G722' clockrate='8000'> " \ - " <parameter name='bitrate' value='64000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='102' name='iLBC' clockrate='8000'> " \ - " <parameter name='bitrate' value='13300'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='98' name='speex' clockrate='8000'> " \ - " <parameter name='bitrate' value='11000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='3' name='GSM' clockrate='8000'> " \ - " <parameter name='bitrate' value='13000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='100' name='EG711U' clockrate='8000'> " \ - " <parameter name='bitrate' value='64000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='101' name='EG711A' clockrate='8000'> " \ - " <parameter name='bitrate' value='64000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='0' name='PCMU' clockrate='8000'> " \ - " <parameter name='bitrate' value='64000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='8' name='PCMA' clockrate='8000'> " \ - " <parameter name='bitrate' value='64000'/> " \ - " </payload-type> " \ - " <payload-type " \ - " id='126' name='CN' clockrate='32000' /> " \ - " <payload-type " \ - " id='105' name='CN' clockrate='16000' /> " \ - " <payload-type " \ - " id='13' name='CN' clockrate='8000' /> " \ - " <payload-type " \ - " id='117' name='red' clockrate='8000' /> " \ - " <payload-type " \ - " id='106' name='telephone-event' clockrate='8000' /> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleInitiateWithRtcpFb( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'> " \ - " <rtcp-fb type='nack'/> " \ - " </payload-type> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='video'> " \ - " <rtcp-fb type='nack'/> " \ - " <payload-type id='99' name='H264-SVC'> " \ - " <rtcp-fb type='ccm' subtype='fir'/> " \ - " <parameter name='height' value='200'/> " \ - " <parameter name='width' value='320'/> " \ - " <parameter name='framerate' value='30'/> " \ - " </payload-type> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test data'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='data'> " \ - " <rtcp-fb type='nack'/> " \ - " <payload-type id='127' name='google-data'> " \ - " </payload-type> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kGingleVideoInitiate( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/video'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' clockrate='16000' /> " \ - " <payload-type xmlns='http://www.google.com/session/video' " \ - " id='99' name='H264-SVC' framerate='30' " \ - " height='200' width='320'/> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleVideoInitiate( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='video'> " \ - " <payload-type id='99' name='H264-SVC'> " \ - " <parameter name='height' value='200'/> " \ - " <parameter name='width' value='320'/> " \ - " <parameter name='framerate' value='30'/> " \ - " </payload-type> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleVideoInitiateWithRtpData( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='video'> " \ - " <payload-type id='99' name='H264-SVC'> " \ - " <parameter name='height' value='200'/> " \ - " <parameter name='width' value='320'/> " \ - " <parameter name='framerate' value='30'/> " \ - " </payload-type> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test data'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='data'> " \ - " <payload-type id='127' name='google-data'/> " \ - " <rtcp-mux/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleVideoInitiateWithSctpData( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='video'> " \ - " <payload-type id='99' name='H264-SVC'> " \ - " <parameter name='height' value='200'/> " \ - " <parameter name='width' value='320'/> " \ - " <parameter name='framerate' value='30'/> " \ - " </payload-type> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test data'> " \ - " <description xmlns='google:jingle:sctp' media='data'> " \ - " <stream sid='1'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleVideoInitiateWithBandwidth( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='video'> " \ - " <payload-type id='99' name='H264-SVC'> " \ - " <parameter name='height' value='200'/> " \ - " <parameter name='width' value='320'/> " \ - " <parameter name='framerate' value='30'/> " \ - " </payload-type> " \ - " <bandwidth type='AS'>42</bandwidth> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleVideoInitiateWithRtcpMux( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " <content name='test video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='video'> " \ - " <payload-type id='99' name='H264-SVC'> " \ - " <parameter name='height' value='200'/> " \ - " <parameter name='width' value='320'/> " \ - " <parameter name='framerate' value='30'/> " \ - " </payload-type> " \ - " <rtcp-mux/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// Initiate string with a combination of supported and unsupported codecs -// Should accept the supported ones -const std::string kGingleInitiateSomeUnsupported( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' clockrate='16000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='97' name='ASDFDS' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='102' name='1010' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='107' name='DFAS' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='100' name='EG711U' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='101' name='EG711A' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='0' name='PCMU' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='110' name=':)' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='13' name='CN' /> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateSomeUnsupported( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'> " \ - " <payload-type " \ - " id='103' name='ISAC' clockrate='16000' /> " \ - " <payload-type " \ - " id='97' name='ASDFDS' /> " \ - " <payload-type " \ - " id='102' name='1010' /> " \ - " <payload-type " \ - " id='107' name='DFAS' /> " \ - " <payload-type " \ - " id='100' name='EG711U' /> " \ - " <payload-type " \ - " id='101' name='EG711A' /> " \ - " <payload-type " \ - " id='0' name='PCMU' /> " \ - " <payload-type " \ - " id='110' name=':)' /> " \ - " <payload-type " \ - " id='13' name='CN' /> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kGingleVideoInitiateWithBandwidth( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/video'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' clockrate='16000' /> " \ - " <payload-type xmlns='http://www.google.com/session/video' " \ - " id='99' name='H264-SVC' framerate='30' " \ - " height='200' width='320'/> " \ - " <bandwidth type='AS'>42</bandwidth> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -// Initiate string without any supported codecs. Should send a reject. -const std::string kGingleInitiateNoSupportedAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='123' name='Supercodec6000' /> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateNoSupportedAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type " \ - " id='123' name='Supercodec6000' /> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// Initiate string without any codecs. Assumes ancient version of Cricket -// and tries a session with ISAC and PCMU -const std::string kGingleInitiateNoAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateNoAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// The codecs are supported, but not at the given clockrates. Should send -// a reject. -const std::string kGingleInitiateWrongClockrates( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' clockrate='8000'/> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='97' name='IPCMWB' clockrate='1337'/> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='102' name='iLBC' clockrate='1982' /> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateWrongClockrates( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type " \ - " id='103' name='ISAC' clockrate='8000'/> " \ - " <payload-type " \ - " id='97' name='IPCMWB' clockrate='1337'/> " \ - " <payload-type " \ - " id='102' name='iLBC' clockrate='1982' /> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// The codecs are supported, but not with the given number of channels. -// Should send a reject. -const std::string kGingleInitiateWrongChannels( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' channels='2'/> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='97' name='IPCMWB' channels='3'/> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateWrongChannels( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type " \ - " id='103' name='ISAC' channels='2'/> " \ - " <payload-type " \ - " id='97' name='IPCMWB' channels='3'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// Initiate with a dynamic codec not using webrtc default payload id. Should -// accept with provided payload id. -const std::string kGingleInitiateDynamicAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='123' name='speex' clockrate='16000'/> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateDynamicAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type " \ - " id='123' name='speex' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// Initiate string with nothing but static codec id's. Should accept. -const std::string kGingleInitiateStaticAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='3' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='0' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='8' /> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateStaticAudioCodecs( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate' " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type id='3' /> " \ - " <payload-type id='0' /> " \ - " <payload-type id='8' /> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// Initiate with payload type-less codecs. Should reject. -const std::string kGingleInitiateNoPayloadTypes( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateNoPayloadTypes( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate'> " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type name='ISAC' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -// Initiate with unnamed dynamic codces. Should reject. -const std::string kGingleInitiateDynamicWithoutNames( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <session xmlns='http://www.google.com/session' type='initiate'" \ - " id='abcdef' initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/phone'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='100' clockrate='16000'/> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleInitiateDynamicWithoutNames( - "<iq xmlns='jabber:client' from='me@domain.com/resource' " \ - " to='user@domain.com/resource' type='set' id='123'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-initiate'> " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " <content name='test audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>" \ - " <payload-type id='100' clockrate='16000'/> " \ - " </description> " \ - " <transport xmlns=\"http://www.google.com/transport/p2p\"/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const uint32 kAudioSsrc = 4294967295U; -const uint32 kVideoSsrc = 87654321; -const uint32 kDataSsrc = 1010101; -// Note that this message does not specify a session ID. It must be populated -// before use. -const std::string kGingleAcceptWithSsrcs( - "<iq xmlns='jabber:client' from='me@mydomain.com' " \ - " to='user@domain.com/resource' type='set' id='150'> " \ - " <session xmlns='http://www.google.com/session' type='accept' " \ - " initiator='me@domain.com/resource'> " \ - " <description xmlns='http://www.google.com/session/video'> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='103' name='ISAC' clockrate='16000' /> " \ - " <payload-type xmlns='http://www.google.com/session/phone' " \ - " id='104' name='ISAC' clockrate='32000' /> " \ - " <src-id xmlns='http://www.google.com/session/phone'> " \ - " 4294967295</src-id> " \ - " <src-id>87654321</src-id> " \ - " </description> " \ - " </session> " \ - "</iq> "); - -const std::string kJingleAcceptWithSsrcs( - "<iq xmlns='jabber:client' from='me@mydomain.com' " \ - " to='user@domain.com/resource' type='set' id='150'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-accept' " \ - " initiator='me@domain.com/resource'> " \ - " <content name='audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='audio' ssrc='4294967295'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " <payload-type id='104' name='ISAC' clockrate='32000'/> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " <content name='video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='video' ssrc='87654321'> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleAcceptWithRtpDataSsrcs( - "<iq xmlns='jabber:client' from='me@mydomain.com' " \ - " to='user@domain.com/resource' type='set' id='150'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-accept' " \ - " initiator='me@domain.com/resource'> " \ - " <content name='audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='audio' ssrc='4294967295'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " <payload-type id='104' name='ISAC' clockrate='32000'/> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " <content name='video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='video' ssrc='87654321'> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " <content name='data'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='data' ssrc='1010101'> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -const std::string kJingleAcceptWithSctpData( - "<iq xmlns='jabber:client' from='me@mydomain.com' " \ - " to='user@domain.com/resource' type='set' id='150'> " \ - " <jingle xmlns='urn:xmpp:jingle:1' action='session-accept' " \ - " initiator='me@domain.com/resource'> " \ - " <content name='audio'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='audio' ssrc='4294967295'> " \ - " <payload-type id='103' name='ISAC' clockrate='16000'/> " \ - " <payload-type id='104' name='ISAC' clockrate='32000'/> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " <content name='video'> " \ - " <description xmlns='urn:xmpp:jingle:apps:rtp:1' " \ - " media='video' ssrc='87654321'> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " <content name='data'> " \ - " <description xmlns='google:jingle:sctp'> " \ - " <stream sid='1'/> " \ - " </description> " \ - " <transport xmlns='http://www.google.com/transport/p2p'/> " \ - " </content> " \ - " </jingle> " \ - "</iq> "); - -std::string JingleView(const std::string& ssrc, - const std::string& width, - const std::string& height, - const std::string& framerate) { - // We have some slightly weird whitespace formatting to make the - // actual XML generated match the expected XML here. - return \ - "<cli:iq" - " to='me@mydomain.com'" - " type='set'" - " xmlns:cli='jabber:client'>" - "<jingle" - " xmlns='urn:xmpp:jingle:1'" - " action='session-info'" - " sid=''>" - "<view xmlns='google:jingle'" - " name='video'" - " type='static'" - " ssrc='" + ssrc + "'>" - "<params" - " width='" + width + "'" - " height='" + height + "'" - " framerate='" + framerate + "'" - " preference='0'/>" - "</view>" - "</jingle>" - "</cli:iq>"; -} - -std::string JingleStreamAdd(const std::string& content_name, - const std::string& nick, - const std::string& name, - const std::string& ssrc) { - return \ - "<iq" - " xmlns='jabber:client'" - " from='me@mydomain.com'" - " to='user@domain.com/resource'" - " type='set'" - " id='150'>" - " <jingle" - " xmlns='urn:xmpp:jingle:1'" - " action='description-info'>" - " <content" - " xmlns='urn:xmpp:jingle:1'" - " name='" + content_name + "'>" - " <description" - " xmlns='urn:xmpp:jingle:apps:rtp:1'" - " media='" + content_name + "'>" - " <streams" - " xmlns='google:jingle'>" - " <stream" - " nick='" + nick + "'" - " name='" + name + "'>" - " <ssrc>" + ssrc + "</ssrc>" - " </stream>" - " </streams>" - " </description>" - " </content>" - " </jingle>" - "</iq>"; -} - -std::string JingleOutboundStreamRemove(const std::string& sid, - const std::string& content_name, - const std::string& name) { - return \ - "<cli:iq" - " to='me@mydomain.com'" - " type='set'" - " xmlns:cli='jabber:client'>" - "<jingle" - " xmlns='urn:xmpp:jingle:1'" - " action='description-info'" - " sid='" + sid + "'>" - "<content" - " name='" + content_name + "'" - " creator='initiator'>" - "<description" - " xmlns='urn:xmpp:jingle:apps:rtp:1'" - " media='" + content_name + "'>" - "<streams" - " xmlns='google:jingle'>" - "<stream" - " name='" + name + "'>" - "</stream>" - "</streams>" - "</description>" - "</content>" - "</jingle>" - "</cli:iq>"; -} - -std::string JingleOutboundStreamAdd(const std::string& sid, - const std::string& content_name, - const std::string& name, - const std::string& ssrc) { - return \ - "<cli:iq" - " to='me@mydomain.com'" - " type='set'" - " xmlns:cli='jabber:client'>" - "<jingle" - " xmlns='urn:xmpp:jingle:1'" - " action='description-info'" - " sid='" + sid + "'>" - "<content" - " name='" + content_name + "'" - " creator='initiator'>" - "<description" - " xmlns='urn:xmpp:jingle:apps:rtp:1'" - " media='" + content_name + "'>" - "<streams" - " xmlns='google:jingle'>" - "<stream" - " name='" + name + "'>" - "<ssrc>" + ssrc + "</ssrc>" - "</stream>" - "</streams>" - "</description>" - "</content>" - "</jingle>" - "</cli:iq>"; -} - -std::string JingleStreamAddWithoutSsrc(const std::string& content_name, - const std::string& nick, - const std::string& name) { - return \ - "<iq" - " xmlns='jabber:client'" - " from='me@mydomain.com'" - " to='user@domain.com/resource'" - " type='set'" - " id='150'>" - " <jingle" - " xmlns='urn:xmpp:jingle:1'" - " action='description-info'>" - " <content" - " xmlns='urn:xmpp:jingle:1'" - " name='" + content_name + "'>" - " <description" - " xmlns='urn:xmpp:jingle:apps:rtp:1'" - " media='" + content_name + "'>" - " <streams" - " xmlns='google:jingle'>" - " <stream" - " nick='" + nick + "'" - " name='" + name + "'>" - " </stream>" - " </streams>" - " </description>" - " </content>" - " </jingle>" - "</iq>"; -} - -std::string JingleStreamRemove(const std::string& content_name, - const std::string& nick, - const std::string& name) { - return \ - "<iq" - " xmlns='jabber:client'" - " from='me@mydomain.com'" - " to='user@domain.com/resource'" - " type='set'" - " id='150'>" - " <jingle" - " xmlns='urn:xmpp:jingle:1'" - " action='description-info'>" - " <content" - " xmlns='urn:xmpp:jingle:1'" - " name='" + content_name + "'>" - " <description" - " xmlns='urn:xmpp:jingle:apps:rtp:1'" - " media='" + content_name + "'>" - " <streams" - " xmlns='google:jingle'>" - " <stream" - " nick='" + nick + "'" - " name='" + name + "'/>" - " </streams>" - " </description>" - " </content>" - " </jingle>" - "</iq>"; -} - -// Convenience function to get CallOptions that have audio enabled, -// but not video or data. -static cricket::CallOptions AudioCallOptions() { - cricket::CallOptions options; - options.recv_audio = true; - options.recv_video = false; - options.data_channel_type = cricket::DCT_NONE; - return options; -} - -// Convenience function to get CallOptions that have audio and video -// enabled, but not data. -static cricket::CallOptions VideoCallOptions() { - cricket::CallOptions options; - options.recv_audio = true; - options.recv_video = true; - options.data_channel_type = cricket::DCT_NONE; - return options; -} - -static buzz::XmlElement* CopyElement(const buzz::XmlElement* elem) { - return new buzz::XmlElement(*elem); -} - -static std::string AddEncryption(std::string stanza, std::string encryption) { - std::string::size_type pos = stanza.find("</description>"); - while (pos != std::string::npos) { - stanza = stanza.insert(pos, encryption); - pos = stanza.find("</description>", pos + encryption.length() + 1); - } - return stanza; -} - -static int IntFromJingleCodecParameter(const buzz::XmlElement* parameter, - const std::string& expected_name) { - if (parameter) { - const std::string& actual_name = - parameter->Attr(cricket::QN_PAYLOADTYPE_PARAMETER_NAME); - - EXPECT_EQ(expected_name, actual_name) - << "wrong parameter name. Expected '" - << expected_name << "'. Actually '" - << actual_name << "'."; - - return atoi(parameter->Attr( - cricket::QN_PAYLOADTYPE_PARAMETER_VALUE).c_str()); - } - return 0; -} - -template <class CodecClass, class DescriptionClass> -static void VerifyCodecFbParams(const FeedbackParams& expected, - const DescriptionClass* desc) { - if (!expected.params().empty()) { - ASSERT_TRUE(desc != NULL); - const std::vector<CodecClass> codecs = desc->codecs(); - for (size_t i = 0; i < codecs.size(); ++i) { - EXPECT_EQ(expected, codecs[i].feedback_params); - } - } -} - -// Parses and extracts payload and codec info from test XML. Since -// that XML will be in various contents (Gingle and Jingle), we need an -// abstract parser with one concrete implementation per XML content. -class MediaSessionTestParser { - public: - virtual buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) = 0; - virtual buzz::XmlElement* ContentFromAction(buzz::XmlElement* action) = 0; - virtual buzz::XmlElement* NextContent(buzz::XmlElement* content) = 0; - virtual buzz::XmlElement* PayloadTypeFromContent( - buzz::XmlElement* content) = 0; - virtual buzz::XmlElement* NextFromPayloadType( - buzz::XmlElement* payload_type) = 0; - virtual cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) = 0; - virtual cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) = 0; - virtual cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) = 0; - virtual buzz::XmlElement* EncryptionFromContent( - buzz::XmlElement* content) = 0; - virtual buzz::XmlElement* NextFromEncryption( - buzz::XmlElement* encryption) = 0; - virtual const buzz::XmlElement* BandwidthFromContent( - buzz::XmlElement* content) = 0; - virtual const buzz::XmlElement* RtcpMuxFromContent( - buzz::XmlElement* content) = 0; - virtual bool ActionIsTerminate(const buzz::XmlElement* action) = 0; - virtual ~MediaSessionTestParser() {} -}; - -class JingleSessionTestParser : public MediaSessionTestParser { - public: - JingleSessionTestParser() {} - - ~JingleSessionTestParser() { - } - - buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) { - return stanza->FirstNamed(cricket::QN_JINGLE); - } - - buzz::XmlElement* ContentFromAction(buzz::XmlElement* action) { - // We need to be able to use multiple contents, but the action - // gets deleted before we can call NextContent, so we need to - // stash away a copy. - action_.reset(CopyElement(action)); - return action_->FirstNamed(cricket::QN_JINGLE_CONTENT); - } - - buzz::XmlElement* NextContent(buzz::XmlElement* content) { - // For some reason, content->NextNamed(cricket::QN_JINGLE_CONTENT) - // doesn't work. - return action_->FirstNamed(cricket::QN_JINGLE_CONTENT) - ->NextNamed(cricket::QN_JINGLE_CONTENT); - } - - buzz::XmlElement* PayloadTypeFromContent(buzz::XmlElement* content) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - if (!content_desc) - return NULL; - - return content_desc->FirstNamed(cricket::QN_JINGLE_RTP_PAYLOADTYPE); - } - - buzz::XmlElement* NextFromPayloadType(buzz::XmlElement* payload_type) { - return payload_type->NextNamed(cricket::QN_JINGLE_RTP_PAYLOADTYPE); - } - - void ParsePayloadTypeFeedbackParameters(const buzz::XmlElement* element, - FeedbackParams* params) { - const buzz::XmlElement* param = - element->FirstNamed(cricket::QN_JINGLE_RTCP_FB); - for (; param != NULL; - param = param->NextNamed(cricket::QN_JINGLE_RTCP_FB)) { - std::string type = param->Attr(cricket::QN_TYPE); - std::string subtype = param->Attr(cricket::QN_SUBTYPE); - if (!type.empty()) { - params->Add(FeedbackParam(type, subtype)); - } - } - } - - cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int clockrate = 0; - if (payload_type->HasAttr(cricket::QN_CLOCKRATE)) - clockrate = atoi(payload_type->Attr(cricket::QN_CLOCKRATE).c_str()); - - int bitrate = IntFromJingleCodecParameter( - payload_type->FirstNamed(cricket::QN_PARAMETER), "bitrate"); - - int channels = 1; - if (payload_type->HasAttr(cricket::QN_CHANNELS)) - channels = atoi(payload_type->Attr( - cricket::QN_CHANNELS).c_str()); - - AudioCodec codec = AudioCodec(id, name, clockrate, bitrate, channels, 0); - ParsePayloadTypeFeedbackParameters(payload_type, &codec.feedback_params); - return codec; - } - - cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int width = 0; - int height = 0; - int framerate = 0; - const buzz::XmlElement* param = - payload_type->FirstNamed(cricket::QN_PARAMETER); - if (param) { - width = IntFromJingleCodecParameter(param, "width"); - param = param->NextNamed(cricket::QN_PARAMETER); - if (param) { - height = IntFromJingleCodecParameter(param, "height"); - param = param->NextNamed(cricket::QN_PARAMETER); - if (param) { - framerate = IntFromJingleCodecParameter(param, "framerate"); - } - } - } - VideoCodec codec = VideoCodec(id, name, width, height, framerate, 0); - ParsePayloadTypeFeedbackParameters(payload_type, &codec.feedback_params); - return codec; - } - - cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - DataCodec codec = DataCodec(id, name, 0); - ParsePayloadTypeFeedbackParameters(payload_type, &codec.feedback_params); - return codec; - } - - bool ActionIsTerminate(const buzz::XmlElement* action) { - return (action->HasAttr(cricket::QN_ACTION) && - action->Attr(cricket::QN_ACTION) == "session-terminate"); - } - - buzz::XmlElement* EncryptionFromContent(buzz::XmlElement* content) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - if (!content_desc) - return NULL; - - return content_desc->FirstNamed(cricket::QN_ENCRYPTION); - } - - buzz::XmlElement* NextFromEncryption(buzz::XmlElement* encryption) { - return encryption->NextNamed(cricket::QN_ENCRYPTION); - } - - const buzz::XmlElement* BandwidthFromContent(buzz::XmlElement* content) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - if (!content_desc) - return NULL; - - return content_desc->FirstNamed(cricket::QN_JINGLE_RTP_BANDWIDTH); - } - - const buzz::XmlElement* RtcpMuxFromContent(buzz::XmlElement* content) { - return content->FirstNamed(cricket::QN_JINGLE_RTCP_MUX); - } - - private: - rtc::scoped_ptr<buzz::XmlElement> action_; -}; - -class GingleSessionTestParser : public MediaSessionTestParser { - public: - GingleSessionTestParser() : found_content_count_(0) {} - - buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) { - return stanza->FirstNamed(cricket::QN_GINGLE_SESSION); - } - - buzz::XmlElement* ContentFromAction(buzz::XmlElement* session) { - buzz::XmlElement* content = - session->FirstNamed(cricket::QN_GINGLE_AUDIO_CONTENT); - if (content == NULL) - content = session->FirstNamed(cricket::QN_GINGLE_VIDEO_CONTENT); - return content; - } - - // Assumes contents are in order of audio, and then video. - buzz::XmlElement* NextContent(buzz::XmlElement* content) { - found_content_count_++; - return content; - } - - buzz::XmlElement* PayloadTypeFromContent(buzz::XmlElement* content) { - if (found_content_count_ > 0) { - return content->FirstNamed(cricket::QN_GINGLE_VIDEO_PAYLOADTYPE); - } else { - return content->FirstNamed(cricket::QN_GINGLE_AUDIO_PAYLOADTYPE); - } - } - - buzz::XmlElement* NextFromPayloadType(buzz::XmlElement* payload_type) { - if (found_content_count_ > 0) { - return payload_type->NextNamed(cricket::QN_GINGLE_VIDEO_PAYLOADTYPE); - } else { - return payload_type->NextNamed(cricket::QN_GINGLE_AUDIO_PAYLOADTYPE); - } - } - - cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int clockrate = 0; - if (payload_type->HasAttr(cricket::QN_CLOCKRATE)) - clockrate = atoi(payload_type->Attr(cricket::QN_CLOCKRATE).c_str()); - - int bitrate = 0; - if (payload_type->HasAttr(cricket::QN_BITRATE)) - bitrate = atoi(payload_type->Attr(cricket::QN_BITRATE).c_str()); - - int channels = 1; - if (payload_type->HasAttr(cricket::QN_CHANNELS)) - channels = atoi(payload_type->Attr(cricket::QN_CHANNELS).c_str()); - - return cricket::AudioCodec(id, name, clockrate, bitrate, channels, 0); - } - - cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int width = 0; - if (payload_type->HasAttr(cricket::QN_WIDTH)) - width = atoi(payload_type->Attr(cricket::QN_WIDTH).c_str()); - - int height = 0; - if (payload_type->HasAttr(cricket::QN_HEIGHT)) - height = atoi(payload_type->Attr(cricket::QN_HEIGHT).c_str()); - - int framerate = 1; - if (payload_type->HasAttr(cricket::QN_FRAMERATE)) - framerate = atoi(payload_type->Attr(cricket::QN_FRAMERATE).c_str()); - - return cricket::VideoCodec(id, name, width, height, framerate, 0); - } - - cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - // Gingle can't do data codecs. - return cricket::DataCodec(0, "", 0); - } - - buzz::XmlElement* EncryptionFromContent( - buzz::XmlElement* content) { - return content->FirstNamed(cricket::QN_ENCRYPTION); - } - - buzz::XmlElement* NextFromEncryption(buzz::XmlElement* encryption) { - return encryption->NextNamed(cricket::QN_ENCRYPTION); - } - - const buzz::XmlElement* BandwidthFromContent(buzz::XmlElement* content) { - return content->FirstNamed(cricket::QN_GINGLE_VIDEO_BANDWIDTH); - } - - const buzz::XmlElement* RtcpMuxFromContent(buzz::XmlElement* content) { - return NULL; - } - - bool ActionIsTerminate(const buzz::XmlElement* session) { - return (session->HasAttr(buzz::QN_TYPE) && - session->Attr(buzz::QN_TYPE) == "terminate"); - } - - int found_content_count_; -}; - -class MediaSessionClientTest : public sigslot::has_slots<> { - public: - explicit MediaSessionClientTest(MediaSessionTestParser* parser, - cricket::SignalingProtocol initial_protocol) { - nm_ = new rtc::BasicNetworkManager(); - pa_ = new cricket::BasicPortAllocator(nm_); - sm_ = new cricket::SessionManager(pa_, NULL); - fme_ = new cricket::FakeMediaEngine(); - fdme_ = new cricket::FakeDataEngine(); - - FeedbackParams params_nack_fir; - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamCcm, - cricket::kRtcpFbCcmParamFir)); - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - FeedbackParams params_nack; - params_nack.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - - std::vector<cricket::AudioCodec> - audio_codecs(kAudioCodecs, kAudioCodecs + ARRAY_SIZE(kAudioCodecs)); - SetCodecFeedbackParams(&audio_codecs, params_nack); - fme_->SetAudioCodecs(audio_codecs); - std::vector<cricket::VideoCodec> - video_codecs(kVideoCodecs, kVideoCodecs + ARRAY_SIZE(kVideoCodecs)); - SetCodecFeedbackParams(&video_codecs, params_nack_fir); - fme_->SetVideoCodecs(video_codecs); - std::vector<cricket::DataCodec> - data_codecs(kDataCodecs, kDataCodecs + ARRAY_SIZE(kDataCodecs)); - SetCodecFeedbackParams(&data_codecs, params_nack); - fdme_->SetDataCodecs(data_codecs); - - client_ = new cricket::MediaSessionClient( - buzz::Jid("user@domain.com/resource"), sm_, - fme_, fdme_, new cricket::FakeDeviceManager()); - client_->session_manager()->SignalOutgoingMessage.connect( - this, &MediaSessionClientTest::OnSendStanza); - client_->session_manager()->SignalSessionCreate.connect( - this, &MediaSessionClientTest::OnSessionCreate); - client_->SignalCallCreate.connect( - this, &MediaSessionClientTest::OnCallCreate); - client_->SignalCallDestroy.connect( - this, &MediaSessionClientTest::OnCallDestroy); - - call_ = NULL; - parser_ = parser; - initial_protocol_ = initial_protocol; - expect_incoming_crypto_ = false; - expect_outgoing_crypto_ = false; - expected_video_bandwidth_ = cricket::kAutoBandwidth; - expected_video_rtcp_mux_ = false; - } - - ~MediaSessionClientTest() { - delete client_; - delete sm_; - delete pa_; - delete nm_; - delete parser_; - ClearStanzas(); - } - - buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) { - return parser_->ActionFromStanza(stanza); - } - - buzz::XmlElement* ContentFromAction(buzz::XmlElement* action) { - return parser_->ContentFromAction(action); - } - - buzz::XmlElement* PayloadTypeFromContent(buzz::XmlElement* payload) { - return parser_->PayloadTypeFromContent(payload); - } - - buzz::XmlElement* NextFromPayloadType(buzz::XmlElement* payload_type) { - return parser_->NextFromPayloadType(payload_type); - } - - buzz::XmlElement* EncryptionFromContent(buzz::XmlElement* content) { - return parser_->EncryptionFromContent(content); - } - - buzz::XmlElement* NextFromEncryption(buzz::XmlElement* encryption) { - return parser_->NextFromEncryption(encryption); - } - - cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - return parser_->AudioCodecFromPayloadType(payload_type); - } - - cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - return parser_->VideoCodecFromPayloadType(payload_type); - } - - cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - return parser_->DataCodecFromPayloadType(payload_type); - } - - const AudioContentDescription* GetFirstAudioContentDescription( - const cricket::SessionDescription* sdesc) { - const cricket::ContentInfo* content = - cricket::GetFirstAudioContent(sdesc); - if (content == NULL) - return NULL; - return static_cast<const AudioContentDescription*>(content->description); - } - - const cricket::VideoContentDescription* GetFirstVideoContentDescription( - const cricket::SessionDescription* sdesc) { - const cricket::ContentInfo* content = - cricket::GetFirstVideoContent(sdesc); - if (content == NULL) - return NULL; - return static_cast<const cricket::VideoContentDescription*>( - content->description); - } - - void CheckCryptoFromGoodIncomingInitiate(const cricket::Session* session) { - ASSERT_TRUE(session != NULL); - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->remote_description()); - ASSERT_TRUE(content != NULL); - ASSERT_EQ(2U, content->cryptos().size()); - ASSERT_EQ(145, content->cryptos()[0].tag); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_32", content->cryptos()[0].cipher_suite); - ASSERT_EQ("inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9", - content->cryptos()[0].key_params); - ASSERT_EQ(51, content->cryptos()[1].tag); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", content->cryptos()[1].cipher_suite); - ASSERT_EQ("inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy", - content->cryptos()[1].key_params); - } - - void CheckCryptoForGoodOutgoingAccept(const cricket::Session* session) { - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->local_description()); - ASSERT_EQ(1U, content->cryptos().size()); - ASSERT_EQ(145, content->cryptos()[0].tag); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_32", content->cryptos()[0].cipher_suite); - ASSERT_EQ(47U, content->cryptos()[0].key_params.size()); - } - - void CheckBadCryptoFromIncomingInitiate(const cricket::Session* session) { - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->remote_description()); - ASSERT_EQ(1U, content->cryptos().size()); - ASSERT_EQ(145, content->cryptos()[0].tag); - ASSERT_EQ("NOT_SUPPORTED", content->cryptos()[0].cipher_suite); - ASSERT_EQ("inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9", - content->cryptos()[0].key_params); - } - - void CheckNoCryptoForOutgoingAccept(const cricket::Session* session) { - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->local_description()); - ASSERT_TRUE(content->cryptos().empty()); - } - - void CheckRtcpFb(const cricket::SessionDescription* sdesc) { - VerifyCodecFbParams<AudioCodec>(expected_audio_fb_params_, - GetFirstAudioContentDescription(sdesc)); - - VerifyCodecFbParams<VideoCodec>(expected_video_fb_params_, - GetFirstVideoContentDescription(sdesc)); - - VerifyCodecFbParams<DataCodec>(expected_data_fb_params_, - GetFirstDataContentDescription(sdesc)); - } - - void CheckVideoBandwidth(int expected_bandwidth, - const cricket::SessionDescription* sdesc) { - const cricket::VideoContentDescription* video = - GetFirstVideoContentDescription(sdesc); - if (video != NULL) { - ASSERT_EQ(expected_bandwidth, video->bandwidth()); - } - } - - void CheckVideoRtcpMux(bool expected_video_rtcp_mux, - const cricket::SessionDescription* sdesc) { - const cricket::VideoContentDescription* video = - GetFirstVideoContentDescription(sdesc); - if (video != NULL) { - ASSERT_EQ(expected_video_rtcp_mux, video->rtcp_mux()); - } - } - - virtual void CheckRtpDataContent(buzz::XmlElement* content) { - if (initial_protocol_) { - // Gingle can not write out data content. - return; - } - - buzz::XmlElement* e = PayloadTypeFromContent(content); - ASSERT_TRUE(e != NULL); - cricket::DataCodec codec = DataCodecFromPayloadType(e); - EXPECT_EQ(127, codec.id); - EXPECT_EQ("google-data", codec.name); - EXPECT_EQ(expected_data_fb_params_, codec.feedback_params); - - CheckDataRtcpMux(true, call_->sessions()[0]->local_description()); - CheckDataRtcpMux(true, call_->sessions()[0]->remote_description()); - if (expect_outgoing_crypto_) { - content = parser_->NextContent(content); - buzz::XmlElement* encryption = EncryptionFromContent(content); - ASSERT_TRUE(encryption != NULL); - // TODO(pthatcher): Check encryption parameters? - } - } - - virtual void CheckSctpDataContent(buzz::XmlElement* content) { - if (initial_protocol_) { - // Gingle can not write out data content. - return; - } - - buzz::XmlElement* payload_type = PayloadTypeFromContent(content); - ASSERT_TRUE(payload_type == NULL); - buzz::XmlElement* encryption = EncryptionFromContent(content); - ASSERT_TRUE(encryption == NULL); - // TODO(pthatcher): Check for <streams>. - } - - void CheckDataRtcpMux(bool expected_data_rtcp_mux, - const cricket::SessionDescription* sdesc) { - const cricket::DataContentDescription* data = - GetFirstDataContentDescription(sdesc); - if (data != NULL) { - ASSERT_EQ(expected_data_rtcp_mux, data->rtcp_mux()); - } - } - - void CheckAudioSsrcForIncomingAccept(const cricket::Session* session) { - const AudioContentDescription* audio = - GetFirstAudioContentDescription(session->remote_description()); - ASSERT_TRUE(audio != NULL); - ASSERT_EQ(kAudioSsrc, audio->first_ssrc()); - } - - void CheckVideoSsrcForIncomingAccept(const cricket::Session* session) { - const cricket::VideoContentDescription* video = - GetFirstVideoContentDescription(session->remote_description()); - ASSERT_TRUE(video != NULL); - ASSERT_EQ(kVideoSsrc, video->first_ssrc()); - } - - void CheckDataSsrcForIncomingAccept(const cricket::Session* session) { - const cricket::DataContentDescription* data = - GetFirstDataContentDescription(session->remote_description()); - ASSERT_TRUE(data != NULL); - ASSERT_EQ(kDataSsrc, data->first_ssrc()); - } - - void TestGoodIncomingInitiate(const std::string& initiate_string, - const cricket::CallOptions& options, - buzz::XmlElement** element) { - *element = NULL; - - rtc::scoped_ptr<buzz::XmlElement> el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - ASSERT_TRUE(call_ != NULL); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_RECEIVEDINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - CheckVideoBandwidth(expected_video_bandwidth_, - call_->sessions()[0]->remote_description()); - CheckVideoRtcpMux(expected_video_rtcp_mux_, - call_->sessions()[0]->remote_description()); - CheckRtcpFb(call_->sessions()[0]->remote_description()); - if (expect_incoming_crypto_) { - CheckCryptoFromGoodIncomingInitiate(call_->sessions()[0]); - } - - // TODO(pthatcher): Add tests for sending <bandwidth> in accept. - call_->AcceptSession(call_->sessions()[0], options); - ASSERT_EQ(cricket::Session::STATE_SENTACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - - buzz::XmlElement* e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(ContentFromAction(e) != NULL); - *element = CopyElement(ContentFromAction(e)); - ASSERT_TRUE(*element != NULL); - ClearStanzas(); - if (expect_outgoing_crypto_) { - CheckCryptoForGoodOutgoingAccept(call_->sessions()[0]); - } - - if (options.data_channel_type == cricket::DCT_RTP) { - CheckDataRtcpMux(true, call_->sessions()[0]->local_description()); - CheckDataRtcpMux(true, call_->sessions()[0]->remote_description()); - // TODO(pthatcher): Check rtcpmux and crypto? - } - - call_->Terminate(); - ASSERT_EQ(cricket::Session::STATE_SENTTERMINATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(parser_->ActionIsTerminate(e)); - ClearStanzas(); - } - - void TestRejectOffer(const std::string &initiate_string, - const cricket::CallOptions& options, - buzz::XmlElement** element) { - *element = NULL; - - rtc::scoped_ptr<buzz::XmlElement> el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - ASSERT_TRUE(call_ != NULL); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_RECEIVEDINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - - call_->AcceptSession(call_->sessions()[0], options); - ASSERT_EQ(cricket::Session::STATE_SENTACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - - buzz::XmlElement* e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(ContentFromAction(e) != NULL); - *element = CopyElement(ContentFromAction(e)); - ASSERT_TRUE(*element != NULL); - ClearStanzas(); - - buzz::XmlElement* content = *element; - // The NextContent method actually returns the second content. So we - // can't handle the case when audio, video and data are all enabled. But - // since we are testing rejection, it won't be the case. - if (options.has_audio()) { - ASSERT_TRUE(content != NULL); - ASSERT_EQ("test audio", content->Attr(buzz::QName("", "name"))); - content = parser_->NextContent(content); - } - - if (options.has_video()) { - ASSERT_TRUE(content != NULL); - ASSERT_EQ("test video", content->Attr(buzz::QName("", "name"))); - content = parser_->NextContent(content); - } - - if (options.has_data()) { - ASSERT_TRUE(content != NULL); - ASSERT_EQ("test data", content->Attr(buzz::QName("", "name"))); - content = parser_->NextContent(content); - } - - call_->Terminate(); - ASSERT_EQ(cricket::Session::STATE_SENTTERMINATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(parser_->ActionIsTerminate(e)); - ClearStanzas(); - } - - void TestBadIncomingInitiate(const std::string& initiate_string) { - rtc::scoped_ptr<buzz::XmlElement> el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - ASSERT_TRUE(call_ != NULL); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_SENTREJECT, - call_->sessions()[0]->state()); - ASSERT_EQ(2U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[1]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[1]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - } - - void VerifyAudioCodec(const AudioCodec& codec, int id, - const std::string& name, int clockrate, - int bitrate, int channels) { - ASSERT_EQ(id, codec.id); - ASSERT_EQ(name, codec.name); - ASSERT_EQ(clockrate, codec.clockrate); - ASSERT_EQ(bitrate, codec.bitrate); - ASSERT_EQ(channels, codec.channels); - ASSERT_EQ(expected_audio_fb_params_, codec.feedback_params); - } - - void TestGoodOutgoingInitiate(const cricket::CallOptions& options) { - if (initial_protocol_ == cricket::PROTOCOL_JINGLE) { - // rtcp fb is only implemented for jingle. - ExpectRtcpFb(); - } - - client_->CreateCall(); - ASSERT_TRUE(call_ != NULL); - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_SENTINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - buzz::XmlElement* action = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(action != NULL); - buzz::XmlElement* content = ContentFromAction(action); - ASSERT_TRUE(content != NULL); - - buzz::XmlElement* e = PayloadTypeFromContent(content); - ASSERT_TRUE(e != NULL); - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 103, "ISAC", 16000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 104, "ISAC", 32000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 119, "ISACLC", 16000, 40000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 99, "speex", 16000, 22000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 97, "IPCMWB", 16000, 80000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 9, "G722", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 102, "iLBC", 8000, 13300, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 98, "speex", 8000, 11000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 3, "GSM", 8000, 13000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 100, "EG711U", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 101, "EG711A", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 0, "PCMU", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 8, "PCMA", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 126, "CN", 32000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 105, "CN", 16000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 13, "CN", 8000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 117, "red", 8000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 106, "telephone-event", 8000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - - if (expect_outgoing_crypto_) { - buzz::XmlElement* encryption = EncryptionFromContent(content); - ASSERT_TRUE(encryption != NULL); - - if (client_->secure() == cricket::SEC_REQUIRED) { - ASSERT_TRUE(cricket::GetXmlAttr( - encryption, cricket::QN_ENCRYPTION_REQUIRED, false)); - } - - if (content->Name().Namespace() == cricket::NS_GINGLE_AUDIO) { - e = encryption->FirstNamed(cricket::QN_GINGLE_AUDIO_CRYPTO_USAGE); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE( - e->NextNamed(cricket::QN_GINGLE_AUDIO_CRYPTO_USAGE) == NULL); - ASSERT_TRUE( - e->FirstNamed(cricket::QN_GINGLE_VIDEO_CRYPTO_USAGE) == NULL); - } - - e = encryption->FirstNamed(cricket::QN_CRYPTO); - ASSERT_TRUE(e != NULL); - ASSERT_EQ("0", e->Attr(cricket::QN_CRYPTO_TAG)); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_32", e->Attr(cricket::QN_CRYPTO_SUITE)); - std::string key_0 = e->Attr(cricket::QN_CRYPTO_KEY_PARAMS); - ASSERT_EQ(47U, key_0.length()); - ASSERT_EQ("inline:", key_0.substr(0, 7)); - - e = e->NextNamed(cricket::QN_CRYPTO); - ASSERT_TRUE(e != NULL); - ASSERT_EQ("1", e->Attr(cricket::QN_CRYPTO_TAG)); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", e->Attr(cricket::QN_CRYPTO_SUITE)); - std::string key_1 = e->Attr(cricket::QN_CRYPTO_KEY_PARAMS); - ASSERT_EQ(47U, key_1.length()); - ASSERT_EQ("inline:", key_1.substr(0, 7)); - ASSERT_NE(key_0, key_1); - - encryption = NextFromEncryption(encryption); - ASSERT_TRUE(encryption == NULL); - } - - if (options.has_video()) { - CheckVideoBandwidth(options.video_bandwidth, - call_->sessions()[0]->local_description()); - CheckVideoRtcpMux(expected_video_rtcp_mux_, - call_->sessions()[0]->remote_description()); - content = parser_->NextContent(content); - const buzz::XmlElement* bandwidth = - parser_->BandwidthFromContent(content); - if (options.video_bandwidth == cricket::kAutoBandwidth) { - ASSERT_TRUE(bandwidth == NULL); - } else { - ASSERT_TRUE(bandwidth != NULL); - ASSERT_EQ("AS", bandwidth->Attr(buzz::QName("", "type"))); - ASSERT_EQ(rtc::ToString(options.video_bandwidth / 1000), - bandwidth->BodyText()); - } - - buzz::XmlElement* e = PayloadTypeFromContent(content); - ASSERT_TRUE(e != NULL); - VideoCodec codec = VideoCodecFromPayloadType(e); - VideoCodec expected_codec = kVideoCodecs[0]; - expected_codec.preference = codec.preference; - expected_codec.feedback_params = expected_video_fb_params_; - EXPECT_EQ(expected_codec, codec); - } - - if (options.data_channel_type == cricket::DCT_RTP) { - content = parser_->NextContent(content); - CheckRtpDataContent(content); - } - - if (options.data_channel_type == cricket::DCT_SCTP) { - content = parser_->NextContent(content); - CheckSctpDataContent(content); - } - - ClearStanzas(); - } - - void TestHasAllSupportedAudioCodecs(buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(104, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(32000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(119, codec.id); - ASSERT_EQ("ISACLC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(40000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(99, codec.id); - ASSERT_EQ("speex", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(22000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(97, codec.id); - ASSERT_EQ("IPCMWB", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(80000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(9, codec.id); - ASSERT_EQ("G722", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(102, codec.id); - ASSERT_EQ("iLBC", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(13300, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(98, codec.id); - ASSERT_EQ("speex", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(11000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(3, codec.id); - ASSERT_EQ("GSM", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(13000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(100, codec.id); - ASSERT_EQ("EG711U", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(101, codec.id); - ASSERT_EQ("EG711A", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - ASSERT_EQ("PCMU", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(8, codec.id); - ASSERT_EQ("PCMA", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(126, codec.id); - ASSERT_EQ("CN", codec.name); - ASSERT_EQ(32000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(105, codec.id); - ASSERT_EQ("CN", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(13, codec.id); - ASSERT_EQ("CN", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(117, codec.id); - ASSERT_EQ("red", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(106, codec.id); - ASSERT_EQ("telephone-event", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestCodecsOfVideoInitiate(buzz::XmlElement* content) { - ASSERT_TRUE(content != NULL); - buzz::XmlElement* payload_type = PayloadTypeFromContent(content); - ASSERT_TRUE(payload_type != NULL); - cricket::AudioCodec codec = AudioCodecFromPayloadType(payload_type); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - content = parser_->NextContent(content); - ASSERT_TRUE(content != NULL); - payload_type = PayloadTypeFromContent(content); - ASSERT_TRUE(payload_type != NULL); - cricket::VideoCodec vcodec = - parser_->VideoCodecFromPayloadType(payload_type); - ASSERT_EQ(99, vcodec.id); - ASSERT_EQ("H264-SVC", vcodec.name); - ASSERT_EQ(320, vcodec.width); - ASSERT_EQ(200, vcodec.height); - ASSERT_EQ(30, vcodec.framerate); - } - - void TestHasAudioCodecsFromInitiateSomeUnsupported(buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(100, codec.id); - ASSERT_EQ("EG711U", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(101, codec.id); - ASSERT_EQ("EG711A", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - ASSERT_EQ("PCMU", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(13, codec.id); - ASSERT_EQ("CN", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestHasAudioCodecsFromInitiateDynamicAudioCodecs( - buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(123, codec.id); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestHasDefaultAudioCodecs(buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - ASSERT_EQ("PCMU", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestHasAudioCodecsFromInitiateStaticAudioCodecs( - buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(3, codec.id); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(8, codec.id); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestGingleInitiateWithUnsupportedCrypto( - const std::string &initiate_string, - buzz::XmlElement** element) { - *element = NULL; - - rtc::scoped_ptr<buzz::XmlElement> el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - - ASSERT_EQ(cricket::Session::STATE_RECEIVEDINITIATE, - call_->sessions()[0]->state()); - ClearStanzas(); - CheckBadCryptoFromIncomingInitiate(call_->sessions()[0]); - - call_->AcceptSession(call_->sessions()[0], cricket::CallOptions()); - ClearStanzas(); - CheckNoCryptoForOutgoingAccept(call_->sessions()[0]); - - call_->Terminate(); - ASSERT_EQ(cricket::Session::STATE_SENTTERMINATE, - call_->sessions()[0]->state()); - ClearStanzas(); - } - - void TestIncomingAcceptWithSsrcs( - const std::string& accept_string, - cricket::CallOptions& options) { - client_->CreateCall(); - ASSERT_TRUE(call_ != NULL); - - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_SENTINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - buzz::XmlElement* action = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(action != NULL); - buzz::XmlElement* content = ContentFromAction(action); - ASSERT_TRUE(content != NULL); - if (initial_protocol_ == cricket::PROTOCOL_JINGLE) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - ASSERT_TRUE(content_desc != NULL); - ASSERT_EQ("", content_desc->Attr(cricket::QN_SSRC)); - } - ClearStanzas(); - - // We need to insert the session ID into the session accept message. - rtc::scoped_ptr<buzz::XmlElement> el( - buzz::XmlElement::ForStr(accept_string)); - const std::string sid = call_->sessions()[0]->id(); - if (initial_protocol_ == cricket::PROTOCOL_JINGLE) { - buzz::XmlElement* jingle = el->FirstNamed(cricket::QN_JINGLE); - jingle->SetAttr(cricket::QN_SID, sid); - } else { - buzz::XmlElement* session = el->FirstNamed(cricket::QN_GINGLE_SESSION); - session->SetAttr(cricket::QN_ID, sid); - } - - client_->session_manager()->OnIncomingMessage(el.get()); - - ASSERT_EQ(cricket::Session::STATE_RECEIVEDACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - - CheckAudioSsrcForIncomingAccept(call_->sessions()[0]); - CheckVideoSsrcForIncomingAccept(call_->sessions()[0]); - if (options.data_channel_type == cricket::DCT_RTP) { - CheckDataSsrcForIncomingAccept(call_->sessions()[0]); - } - // TODO(pthatcher): Check kDataSid if DCT_SCTP. - // const uint32 kDataSid = 0; - } - - size_t ClearStanzas() { - size_t size = stanzas_.size(); - for (size_t i = 0; i < size; i++) { - delete stanzas_[i]; - } - stanzas_.clear(); - return size; - } - - buzz::XmlElement* SetJingleSid(buzz::XmlElement* stanza) { - buzz::XmlElement* jingle = - stanza->FirstNamed(cricket::QN_JINGLE); - jingle->SetAttr(cricket::QN_SID, call_->sessions()[0]->id()); - return stanza; - } - - void TestSendVideoStreamUpdate() { - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - - client_->CreateCall(); - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ClearStanzas(); - - cricket::StreamParams stream; - stream.id = "test-stream"; - stream.ssrcs.push_back(1001); - rtc::scoped_ptr<buzz::XmlElement> expected_stream_add( - buzz::XmlElement::ForStr( - JingleOutboundStreamAdd( - call_->sessions()[0]->id(), - "video", stream.id, "1001"))); - rtc::scoped_ptr<buzz::XmlElement> expected_stream_remove( - buzz::XmlElement::ForStr( - JingleOutboundStreamRemove( - call_->sessions()[0]->id(), - "video", stream.id))); - - call_->SendVideoStreamUpdate(call_->sessions()[0], - call_->CreateVideoStreamUpdate(stream)); - ASSERT_EQ(1U, stanzas_.size()); - EXPECT_EQ(expected_stream_add->Str(), stanzas_[0]->Str()); - ClearStanzas(); - - stream.ssrcs.clear(); - call_->SendVideoStreamUpdate(call_->sessions()[0], - call_->CreateVideoStreamUpdate(stream)); - ASSERT_EQ(1U, stanzas_.size()); - EXPECT_EQ(expected_stream_remove->Str(), stanzas_[0]->Str()); - ClearStanzas(); - } - - void TestStreamsUpdateAndViewRequests() { - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - - client_->CreateCall(); - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ASSERT_EQ(1U, ClearStanzas()); - ASSERT_EQ(0U, last_streams_added_.audio().size()); - ASSERT_EQ(0U, last_streams_added_.video().size()); - ASSERT_EQ(0U, last_streams_removed_.audio().size()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - rtc::scoped_ptr<buzz::XmlElement> accept_stanza( - buzz::XmlElement::ForStr(kJingleAcceptWithSsrcs)); - SetJingleSid(accept_stanza.get()); - client_->session_manager()->OnIncomingMessage(accept_stanza.get()); - ASSERT_EQ(cricket::Session::STATE_RECEIVEDACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - // Need to clear the added streams, because they are populated when - // receiving an accept message now. - last_streams_added_.mutable_video()->clear(); - last_streams_added_.mutable_audio()->clear(); - - call_->sessions()[0]->SetState(cricket::Session::STATE_INPROGRESS); - - rtc::scoped_ptr<buzz::XmlElement> streams_stanza( - buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video1", "ABC"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - // First one is ignored because of bad syntax. - ASSERT_EQ(1U, stanzas_.size()); - // TODO(pthatcher): Figure out how to make this an ERROR rather than RESULT. - ASSERT_EQ(std::string(buzz::STR_ERROR), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - ASSERT_EQ(0U, last_streams_added_.audio().size()); - ASSERT_EQ(0U, last_streams_added_.video().size()); - ASSERT_EQ(0U, last_streams_removed_.audio().size()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("audio", "Bob", "audio1", "1234"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.audio().size()); - ASSERT_EQ("Bob", last_streams_added_.audio()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.audio()[0].ssrcs.size()); - ASSERT_EQ(1234U, last_streams_added_.audio()[0].first_ssrc()); - - // Ignores adds without ssrcs. - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAddWithoutSsrc("audio", "Bob", "audioX"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.audio().size()); - ASSERT_EQ(1234U, last_streams_added_.audio()[0].first_ssrc()); - - // Ignores stream updates with unknown content names. (Don't terminate). - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAddWithoutSsrc("foo", "Bob", "foo"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("audio", "Joe", "audio1", "2468"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.audio().size()); - ASSERT_EQ("Joe", last_streams_added_.audio()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.audio()[0].ssrcs.size()); - ASSERT_EQ(2468U, last_streams_added_.audio()[0].first_ssrc()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video1", "5678"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.video().size()); - ASSERT_EQ("Bob", last_streams_added_.video()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.video()[0].ssrcs.size()); - ASSERT_EQ(5678U, last_streams_added_.video()[0].first_ssrc()); - - // We're testing that a "duplicate" is effectively ignored. - last_streams_added_.mutable_video()->clear(); - last_streams_removed_.mutable_video()->clear(); - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video1", "5678"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(0U, last_streams_added_.video().size()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video2", "5679"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.video().size()); - ASSERT_EQ("Bob", last_streams_added_.video()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.video()[0].ssrcs.size()); - ASSERT_EQ(5679U, last_streams_added_.video()[0].first_ssrc()); - - cricket::FakeVoiceMediaChannel* voice_channel = fme_->GetVoiceChannel(0); - ASSERT_TRUE(voice_channel != NULL); - 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->HasRecvStream(5678U)); - ClearStanzas(); - - cricket::ViewRequest viewRequest; - cricket::StaticVideoView staticVideoView( - cricket::StreamSelector(5678U), 640, 480, 30); - viewRequest.static_video_views.push_back(staticVideoView); - rtc::scoped_ptr<buzz::XmlElement> expected_view_elem( - buzz::XmlElement::ForStr(JingleView("5678", "640", "480", "30"))); - SetJingleSid(expected_view_elem.get()); - - ASSERT_TRUE( - call_->SendViewRequest(call_->sessions()[0], viewRequest)); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_EQ(expected_view_elem->Str(), stanzas_[0]->Str()); - ClearStanzas(); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("audio", "Bob", "audio1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_removed_.audio().size()); - ASSERT_EQ(1U, last_streams_removed_.audio()[0].ssrcs.size()); - EXPECT_EQ(1234U, last_streams_removed_.audio()[0].first_ssrc()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("video", "Bob", "video1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_removed_.video().size()); - ASSERT_EQ(1U, last_streams_removed_.video()[0].ssrcs.size()); - EXPECT_EQ(5678U, last_streams_removed_.video()[0].first_ssrc()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("video", "Bob", "video2"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_removed_.video().size()); - ASSERT_EQ(1U, last_streams_removed_.video()[0].ssrcs.size()); - EXPECT_EQ(5679U, last_streams_removed_.video()[0].first_ssrc()); - - // Duplicate removal: should be ignored. - last_streams_removed_.mutable_audio()->clear(); - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("audio", "Bob", "audio1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(0U, last_streams_removed_.audio().size()); - - // Duplicate removal: should be ignored. - last_streams_removed_.mutable_video()->clear(); - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("video", "Bob", "video1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - voice_channel = fme_->GetVoiceChannel(0); - ASSERT_TRUE(voice_channel != NULL); - 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->HasRecvStream(5678U)); - - // Fails because ssrc is now invalid. - ASSERT_FALSE( - call_->SendViewRequest(call_->sessions()[0], viewRequest)); - - ClearStanzas(); - } - - void MakeSignalingSecure(cricket::SecurePolicy secure) { - client_->set_secure(secure); - } - - void ExpectCrypto(cricket::SecurePolicy secure) { - MakeSignalingSecure(secure); - expect_incoming_crypto_ = true; -#ifdef HAVE_SRTP - expect_outgoing_crypto_ = true; -#endif - } - - void ExpectVideoBandwidth(int bandwidth) { - expected_video_bandwidth_ = bandwidth; - } - - void ExpectVideoRtcpMux(bool rtcp_mux) { - expected_video_rtcp_mux_ = rtcp_mux; - } - - template <class C> - void SetCodecFeedbackParams(std::vector<C>* codecs, - const FeedbackParams& fb_params) { - for (size_t i = 0; i < codecs->size(); ++i) { - codecs->at(i).feedback_params = fb_params; - } - } - - void ExpectRtcpFb() { - FeedbackParams params_nack_fir; - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamCcm, - cricket::kRtcpFbCcmParamFir)); - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - - FeedbackParams params_nack; - params_nack.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - - expected_audio_fb_params_ = params_nack; - expected_video_fb_params_ = params_nack_fir; - expected_data_fb_params_ = params_nack; - } - - cricket::FakeMediaEngine* fme() { return fme_; } - - private: - void OnSendStanza(cricket::SessionManager* manager, - const buzz::XmlElement* stanza) { - LOG(LS_INFO) << stanza->Str(); - stanzas_.push_back(new buzz::XmlElement(*stanza)); - } - - void OnSessionCreate(cricket::Session* session, bool initiate) { - session->set_current_protocol(initial_protocol_); - } - - void OnCallCreate(cricket::Call *call) { - call_ = call; - call->SignalMediaStreamsUpdate.connect( - this, &MediaSessionClientTest::OnMediaStreamsUpdate); - } - - void OnCallDestroy(cricket::Call *call) { - call_ = NULL; - } - - void OnMediaStreamsUpdate(cricket::Call *call, - cricket::Session *session, - const cricket::MediaStreams& added, - const cricket::MediaStreams& removed) { - last_streams_added_.CopyFrom(added); - last_streams_removed_.CopyFrom(removed); - } - - rtc::NetworkManager* nm_; - cricket::PortAllocator* pa_; - cricket::SessionManager* sm_; - cricket::FakeMediaEngine* fme_; - cricket::FakeDataEngine* fdme_; - cricket::MediaSessionClient* client_; - - cricket::Call* call_; - std::vector<buzz::XmlElement* > stanzas_; - MediaSessionTestParser* parser_; - cricket::SignalingProtocol initial_protocol_; - bool expect_incoming_crypto_; - bool expect_outgoing_crypto_; - int expected_video_bandwidth_; - bool expected_video_rtcp_mux_; - FeedbackParams expected_audio_fb_params_; - FeedbackParams expected_video_fb_params_; - FeedbackParams expected_data_fb_params_; - cricket::MediaStreams last_streams_added_; - cricket::MediaStreams last_streams_removed_; -}; - -MediaSessionClientTest* GingleTest() { - return new MediaSessionClientTest(new GingleSessionTestParser(), - cricket::PROTOCOL_GINGLE); -} - -MediaSessionClientTest* JingleTest() { - return new MediaSessionClientTest(new JingleSessionTestParser(), - cricket::PROTOCOL_JINGLE); -} - -class MediaSessionTest : public ::testing::Test {}; - -TEST_F(MediaSessionTest, JingleGoodInitiateWithRtcpFb) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - - cricket::CallOptions options = VideoCallOptions(); - options.data_channel_type = cricket::DCT_SCTP; - test->ExpectRtcpFb(); - test->TestGoodIncomingInitiate( - kJingleInitiateWithRtcpFb, options, elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiate) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kJingleVideoInitiate, VideoCallOptions(), elem.use()); - test->TestCodecsOfVideoInitiate(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithBandwidth) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->ExpectVideoBandwidth(42000); - test->TestGoodIncomingInitiate( - kJingleVideoInitiateWithBandwidth, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithRtcpMux) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->ExpectVideoRtcpMux(true); - test->TestGoodIncomingInitiate( - kJingleVideoInitiateWithRtcpMux, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithRtpData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - cricket::CallOptions options = VideoCallOptions(); - options.data_channel_type = cricket::DCT_RTP; - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiateWithRtpData, kJingleCryptoOffer), - options, - elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithSctpData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - cricket::CallOptions options = VideoCallOptions(); - options.data_channel_type = cricket::DCT_SCTP; - test->TestGoodIncomingInitiate(kJingleVideoInitiateWithSctpData, - options, - elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectAudio) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - cricket::CallOptions options = VideoCallOptions(); - options.recv_audio = false; - options.data_channel_type = cricket::DCT_RTP; - test->TestRejectOffer(kJingleVideoInitiateWithRtpData, options, elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectVideo) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - cricket::CallOptions options = AudioCallOptions(); - options.data_channel_type = cricket::DCT_RTP; - test->TestRejectOffer(kJingleVideoInitiateWithRtpData, options, elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestRejectOffer( - kJingleVideoInitiateWithRtpData, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectVideoAndData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestRejectOffer( - kJingleVideoInitiateWithRtpData, AudioCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateAllSupportedAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kJingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -// Changes the codecs that our FakeMediaEngine will support with a different -// preference order than the incoming offer. -// Verifies the answer accepts the preference order of the remote peer. -TEST_F(MediaSessionTest, JingleGoodInitiateDifferentPreferenceAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->fme()->SetAudioCodecs(MAKE_VECTOR(kAudioCodecsDifferentPreference)); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kJingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateSomeUnsupportedAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kJingleInitiateSomeUnsupported, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateSomeUnsupported(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateDynamicAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kJingleInitiateDynamicAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateDynamicAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateStaticAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kJingleInitiateStaticAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateStaticAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, JingleBadInitiateNoAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateNoAudioCodecs); -} - -TEST_F(MediaSessionTest, JingleBadInitiateNoSupportedAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateNoSupportedAudioCodecs); -} - -TEST_F(MediaSessionTest, JingleBadInitiateWrongClockrates) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateWrongClockrates); -} - -TEST_F(MediaSessionTest, JingleBadInitiateWrongChannels) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateWrongChannels); -} - -TEST_F(MediaSessionTest, JingleBadInitiateNoPayloadTypes) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateNoPayloadTypes); -} - -TEST_F(MediaSessionTest, JingleBadInitiateDynamicWithoutNames) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateDynamicWithoutNames); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiate) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithBandwidth) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.video_bandwidth = 42000; - test->TestGoodOutgoingInitiate(options); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithRtcpMux) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.rtcp_mux_enabled = true; - test->TestGoodOutgoingInitiate(options); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithRtpData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options; - options.data_channel_type = cricket::DCT_RTP; - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(options); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithSctpData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options; - options.data_channel_type = cricket::DCT_SCTP; - test->TestGoodOutgoingInitiate(options); -} - -// Crypto related tests. - -// Offer has crypto but the session is not secured, just ignore it. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoIsIgnoredWhenNotSecured) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiate, kJingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto required but the session is not secure, fail. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoRequiredWhenNotSecured) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate(AddEncryption(kJingleVideoInitiate, - kJingleRequiredCryptoOffer)); -} - -// Offer has no crypto but the session is secure required, fail. -TEST_F(MediaSessionTest, JingleInitiateWithNoCryptoFailsWhenSecureRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate(kJingleInitiate); -} - -// Offer has crypto and session is secure, expect crypto in the answer. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoWhenSecureEnabled) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiate, kJingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto and session is secure required, expect crypto in -// the answer. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoWhenSecureRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiate, kJingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported crypto and session is secure, no crypto in -// the answer. -TEST_F(MediaSessionTest, JingleInitiateWithUnsupportedCrypto) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleUnsupportedCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported REQUIRED crypto and session is not secure, fail. -TEST_F(MediaSessionTest, JingleInitiateWithRequiredUnsupportedCrypto) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestBadIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is secure, fail. -TEST_F(MediaSessionTest, - JingleInitiateWithRequiredUnsupportedCryptoWhenSecure) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestBadIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is required secure, fail. -TEST_F(MediaSessionTest, - JingleInitiateWithRequiredUnsupportedCryptoWhenSecureRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->MakeSignalingSecure(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleRequiredUnsupportedCryptoOffer)); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithCrypto) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithCryptoRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, JingleIncomingAcceptWithSsrcs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - test->TestIncomingAcceptWithSsrcs(kJingleAcceptWithSsrcs, options); -} - -TEST_F(MediaSessionTest, JingleIncomingAcceptWithRtpDataSsrcs) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - options.data_channel_type = cricket::DCT_RTP; - test->TestIncomingAcceptWithSsrcs(kJingleAcceptWithRtpDataSsrcs, options); -} - -TEST_F(MediaSessionTest, JingleIncomingAcceptWithSctpData) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - options.data_channel_type = cricket::DCT_SCTP; - test->TestIncomingAcceptWithSsrcs(kJingleAcceptWithSctpData, options); -} - -TEST_F(MediaSessionTest, JingleStreamsUpdateAndView) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestStreamsUpdateAndViewRequests(); -} - -TEST_F(MediaSessionTest, JingleSendVideoStreamUpdate) { - rtc::scoped_ptr<MediaSessionClientTest> test(JingleTest()); - test->TestSendVideoStreamUpdate(); -} - -// Gingle tests - -TEST_F(MediaSessionTest, GingleGoodVideoInitiate) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleVideoInitiate, VideoCallOptions(), elem.use()); - test->TestCodecsOfVideoInitiate(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodVideoInitiateWithBandwidth) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectVideoBandwidth(42000); - test->TestGoodIncomingInitiate( - kGingleVideoInitiateWithBandwidth, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateAllSupportedAudioCodecs) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateAllSupportedAudioCodecsWithCrypto) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - AudioCallOptions(), - elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -// Changes the codecs that our FakeMediaEngine will support with a different -// preference order than the incoming offer. -// Verifies the answer accepts the preference order of the remote peer. -TEST_F(MediaSessionTest, GingleGoodInitiateDifferentPreferenceAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->fme()->SetAudioCodecs(MAKE_VECTOR(kAudioCodecsDifferentPreference)); - rtc::scoped_ptr<buzz::XmlElement> elem; - test->TestGoodIncomingInitiate( - kGingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateSomeUnsupportedAudioCodecs) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateSomeUnsupported, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateSomeUnsupported(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateDynamicAudioCodecs) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateDynamicAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateDynamicAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateStaticAudioCodecs) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateStaticAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateStaticAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateNoAudioCodecs) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateNoAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasDefaultAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleBadInitiateNoSupportedAudioCodecs) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateNoSupportedAudioCodecs); -} - -TEST_F(MediaSessionTest, GingleBadInitiateWrongClockrates) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateWrongClockrates); -} - -TEST_F(MediaSessionTest, GingleBadInitiateWrongChannels) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateWrongChannels); -} - -TEST_F(MediaSessionTest, GingleBadInitiateNoPayloadTypes) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateNoPayloadTypes); -} - -TEST_F(MediaSessionTest, GingleBadInitiateDynamicWithoutNames) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateDynamicWithoutNames); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiate) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithBandwidth) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.video_bandwidth = 42000; - test->TestGoodOutgoingInitiate(options); -} - -// Crypto related tests. - -// Offer has crypto but the session is not secured, just ignore it. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoIsIgnoredWhenNotSecured) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto required but the session is not secure, fail. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoRequiredWhenNotSecured) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate(AddEncryption(kGingleInitiate, - kGingleRequiredCryptoOffer)); -} - -// Offer has no crypto but the session is secure required, fail. -TEST_F(MediaSessionTest, GingleInitiateWithNoCryptoFailsWhenSecureRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate(kGingleInitiate); -} - -// Offer has crypto and session is secure, expect crypto in the answer. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoWhenSecureEnabled) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto and session is secure required, expect crypto in -// the answer. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoWhenSecureRequired) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported crypto and session is secure, no crypto in -// the answer. -TEST_F(MediaSessionTest, GingleInitiateWithUnsupportedCrypto) { - rtc::scoped_ptr<buzz::XmlElement> elem; - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleUnsupportedCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported REQUIRED crypto and session is not secure, fail. -TEST_F(MediaSessionTest, GingleInitiateWithRequiredUnsupportedCrypto) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->TestBadIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is secure, fail. -TEST_F(MediaSessionTest, - GingleInitiateWithRequiredUnsupportedCryptoWhenSecure) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestBadIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is required secure, fail. -TEST_F(MediaSessionTest, - GingleInitiateWithRequiredUnsupportedCryptoWhenSecureRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->MakeSignalingSecure(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleRequiredUnsupportedCryptoOffer)); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithCrypto) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithCryptoRequired) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, GingleIncomingAcceptWithSsrcs) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - test->TestIncomingAcceptWithSsrcs(kGingleAcceptWithSsrcs, options); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithRtpData) { - rtc::scoped_ptr<MediaSessionClientTest> test(GingleTest()); - cricket::CallOptions options; - options.data_channel_type = cricket::DCT_RTP; - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(options); -} |