Update talk to 60094938.
Review URL: https://webrtc-codereview.appspot.com/7489005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5420 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
754de528b7
commit
a8910d2f88
@ -295,24 +295,24 @@ bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
|
|||||||
AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
|
AudioTrackVector audio_tracks = local_stream->GetAudioTracks();
|
||||||
for (AudioTrackVector::const_iterator it = audio_tracks.begin();
|
for (AudioTrackVector::const_iterator it = audio_tracks.begin();
|
||||||
it != audio_tracks.end(); ++it) {
|
it != audio_tracks.end(); ++it) {
|
||||||
TrackInfos::const_iterator track_info_it =
|
const TrackInfo* track_info = FindTrackInfo(local_audio_tracks_,
|
||||||
local_audio_tracks_.find((*it)->id());
|
local_stream->label(),
|
||||||
if (track_info_it != local_audio_tracks_.end()) {
|
(*it)->id());
|
||||||
const TrackInfo& info = track_info_it->second;
|
if (track_info) {
|
||||||
OnLocalTrackSeen(info.stream_label, info.track_id, info.ssrc,
|
OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
|
||||||
cricket::MEDIA_TYPE_AUDIO);
|
track_info->ssrc, cricket::MEDIA_TYPE_AUDIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoTrackVector video_tracks = local_stream->GetVideoTracks();
|
VideoTrackVector video_tracks = local_stream->GetVideoTracks();
|
||||||
for (VideoTrackVector::const_iterator it = video_tracks.begin();
|
for (VideoTrackVector::const_iterator it = video_tracks.begin();
|
||||||
it != video_tracks.end(); ++it) {
|
it != video_tracks.end(); ++it) {
|
||||||
TrackInfos::const_iterator track_info_it =
|
const TrackInfo* track_info = FindTrackInfo(local_video_tracks_,
|
||||||
local_video_tracks_.find((*it)->id());
|
local_stream->label(),
|
||||||
if (track_info_it != local_video_tracks_.end()) {
|
(*it)->id());
|
||||||
const TrackInfo& info = track_info_it->second;
|
if (track_info) {
|
||||||
OnLocalTrackSeen(info.stream_label, info.track_id, info.ssrc,
|
OnLocalTrackSeen(track_info->stream_label, track_info->track_id,
|
||||||
cricket::MEDIA_TYPE_VIDEO);
|
track_info->ssrc, cricket::MEDIA_TYPE_VIDEO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -321,6 +321,7 @@ bool MediaStreamSignaling::AddLocalStream(MediaStreamInterface* local_stream) {
|
|||||||
void MediaStreamSignaling::RemoveLocalStream(
|
void MediaStreamSignaling::RemoveLocalStream(
|
||||||
MediaStreamInterface* local_stream) {
|
MediaStreamInterface* local_stream) {
|
||||||
local_streams_->RemoveStream(local_stream);
|
local_streams_->RemoveStream(local_stream);
|
||||||
|
|
||||||
stream_observer_->OnRemoveLocalStream(local_stream);
|
stream_observer_->OnRemoveLocalStream(local_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,28 +475,6 @@ void MediaStreamSignaling::OnDataChannelClose() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaStreamSignaling::GetRemoteAudioTrackSsrc(
|
|
||||||
const std::string& track_id, uint32* ssrc) const {
|
|
||||||
TrackInfos::const_iterator it = remote_audio_tracks_.find(track_id);
|
|
||||||
if (it == remote_audio_tracks_.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ssrc = it->second.ssrc;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MediaStreamSignaling::GetRemoteVideoTrackSsrc(
|
|
||||||
const std::string& track_id, uint32* ssrc) const {
|
|
||||||
TrackInfos::const_iterator it = remote_video_tracks_.find(track_id);
|
|
||||||
if (it == remote_video_tracks_.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ssrc = it->second.ssrc;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaStreamSignaling::UpdateSessionOptions() {
|
void MediaStreamSignaling::UpdateSessionOptions() {
|
||||||
options_.streams.clear();
|
options_.streams.clear();
|
||||||
if (local_streams_ != NULL) {
|
if (local_streams_ != NULL) {
|
||||||
@ -554,12 +533,12 @@ void MediaStreamSignaling::UpdateRemoteStreamsList(
|
|||||||
// new StreamParam.
|
// new StreamParam.
|
||||||
TrackInfos::iterator track_it = current_tracks->begin();
|
TrackInfos::iterator track_it = current_tracks->begin();
|
||||||
while (track_it != current_tracks->end()) {
|
while (track_it != current_tracks->end()) {
|
||||||
TrackInfo info = track_it->second;
|
const TrackInfo& info = *track_it;
|
||||||
cricket::StreamParams params;
|
cricket::StreamParams params;
|
||||||
if (!cricket::GetStreamBySsrc(streams, info.ssrc, ¶ms) ||
|
if (!cricket::GetStreamBySsrc(streams, info.ssrc, ¶ms) ||
|
||||||
params.id != info.track_id) {
|
params.id != info.track_id) {
|
||||||
OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
|
OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
|
||||||
current_tracks->erase(track_it++);
|
track_it = current_tracks->erase(track_it);
|
||||||
} else {
|
} else {
|
||||||
++track_it;
|
++track_it;
|
||||||
}
|
}
|
||||||
@ -583,10 +562,10 @@ void MediaStreamSignaling::UpdateRemoteStreamsList(
|
|||||||
new_streams->AddStream(stream);
|
new_streams->AddStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackInfos::iterator track_it = current_tracks->find(track_id);
|
const TrackInfo* track_info = FindTrackInfo(*current_tracks, stream_label,
|
||||||
if (track_it == current_tracks->end()) {
|
track_id);
|
||||||
(*current_tracks)[track_id] =
|
if (!track_info) {
|
||||||
TrackInfo(stream_label, track_id, ssrc);
|
current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
|
||||||
OnRemoteTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
|
OnRemoteTrackSeen(stream_label, track_id, it->first_ssrc(), media_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -642,7 +621,7 @@ void MediaStreamSignaling::RejectRemoteTracks(cricket::MediaType media_type) {
|
|||||||
TrackInfos* current_tracks = GetRemoteTracks(media_type);
|
TrackInfos* current_tracks = GetRemoteTracks(media_type);
|
||||||
for (TrackInfos::iterator track_it = current_tracks->begin();
|
for (TrackInfos::iterator track_it = current_tracks->begin();
|
||||||
track_it != current_tracks->end(); ++track_it) {
|
track_it != current_tracks->end(); ++track_it) {
|
||||||
TrackInfo info = track_it->second;
|
const TrackInfo& info = *track_it;
|
||||||
MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
|
MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
|
||||||
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
||||||
AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
|
AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
|
||||||
@ -695,15 +674,16 @@ void MediaStreamSignaling::MaybeCreateDefaultStream() {
|
|||||||
}
|
}
|
||||||
if (remote_info_.default_audio_track_needed &&
|
if (remote_info_.default_audio_track_needed &&
|
||||||
default_remote_stream->GetAudioTracks().size() == 0) {
|
default_remote_stream->GetAudioTracks().size() == 0) {
|
||||||
remote_audio_tracks_[kDefaultAudioTrackLabel] =
|
remote_audio_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
|
||||||
TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0);
|
kDefaultAudioTrackLabel, 0));
|
||||||
|
|
||||||
OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
|
OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
|
||||||
cricket::MEDIA_TYPE_AUDIO);
|
cricket::MEDIA_TYPE_AUDIO);
|
||||||
}
|
}
|
||||||
if (remote_info_.default_video_track_needed &&
|
if (remote_info_.default_video_track_needed &&
|
||||||
default_remote_stream->GetVideoTracks().size() == 0) {
|
default_remote_stream->GetVideoTracks().size() == 0) {
|
||||||
remote_video_tracks_[kDefaultVideoTrackLabel] =
|
remote_video_tracks_.push_back(TrackInfo(kDefaultStreamLabel,
|
||||||
TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0);
|
kDefaultVideoTrackLabel, 0));
|
||||||
OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
|
OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
|
||||||
cricket::MEDIA_TYPE_VIDEO);
|
cricket::MEDIA_TYPE_VIDEO);
|
||||||
}
|
}
|
||||||
@ -736,16 +716,16 @@ void MediaStreamSignaling::UpdateLocalTracks(
|
|||||||
cricket::MediaType media_type) {
|
cricket::MediaType media_type) {
|
||||||
TrackInfos* current_tracks = GetLocalTracks(media_type);
|
TrackInfos* current_tracks = GetLocalTracks(media_type);
|
||||||
|
|
||||||
// Find removed tracks. Ie tracks where the track id or ssrc don't match the
|
// Find removed tracks. Ie tracks where the track id, stream label or ssrc
|
||||||
// new StreamParam.
|
// don't match the new StreamParam.
|
||||||
TrackInfos::iterator track_it = current_tracks->begin();
|
TrackInfos::iterator track_it = current_tracks->begin();
|
||||||
while (track_it != current_tracks->end()) {
|
while (track_it != current_tracks->end()) {
|
||||||
TrackInfo info = track_it->second;
|
const TrackInfo& info = *track_it;
|
||||||
cricket::StreamParams params;
|
cricket::StreamParams params;
|
||||||
if (!cricket::GetStreamBySsrc(streams, info.ssrc, ¶ms) ||
|
if (!cricket::GetStreamBySsrc(streams, info.ssrc, ¶ms) ||
|
||||||
params.id != info.track_id) {
|
params.id != info.track_id || params.sync_label != info.stream_label) {
|
||||||
OnLocalTrackRemoved(info.stream_label, info.track_id, media_type);
|
OnLocalTrackRemoved(info.stream_label, info.track_id, media_type);
|
||||||
current_tracks->erase(track_it++);
|
track_it = current_tracks->erase(track_it);
|
||||||
} else {
|
} else {
|
||||||
++track_it;
|
++track_it;
|
||||||
}
|
}
|
||||||
@ -759,10 +739,11 @@ void MediaStreamSignaling::UpdateLocalTracks(
|
|||||||
const std::string& stream_label = it->sync_label;
|
const std::string& stream_label = it->sync_label;
|
||||||
const std::string& track_id = it->id;
|
const std::string& track_id = it->id;
|
||||||
uint32 ssrc = it->first_ssrc();
|
uint32 ssrc = it->first_ssrc();
|
||||||
TrackInfos::iterator track_it = current_tracks->find(track_id);
|
const TrackInfo* track_info = FindTrackInfo(*current_tracks,
|
||||||
if (track_it == current_tracks->end()) {
|
stream_label,
|
||||||
(*current_tracks)[track_id] =
|
track_id);
|
||||||
TrackInfo(stream_label, track_id, ssrc);
|
if (!track_info) {
|
||||||
|
current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
|
||||||
OnLocalTrackSeen(stream_label, track_id, it->first_ssrc(),
|
OnLocalTrackSeen(stream_label, track_id, it->first_ssrc(),
|
||||||
media_type);
|
media_type);
|
||||||
}
|
}
|
||||||
@ -948,4 +929,18 @@ void MediaStreamSignaling::OnDtlsRoleReadyForSctp(talk_base::SSLRole role) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MediaStreamSignaling::TrackInfo*
|
||||||
|
MediaStreamSignaling::FindTrackInfo(
|
||||||
|
const MediaStreamSignaling::TrackInfos& infos,
|
||||||
|
const std::string& stream_label,
|
||||||
|
const std::string track_id) const {
|
||||||
|
|
||||||
|
for (TrackInfos::const_iterator it = infos.begin();
|
||||||
|
it != infos.end(); ++it) {
|
||||||
|
if (it->stream_label == stream_label && it->track_id == track_id)
|
||||||
|
return &*it;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -238,10 +238,6 @@ class MediaStreamSignaling {
|
|||||||
// Called when the data channel closes.
|
// Called when the data channel closes.
|
||||||
void OnDataChannelClose();
|
void OnDataChannelClose();
|
||||||
|
|
||||||
// Returns the SSRC for a given track.
|
|
||||||
bool GetRemoteAudioTrackSsrc(const std::string& track_id, uint32* ssrc) const;
|
|
||||||
bool GetRemoteVideoTrackSsrc(const std::string& track_id, uint32* ssrc) const;
|
|
||||||
|
|
||||||
// Returns all current known local MediaStreams.
|
// Returns all current known local MediaStreams.
|
||||||
StreamCollectionInterface* local_streams() const { return local_streams_;}
|
StreamCollectionInterface* local_streams() const { return local_streams_;}
|
||||||
|
|
||||||
@ -287,7 +283,7 @@ class MediaStreamSignaling {
|
|||||||
std::string track_id;
|
std::string track_id;
|
||||||
uint32 ssrc;
|
uint32 ssrc;
|
||||||
};
|
};
|
||||||
typedef std::map<std::string, TrackInfo> TrackInfos;
|
typedef std::vector<TrackInfo> TrackInfos;
|
||||||
|
|
||||||
void UpdateSessionOptions();
|
void UpdateSessionOptions();
|
||||||
|
|
||||||
@ -366,6 +362,10 @@ class MediaStreamSignaling {
|
|||||||
const std::vector<std::string>& active_channels, bool is_local_update);
|
const std::vector<std::string>& active_channels, bool is_local_update);
|
||||||
void CreateRemoteDataChannel(const std::string& label, uint32 remote_ssrc);
|
void CreateRemoteDataChannel(const std::string& label, uint32 remote_ssrc);
|
||||||
|
|
||||||
|
const TrackInfo* FindTrackInfo(const TrackInfos& infos,
|
||||||
|
const std::string& stream_label,
|
||||||
|
const std::string track_id) const;
|
||||||
|
|
||||||
RemotePeerInfo remote_info_;
|
RemotePeerInfo remote_info_;
|
||||||
talk_base::Thread* signaling_thread_;
|
talk_base::Thread* signaling_thread_;
|
||||||
DataChannelFactory* data_channel_factory_;
|
DataChannelFactory* data_channel_factory_;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "talk/app/webrtc/audiotrack.h"
|
#include "talk/app/webrtc/audiotrack.h"
|
||||||
#include "talk/app/webrtc/mediastream.h"
|
#include "talk/app/webrtc/mediastream.h"
|
||||||
@ -383,31 +384,48 @@ class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
|
|||||||
std::string track_id;
|
std::string track_id;
|
||||||
uint32 ssrc;
|
uint32 ssrc;
|
||||||
};
|
};
|
||||||
typedef std::map<std::string, TrackInfo> TrackInfos;
|
typedef std::vector<TrackInfo> TrackInfos;
|
||||||
|
|
||||||
void AddTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
|
void AddTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
|
||||||
MediaStreamTrackInterface* track,
|
MediaStreamTrackInterface* track,
|
||||||
uint32 ssrc) {
|
uint32 ssrc) {
|
||||||
(*track_infos)[track->id()] = TrackInfo(stream->label(), track->id(),
|
(*track_infos).push_back(TrackInfo(stream->label(), track->id(),
|
||||||
ssrc);
|
ssrc));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
|
void RemoveTrack(TrackInfos* track_infos, MediaStreamInterface* stream,
|
||||||
MediaStreamTrackInterface* track) {
|
MediaStreamTrackInterface* track) {
|
||||||
TrackInfos::iterator it = track_infos->find(track->id());
|
for (TrackInfos::iterator it = track_infos->begin();
|
||||||
ASSERT_TRUE(it != track_infos->end());
|
it != track_infos->end(); ++it) {
|
||||||
ASSERT_EQ(it->second.stream_label, stream->label());
|
if (it->stream_label == stream->label() && it->track_id == track->id()) {
|
||||||
track_infos->erase(it);
|
track_infos->erase(it);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ADD_FAILURE();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TrackInfo* FindTrackInfo(const TrackInfos& infos,
|
||||||
|
const std::string& stream_label,
|
||||||
|
const std::string track_id) const {
|
||||||
|
for (TrackInfos::const_iterator it = infos.begin();
|
||||||
|
it != infos.end(); ++it) {
|
||||||
|
if (it->stream_label == stream_label && it->track_id == track_id)
|
||||||
|
return &*it;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VerifyTrack(const TrackInfos& track_infos,
|
void VerifyTrack(const TrackInfos& track_infos,
|
||||||
const std::string& stream_label,
|
const std::string& stream_label,
|
||||||
const std::string& track_id,
|
const std::string& track_id,
|
||||||
uint32 ssrc) {
|
uint32 ssrc) {
|
||||||
TrackInfos::const_iterator it = track_infos.find(track_id);
|
const TrackInfo* track_info = FindTrackInfo(track_infos,
|
||||||
ASSERT_TRUE(it != track_infos.end());
|
stream_label,
|
||||||
EXPECT_EQ(stream_label, it->second.stream_label);
|
track_id);
|
||||||
EXPECT_EQ(ssrc, it->second.ssrc);
|
ASSERT_TRUE(track_info != NULL);
|
||||||
|
EXPECT_EQ(ssrc, track_info->ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackInfos remote_audio_tracks_;
|
TrackInfos remote_audio_tracks_;
|
||||||
@ -1051,6 +1069,47 @@ TEST_F(MediaStreamSignalingTest, ChangeSsrcOnTrackInLocalSessionDescription) {
|
|||||||
observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 98);
|
observer_->VerifyLocalVideoTrack(kStreams[0], kVideoTracks[0], 98);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test that the correct MediaStreamSignalingObserver methods are called
|
||||||
|
// if a new session description is set with the same tracks but they are now
|
||||||
|
// sent on a another MediaStream.
|
||||||
|
TEST_F(MediaStreamSignalingTest, SignalSameTracksInSeparateMediaStream) {
|
||||||
|
talk_base::scoped_ptr<SessionDescriptionInterface> desc;
|
||||||
|
CreateSessionDescriptionAndReference(1, 1, desc.use());
|
||||||
|
|
||||||
|
signaling_->AddLocalStream(reference_collection_->at(0));
|
||||||
|
signaling_->OnLocalDescriptionChanged(desc.get());
|
||||||
|
EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
|
||||||
|
EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
|
||||||
|
|
||||||
|
std::string stream_label_0 = kStreams[0];
|
||||||
|
observer_->VerifyLocalAudioTrack(stream_label_0, kAudioTracks[0], 1);
|
||||||
|
observer_->VerifyLocalVideoTrack(stream_label_0, kVideoTracks[0], 2);
|
||||||
|
|
||||||
|
// Add a new MediaStream but with the same tracks as in the first stream.
|
||||||
|
std::string stream_label_1 = kStreams[1];
|
||||||
|
talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream_1(
|
||||||
|
webrtc::MediaStream::Create(kStreams[1]));
|
||||||
|
stream_1->AddTrack(reference_collection_->at(0)->GetVideoTracks()[0]);
|
||||||
|
stream_1->AddTrack(reference_collection_->at(0)->GetAudioTracks()[0]);
|
||||||
|
signaling_->AddLocalStream(stream_1);
|
||||||
|
|
||||||
|
// Replace msid in the original SDP.
|
||||||
|
std::string sdp;
|
||||||
|
desc->ToString(&sdp);
|
||||||
|
talk_base::replace_substrs(
|
||||||
|
kStreams[0], strlen(kStreams[0]), kStreams[1], strlen(kStreams[1]), &sdp);
|
||||||
|
|
||||||
|
talk_base::scoped_ptr<SessionDescriptionInterface> updated_desc(
|
||||||
|
webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer,
|
||||||
|
sdp, NULL));
|
||||||
|
|
||||||
|
signaling_->OnLocalDescriptionChanged(updated_desc.get());
|
||||||
|
observer_->VerifyLocalAudioTrack(kStreams[1], kAudioTracks[0], 1);
|
||||||
|
observer_->VerifyLocalVideoTrack(kStreams[1], kVideoTracks[0], 2);
|
||||||
|
EXPECT_EQ(1u, observer_->NumberOfLocalAudioTracks());
|
||||||
|
EXPECT_EQ(1u, observer_->NumberOfLocalVideoTracks());
|
||||||
|
}
|
||||||
|
|
||||||
// Verifies that an even SCTP id is allocated for SSL_CLIENT and an odd id for
|
// Verifies that an even SCTP id is allocated for SSL_CLIENT and an odd id for
|
||||||
// SSL_SERVER.
|
// SSL_SERVER.
|
||||||
TEST_F(MediaStreamSignalingTest, SctpIdAllocationBasedOnRole) {
|
TEST_F(MediaStreamSignalingTest, SctpIdAllocationBasedOnRole) {
|
||||||
|
@ -106,10 +106,10 @@ struct CreateVideoSourceParams : public talk_base::MessageData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct StartAecDumpParams : public talk_base::MessageData {
|
struct StartAecDumpParams : public talk_base::MessageData {
|
||||||
explicit StartAecDumpParams(FILE* aec_dump_file)
|
explicit StartAecDumpParams(talk_base::PlatformFile aec_dump_file)
|
||||||
: aec_dump_file(aec_dump_file) {
|
: aec_dump_file(aec_dump_file) {
|
||||||
}
|
}
|
||||||
FILE* aec_dump_file;
|
talk_base::PlatformFile aec_dump_file;
|
||||||
bool result;
|
bool result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ PeerConnectionFactory::CreateVideoSource_s(
|
|||||||
return VideoSourceProxy::Create(signaling_thread_, source);
|
return VideoSourceProxy::Create(signaling_thread_, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerConnectionFactory::StartAecDump_s(FILE* file) {
|
bool PeerConnectionFactory::StartAecDump_s(talk_base::PlatformFile file) {
|
||||||
return channel_manager_->StartAecDump(file);
|
return channel_manager_->StartAecDump(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +380,7 @@ scoped_refptr<AudioTrackInterface> PeerConnectionFactory::CreateAudioTrack(
|
|||||||
return AudioTrackProxy::Create(signaling_thread_, track);
|
return AudioTrackProxy::Create(signaling_thread_, track);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerConnectionFactory::StartAecDump(FILE* file) {
|
bool PeerConnectionFactory::StartAecDump(talk_base::PlatformFile file) {
|
||||||
StartAecDumpParams params(file);
|
StartAecDumpParams params(file);
|
||||||
signaling_thread_->Send(this, MSG_START_AEC_DUMP, ¶ms);
|
signaling_thread_->Send(this, MSG_START_AEC_DUMP, ¶ms);
|
||||||
return params.result;
|
return params.result;
|
||||||
|
@ -78,7 +78,7 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface,
|
|||||||
CreateAudioTrack(const std::string& id,
|
CreateAudioTrack(const std::string& id,
|
||||||
AudioSourceInterface* audio_source);
|
AudioSourceInterface* audio_source);
|
||||||
|
|
||||||
virtual bool StartAecDump(FILE* file);
|
virtual bool StartAecDump(talk_base::PlatformFile file);
|
||||||
|
|
||||||
virtual cricket::ChannelManager* channel_manager();
|
virtual cricket::ChannelManager* channel_manager();
|
||||||
virtual talk_base::Thread* signaling_thread();
|
virtual talk_base::Thread* signaling_thread();
|
||||||
@ -109,7 +109,7 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface,
|
|||||||
PortAllocatorFactoryInterface* allocator_factory,
|
PortAllocatorFactoryInterface* allocator_factory,
|
||||||
DTLSIdentityServiceInterface* dtls_identity_service,
|
DTLSIdentityServiceInterface* dtls_identity_service,
|
||||||
PeerConnectionObserver* observer);
|
PeerConnectionObserver* observer);
|
||||||
bool StartAecDump_s(FILE* file);
|
bool StartAecDump_s(talk_base::PlatformFile file);
|
||||||
|
|
||||||
// Implements talk_base::MessageHandler.
|
// Implements talk_base::MessageHandler.
|
||||||
void OnMessage(talk_base::Message* msg);
|
void OnMessage(talk_base::Message* msg);
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
#include "talk/app/webrtc/jsep.h"
|
#include "talk/app/webrtc/jsep.h"
|
||||||
#include "talk/app/webrtc/mediastreaminterface.h"
|
#include "talk/app/webrtc/mediastreaminterface.h"
|
||||||
#include "talk/app/webrtc/statstypes.h"
|
#include "talk/app/webrtc/statstypes.h"
|
||||||
|
#include "talk/base/fileutils.h"
|
||||||
#include "talk/base/socketaddress.h"
|
#include "talk/base/socketaddress.h"
|
||||||
|
|
||||||
namespace talk_base {
|
namespace talk_base {
|
||||||
@ -442,9 +443,10 @@ class PeerConnectionFactoryInterface : public talk_base::RefCountInterface {
|
|||||||
|
|
||||||
// Starts AEC dump using existing file. Takes ownership of |file| and passes
|
// Starts AEC dump using existing file. Takes ownership of |file| and passes
|
||||||
// it on to VoiceEngine (via other objects) immediately, which will take
|
// it on to VoiceEngine (via other objects) immediately, which will take
|
||||||
// the ownerhip.
|
// the ownerhip. If the operation fails, the file will be closed.
|
||||||
// TODO(grunell): Remove when Chromium has started to use AEC in each source.
|
// TODO(grunell): Remove when Chromium has started to use AEC in each source.
|
||||||
virtual bool StartAecDump(FILE* file) = 0;
|
// http://crbug.com/264611.
|
||||||
|
virtual bool StartAecDump(talk_base::PlatformFile file) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Dtor and ctor protected as objects shouldn't be created or deleted via
|
// Dtor and ctor protected as objects shouldn't be created or deleted via
|
||||||
|
@ -28,6 +28,9 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
// TODO(grunell): Remove io.h includes when Chromium has started
|
||||||
|
// to use AEC in each source. http://crbug.com/264611.
|
||||||
|
#include <io.h>
|
||||||
#include "talk/base/win32.h"
|
#include "talk/base/win32.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -294,4 +297,28 @@ bool CreateUniqueFile(Pathname& path, bool create_empty) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taken from Chromium's base/platform_file_*.cc.
|
||||||
|
// TODO(grunell): Remove when Chromium has started to use AEC in each source.
|
||||||
|
// http://crbug.com/264611.
|
||||||
|
FILE* FdopenPlatformFileForWriting(PlatformFile file) {
|
||||||
|
#if defined(WIN32)
|
||||||
|
if (file == kInvalidPlatformFileValue)
|
||||||
|
return NULL;
|
||||||
|
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(file), 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return NULL;
|
||||||
|
return _fdopen(fd, "w");
|
||||||
|
#else
|
||||||
|
return fdopen(file, "w");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClosePlatformFile(PlatformFile file) {
|
||||||
|
#if defined(WIN32)
|
||||||
|
return CloseHandle(file) != 0;
|
||||||
|
#else
|
||||||
|
return close(file);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace talk_base
|
} // namespace talk_base
|
||||||
|
@ -452,6 +452,21 @@ class FilesystemScope{
|
|||||||
// process).
|
// process).
|
||||||
bool CreateUniqueFile(Pathname& path, bool create_empty);
|
bool CreateUniqueFile(Pathname& path, bool create_empty);
|
||||||
|
|
||||||
|
// Taken from Chromium's base/platform_file.h.
|
||||||
|
// Don't use ClosePlatformFile to close a file opened with FdopenPlatformFile.
|
||||||
|
// Use fclose instead.
|
||||||
|
// TODO(grunell): Remove when Chromium has started to use AEC in each source.
|
||||||
|
// http://crbug.com/264611.
|
||||||
|
#if defined(WIN32)
|
||||||
|
typedef HANDLE PlatformFile;
|
||||||
|
const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
|
||||||
|
#elif defined(POSIX)
|
||||||
|
typedef int PlatformFile;
|
||||||
|
const PlatformFile kInvalidPlatformFileValue = -1;
|
||||||
|
#endif
|
||||||
|
FILE* FdopenPlatformFileForWriting(PlatformFile file);
|
||||||
|
bool ClosePlatformFile(PlatformFile file);
|
||||||
|
|
||||||
} // namespace talk_base
|
} // namespace talk_base
|
||||||
|
|
||||||
#endif // TALK_BASE_FILEUTILS_H_
|
#endif // TALK_BASE_FILEUTILS_H_
|
||||||
|
@ -509,6 +509,8 @@
|
|||||||
'xmpp/pubsub_task.h',
|
'xmpp/pubsub_task.h',
|
||||||
'xmpp/pubsubclient.cc',
|
'xmpp/pubsubclient.cc',
|
||||||
'xmpp/pubsubclient.h',
|
'xmpp/pubsubclient.h',
|
||||||
|
'xmpp/pubsubstateclient.cc',
|
||||||
|
'xmpp/pubsubstateclient.h',
|
||||||
'xmpp/pubsubtasks.cc',
|
'xmpp/pubsubtasks.cc',
|
||||||
'xmpp/pubsubtasks.h',
|
'xmpp/pubsubtasks.h',
|
||||||
'xmpp/receivetask.cc',
|
'xmpp/receivetask.cc',
|
||||||
|
@ -486,7 +486,7 @@ talk.App(env, name = "relayserver",
|
|||||||
"jingle",
|
"jingle",
|
||||||
],
|
],
|
||||||
srcs = [
|
srcs = [
|
||||||
"p2p/base/relayserver_main.cc",
|
"examples/relayserver/relayserver_main.cc",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
talk.App(env, name = "stunserver",
|
talk.App(env, name = "stunserver",
|
||||||
@ -494,7 +494,7 @@ talk.App(env, name = "stunserver",
|
|||||||
"jingle",
|
"jingle",
|
||||||
],
|
],
|
||||||
srcs = [
|
srcs = [
|
||||||
"p2p/base/stunserver_main.cc",
|
"examples/stunserver/stunserver_main.cc",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
talk.App(env, name = "turnserver",
|
talk.App(env, name = "turnserver",
|
||||||
@ -503,7 +503,7 @@ talk.App(env, name = "turnserver",
|
|||||||
"ssl",
|
"ssl",
|
||||||
],
|
],
|
||||||
srcs = [
|
srcs = [
|
||||||
"p2p/base/turnserver_main.cc",
|
"examples/turnserver/turnserver_main.cc",
|
||||||
],
|
],
|
||||||
libs = [
|
libs = [
|
||||||
"jingle",
|
"jingle",
|
||||||
|
@ -790,7 +790,7 @@ class FakeVoiceEngine : public FakeBaseEngine {
|
|||||||
|
|
||||||
bool SetLocalMonitor(bool enable) { return true; }
|
bool SetLocalMonitor(bool enable) { return true; }
|
||||||
|
|
||||||
bool StartAecDump(FILE* file) { return false; }
|
bool StartAecDump(talk_base::PlatformFile file) { return false; }
|
||||||
|
|
||||||
bool RegisterProcessor(uint32 ssrc, VoiceProcessor* voice_processor,
|
bool RegisterProcessor(uint32 ssrc, VoiceProcessor* voice_processor,
|
||||||
MediaProcessorDirection direction) {
|
MediaProcessorDirection direction) {
|
||||||
|
@ -133,7 +133,7 @@ class FileMediaEngine : public MediaEngineInterface {
|
|||||||
virtual bool FindVideoCodec(const VideoCodec& codec) { return true; }
|
virtual bool FindVideoCodec(const VideoCodec& codec) { return true; }
|
||||||
virtual void SetVoiceLogging(int min_sev, const char* filter) {}
|
virtual void SetVoiceLogging(int min_sev, const char* filter) {}
|
||||||
virtual void SetVideoLogging(int min_sev, const char* filter) {}
|
virtual void SetVideoLogging(int min_sev, const char* filter) {}
|
||||||
virtual bool StartAecDump(FILE* file) { return false; }
|
virtual bool StartAecDump(talk_base::PlatformFile) { return false; }
|
||||||
|
|
||||||
virtual bool RegisterVideoProcessor(VideoProcessor* processor) {
|
virtual bool RegisterVideoProcessor(VideoProcessor* processor) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/fileutils.h"
|
||||||
#include "talk/base/sigslotrepeater.h"
|
#include "talk/base/sigslotrepeater.h"
|
||||||
#include "talk/media/base/codec.h"
|
#include "talk/media/base/codec.h"
|
||||||
#include "talk/media/base/mediachannel.h"
|
#include "talk/media/base/mediachannel.h"
|
||||||
@ -136,7 +137,7 @@ class MediaEngineInterface {
|
|||||||
virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
|
virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
|
||||||
|
|
||||||
// Starts AEC dump using existing file.
|
// Starts AEC dump using existing file.
|
||||||
virtual bool StartAecDump(FILE* file) = 0;
|
virtual bool StartAecDump(talk_base::PlatformFile file) = 0;
|
||||||
|
|
||||||
// Voice processors for effects.
|
// Voice processors for effects.
|
||||||
virtual bool RegisterVoiceProcessor(uint32 ssrc,
|
virtual bool RegisterVoiceProcessor(uint32 ssrc,
|
||||||
@ -256,7 +257,7 @@ class CompositeMediaEngine : public MediaEngineInterface {
|
|||||||
video_.SetLogging(min_sev, filter);
|
video_.SetLogging(min_sev, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool StartAecDump(FILE* file) {
|
virtual bool StartAecDump(talk_base::PlatformFile file) {
|
||||||
return voice_.StartAecDump(file);
|
return voice_.StartAecDump(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +317,7 @@ class NullVoiceEngine {
|
|||||||
return rtp_header_extensions_;
|
return rtp_header_extensions_;
|
||||||
}
|
}
|
||||||
void SetLogging(int min_sev, const char* filter) {}
|
void SetLogging(int min_sev, const char* filter) {}
|
||||||
bool StartAecDump(FILE* file) { return false; }
|
bool StartAecDump(talk_base::PlatformFile file) { return false; }
|
||||||
bool RegisterProcessor(uint32 ssrc,
|
bool RegisterProcessor(uint32 ssrc,
|
||||||
VoiceProcessor* voice_processor,
|
VoiceProcessor* voice_processor,
|
||||||
MediaProcessorDirection direction) { return true; }
|
MediaProcessorDirection direction) { return true; }
|
||||||
|
@ -640,9 +640,7 @@ class FakeWebRtcVideoEngine
|
|||||||
}
|
}
|
||||||
WEBRTC_STUB(RegisterCpuOveruseObserver,
|
WEBRTC_STUB(RegisterCpuOveruseObserver,
|
||||||
(int channel, webrtc::CpuOveruseObserver* observer));
|
(int channel, webrtc::CpuOveruseObserver* observer));
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
WEBRTC_STUB(CpuOveruseMeasures, (int, int*, int*, int*, int*));
|
WEBRTC_STUB(CpuOveruseMeasures, (int, int*, int*, int*, int*));
|
||||||
#endif
|
|
||||||
WEBRTC_STUB(ConnectAudioChannel, (const int, const int));
|
WEBRTC_STUB(ConnectAudioChannel, (const int, const int));
|
||||||
WEBRTC_STUB(DisconnectAudioChannel, (const int));
|
WEBRTC_STUB(DisconnectAudioChannel, (const int));
|
||||||
WEBRTC_FUNC(StartSend, (const int channel)) {
|
WEBRTC_FUNC(StartSend, (const int channel)) {
|
||||||
@ -827,12 +825,8 @@ class FakeWebRtcVideoEngine
|
|||||||
}
|
}
|
||||||
WEBRTC_STUB(RegisterSendTransport, (const int, webrtc::Transport&));
|
WEBRTC_STUB(RegisterSendTransport, (const int, webrtc::Transport&));
|
||||||
WEBRTC_STUB(DeregisterSendTransport, (const int));
|
WEBRTC_STUB(DeregisterSendTransport, (const int));
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
WEBRTC_STUB(ReceivedRTPPacket, (const int, const void*, const int,
|
WEBRTC_STUB(ReceivedRTPPacket, (const int, const void*, const int,
|
||||||
const webrtc::PacketTime&));
|
const webrtc::PacketTime&));
|
||||||
#else
|
|
||||||
WEBRTC_STUB(ReceivedRTPPacket, (const int, const void*, const int));
|
|
||||||
#endif
|
|
||||||
WEBRTC_STUB(ReceivedRTCPPacket, (const int, const void*, const int));
|
WEBRTC_STUB(ReceivedRTCPPacket, (const int, const void*, const int));
|
||||||
// Not using WEBRTC_STUB due to bool return value
|
// Not using WEBRTC_STUB due to bool return value
|
||||||
virtual bool IsIPv6Enabled(int channel) { return true; }
|
virtual bool IsIPv6Enabled(int channel) { return true; }
|
||||||
@ -1040,9 +1034,7 @@ class FakeWebRtcVideoEngine
|
|||||||
channels_[channel]->rtp_absolute_send_time_receive_id_ = (enable) ? id : 0;
|
channels_[channel]->rtp_absolute_send_time_receive_id_ = (enable) ? id : 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
WEBRTC_STUB(SetRtcpXrRrtrStatus, (int, bool));
|
WEBRTC_STUB(SetRtcpXrRrtrStatus, (int, bool));
|
||||||
#endif
|
|
||||||
WEBRTC_FUNC(SetTransmissionSmoothingStatus, (int channel, bool enable)) {
|
WEBRTC_FUNC(SetTransmissionSmoothingStatus, (int channel, bool enable)) {
|
||||||
WEBRTC_CHECK_CHANNEL(channel);
|
WEBRTC_CHECK_CHANNEL(channel);
|
||||||
channels_[channel]->transmission_smoothing_ = enable;
|
channels_[channel]->transmission_smoothing_ = enable;
|
||||||
|
@ -631,13 +631,11 @@ class FakeWebRtcVoiceEngine
|
|||||||
|
|
||||||
// webrtc::VoENetEqStats
|
// webrtc::VoENetEqStats
|
||||||
WEBRTC_STUB(GetNetworkStatistics, (int, webrtc::NetworkStatistics&));
|
WEBRTC_STUB(GetNetworkStatistics, (int, webrtc::NetworkStatistics&));
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel,
|
WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel,
|
||||||
webrtc::AudioDecodingCallStats*)) {
|
webrtc::AudioDecodingCallStats*)) {
|
||||||
WEBRTC_CHECK_CHANNEL(channel);
|
WEBRTC_CHECK_CHANNEL(channel);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// webrtc::VoENetwork
|
// webrtc::VoENetwork
|
||||||
WEBRTC_FUNC(RegisterExternalTransport, (int channel,
|
WEBRTC_FUNC(RegisterExternalTransport, (int channel,
|
||||||
@ -923,9 +921,7 @@ class FakeWebRtcVoiceEngine
|
|||||||
WEBRTC_STUB(GetEcDelayMetrics, (int& delay_median, int& delay_std));
|
WEBRTC_STUB(GetEcDelayMetrics, (int& delay_median, int& delay_std));
|
||||||
|
|
||||||
WEBRTC_STUB(StartDebugRecording, (const char* fileNameUTF8));
|
WEBRTC_STUB(StartDebugRecording, (const char* fileNameUTF8));
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
WEBRTC_STUB(StartDebugRecording, (FILE* handle));
|
WEBRTC_STUB(StartDebugRecording, (FILE* handle));
|
||||||
#endif
|
|
||||||
WEBRTC_STUB(StopDebugRecording, ());
|
WEBRTC_STUB(StopDebugRecording, ());
|
||||||
|
|
||||||
WEBRTC_FUNC(SetTypingDetectionStatus, (bool enable)) {
|
WEBRTC_FUNC(SetTypingDetectionStatus, (bool enable)) {
|
||||||
|
@ -145,7 +145,7 @@ class WebRtcMediaEngine : public cricket::MediaEngineInterface {
|
|||||||
virtual void SetVideoLogging(int min_sev, const char* filter) OVERRIDE {
|
virtual void SetVideoLogging(int min_sev, const char* filter) OVERRIDE {
|
||||||
delegate_->SetVideoLogging(min_sev, filter);
|
delegate_->SetVideoLogging(min_sev, filter);
|
||||||
}
|
}
|
||||||
virtual bool StartAecDump(FILE* file) OVERRIDE {
|
virtual bool StartAecDump(talk_base::PlatformFile file) OVERRIDE {
|
||||||
return delegate_->StartAecDump(file);
|
return delegate_->StartAecDump(file);
|
||||||
}
|
}
|
||||||
virtual bool RegisterVoiceProcessor(
|
virtual bool RegisterVoiceProcessor(
|
||||||
|
@ -2300,7 +2300,6 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
|
|||||||
sinfo.encode_usage_percent = -1;
|
sinfo.encode_usage_percent = -1;
|
||||||
sinfo.capture_queue_delay_ms_per_s = -1;
|
sinfo.capture_queue_delay_ms_per_s = -1;
|
||||||
|
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
int capture_jitter_ms = 0;
|
int capture_jitter_ms = 0;
|
||||||
int avg_encode_time_ms = 0;
|
int avg_encode_time_ms = 0;
|
||||||
int encode_usage_percent = 0;
|
int encode_usage_percent = 0;
|
||||||
@ -2316,7 +2315,6 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
|
|||||||
sinfo.encode_usage_percent = encode_usage_percent;
|
sinfo.encode_usage_percent = encode_usage_percent;
|
||||||
sinfo.capture_queue_delay_ms_per_s = capture_queue_delay_ms_per_s;
|
sinfo.capture_queue_delay_ms_per_s = capture_queue_delay_ms_per_s;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Get received RTCP statistics for the sender (reported by the remote
|
// Get received RTCP statistics for the sender (reported by the remote
|
||||||
// client in a RTCP packet), if available.
|
// client in a RTCP packet), if available.
|
||||||
@ -2465,9 +2463,7 @@ bool WebRtcVideoMediaChannel::SetCapturer(uint32 ssrc,
|
|||||||
MaybeDisconnectCapturer(old_capturer);
|
MaybeDisconnectCapturer(old_capturer);
|
||||||
|
|
||||||
send_channel->set_video_capturer(capturer);
|
send_channel->set_video_capturer(capturer);
|
||||||
capturer->SignalVideoFrame.connect(
|
MaybeConnectCapturer(capturer);
|
||||||
this,
|
|
||||||
&WebRtcVideoMediaChannel::SendFrame);
|
|
||||||
if (!capturer->IsScreencast() && ratio_w_ != 0 && ratio_h_ != 0) {
|
if (!capturer->IsScreencast() && ratio_w_ != 0 && ratio_h_ != 0) {
|
||||||
capturer->UpdateAspectRatio(ratio_w_, ratio_h_);
|
capturer->UpdateAspectRatio(ratio_w_, ratio_h_);
|
||||||
}
|
}
|
||||||
@ -2500,12 +2496,8 @@ void WebRtcVideoMediaChannel::OnPacketReceived(
|
|||||||
engine()->vie()->network()->ReceivedRTPPacket(
|
engine()->vie()->network()->ReceivedRTPPacket(
|
||||||
which_channel,
|
which_channel,
|
||||||
packet->data(),
|
packet->data(),
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
static_cast<int>(packet->length()),
|
static_cast<int>(packet->length()),
|
||||||
webrtc::PacketTime(packet_time.timestamp, packet_time.not_before));
|
webrtc::PacketTime(packet_time.timestamp, packet_time.not_before));
|
||||||
#else
|
|
||||||
static_cast<int>(packet->length()));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcVideoMediaChannel::OnRtcpReceived(
|
void WebRtcVideoMediaChannel::OnRtcpReceived(
|
||||||
|
@ -1274,11 +1274,7 @@ TEST_F(WebRtcVideoEngineTestFake, SetOptionsWithDenoising) {
|
|||||||
EXPECT_FALSE(vie_.GetCaptureDenoising(capture_id));
|
EXPECT_FALSE(vie_.GetCaptureDenoising(capture_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test disabled because it drops frames when adapt-before-effects is turned
|
TEST_F(WebRtcVideoEngineTestFake, MultipleSendStreamsWithOneCapturer) {
|
||||||
// off (turned off because it was exposing a crash - see bug 12250150). This is
|
|
||||||
// safe for now because this test exercises an unused feature.
|
|
||||||
// TODO(tpsiaki) reenable once adapt-before-effects is turned back on.
|
|
||||||
TEST_F(WebRtcVideoEngineTestFake, DISABLED_MultipleSendStreamsWithOneCapturer) {
|
|
||||||
EXPECT_TRUE(SetupEngine());
|
EXPECT_TRUE(SetupEngine());
|
||||||
|
|
||||||
// Start the capturer
|
// Start the capturer
|
||||||
|
@ -1433,20 +1433,23 @@ bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebRtcVoiceEngine::StartAecDump(FILE* file) {
|
bool WebRtcVoiceEngine::StartAecDump(talk_base::PlatformFile file) {
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
FILE* aec_dump_file_stream = talk_base::FdopenPlatformFileForWriting(file);
|
||||||
|
if (!aec_dump_file_stream) {
|
||||||
|
LOG(LS_ERROR) << "Could not open AEC dump file stream.";
|
||||||
|
if (!talk_base::ClosePlatformFile(file))
|
||||||
|
LOG(LS_WARNING) << "Could not close file.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
StopAecDump();
|
StopAecDump();
|
||||||
if (voe_wrapper_->processing()->StartDebugRecording(file) !=
|
if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) !=
|
||||||
webrtc::AudioProcessing::kNoError) {
|
webrtc::AudioProcessing::kNoError) {
|
||||||
LOG_RTCERR1(StartDebugRecording, "FILE*");
|
LOG_RTCERR0(StartDebugRecording);
|
||||||
fclose(file);
|
fclose(aec_dump_file_stream);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
is_dumping_aec_ = true;
|
is_dumping_aec_ = true;
|
||||||
return true;
|
return true;
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebRtcVoiceEngine::RegisterProcessor(
|
bool WebRtcVoiceEngine::RegisterProcessor(
|
||||||
|
@ -175,7 +175,7 @@ class WebRtcVoiceEngine
|
|||||||
webrtc::AudioDeviceModule* adm_sc);
|
webrtc::AudioDeviceModule* adm_sc);
|
||||||
|
|
||||||
// Starts AEC dump using existing file.
|
// Starts AEC dump using existing file.
|
||||||
bool StartAecDump(FILE* file);
|
bool StartAecDump(talk_base::PlatformFile file);
|
||||||
|
|
||||||
// Check whether the supplied trace should be ignored.
|
// Check whether the supplied trace should be ignored.
|
||||||
bool ShouldIgnoreTrace(const std::string& trace);
|
bool ShouldIgnoreTrace(const std::string& trace);
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
#if defined(POSIX)
|
||||||
|
#include <dirent.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "talk/base/asynctcpsocket.h"
|
#include "talk/base/asynctcpsocket.h"
|
||||||
#include "talk/base/buffer.h"
|
#include "talk/base/buffer.h"
|
||||||
@ -71,7 +74,7 @@ static const char kIcePwd1[] = "TESTICEPWD00000000000001";
|
|||||||
static const char kIcePwd2[] = "TESTICEPWD00000000000002";
|
static const char kIcePwd2[] = "TESTICEPWD00000000000002";
|
||||||
static const char kTurnUsername[] = "test";
|
static const char kTurnUsername[] = "test";
|
||||||
static const char kTurnPassword[] = "test";
|
static const char kTurnPassword[] = "test";
|
||||||
static const int kTimeout = 1000;
|
static const unsigned int kTimeout = 1000;
|
||||||
|
|
||||||
static const cricket::ProtocolAddress kTurnUdpProtoAddr(
|
static const cricket::ProtocolAddress kTurnUdpProtoAddr(
|
||||||
kTurnUdpIntAddr, cricket::PROTO_UDP);
|
kTurnUdpIntAddr, cricket::PROTO_UDP);
|
||||||
@ -80,8 +83,26 @@ static const cricket::ProtocolAddress kTurnTcpProtoAddr(
|
|||||||
static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(
|
static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(
|
||||||
kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
|
kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
|
||||||
|
|
||||||
|
static const unsigned int MSG_TESTFINISH = 0;
|
||||||
|
|
||||||
|
#if defined(LINUX)
|
||||||
|
static int GetFDCount() {
|
||||||
|
struct dirent *dp;
|
||||||
|
int fd_count = 0;
|
||||||
|
DIR *dir = opendir("/proc/self/fd/");
|
||||||
|
while ((dp = readdir(dir)) != NULL) {
|
||||||
|
if (dp->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
++fd_count;
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
return fd_count;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class TurnPortTest : public testing::Test,
|
class TurnPortTest : public testing::Test,
|
||||||
public sigslot::has_slots<> {
|
public sigslot::has_slots<>,
|
||||||
|
public talk_base::MessageHandler {
|
||||||
public:
|
public:
|
||||||
TurnPortTest()
|
TurnPortTest()
|
||||||
: main_(talk_base::Thread::Current()),
|
: main_(talk_base::Thread::Current()),
|
||||||
@ -95,10 +116,17 @@ class TurnPortTest : public testing::Test,
|
|||||||
turn_error_(false),
|
turn_error_(false),
|
||||||
turn_unknown_address_(false),
|
turn_unknown_address_(false),
|
||||||
turn_create_permission_success_(false),
|
turn_create_permission_success_(false),
|
||||||
udp_ready_(false) {
|
udp_ready_(false),
|
||||||
|
test_finish_(false) {
|
||||||
network_.AddIP(talk_base::IPAddress(INADDR_ANY));
|
network_.AddIP(talk_base::IPAddress(INADDR_ANY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void OnMessage(talk_base::Message* msg) {
|
||||||
|
ASSERT(msg->message_id == MSG_TESTFINISH);
|
||||||
|
if (msg->message_id == MSG_TESTFINISH)
|
||||||
|
test_finish_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
void OnTurnPortComplete(Port* port) {
|
void OnTurnPortComplete(Port* port) {
|
||||||
turn_ready_ = true;
|
turn_ready_ = true;
|
||||||
}
|
}
|
||||||
@ -264,6 +292,7 @@ class TurnPortTest : public testing::Test,
|
|||||||
bool turn_unknown_address_;
|
bool turn_unknown_address_;
|
||||||
bool turn_create_permission_success_;
|
bool turn_create_permission_success_;
|
||||||
bool udp_ready_;
|
bool udp_ready_;
|
||||||
|
bool test_finish_;
|
||||||
std::vector<talk_base::Buffer> turn_packets_;
|
std::vector<talk_base::Buffer> turn_packets_;
|
||||||
std::vector<talk_base::Buffer> udp_packets_;
|
std::vector<talk_base::Buffer> udp_packets_;
|
||||||
};
|
};
|
||||||
@ -378,3 +407,24 @@ TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) {
|
|||||||
EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
|
EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test verifies any FD's are not leaked after TurnPort is destroyed.
|
||||||
|
// https://code.google.com/p/webrtc/issues/detail?id=2651
|
||||||
|
#if defined(LINUX)
|
||||||
|
TEST_F(TurnPortTest, TestResolverShutdown) {
|
||||||
|
turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
|
||||||
|
int last_fd_count = GetFDCount();
|
||||||
|
// Need to supply unresolved address to kick off resolver.
|
||||||
|
CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
|
||||||
|
cricket::ProtocolAddress(talk_base::SocketAddress(
|
||||||
|
"stun.l.google.com", 3478), cricket::PROTO_UDP));
|
||||||
|
turn_port_->PrepareAddress();
|
||||||
|
ASSERT_TRUE_WAIT(turn_error_, kTimeout);
|
||||||
|
EXPECT_TRUE(turn_port_->Candidates().empty());
|
||||||
|
turn_port_.reset();
|
||||||
|
talk_base::Thread::Current()->Post(this, MSG_TESTFINISH);
|
||||||
|
// Waiting for above message to be processed.
|
||||||
|
ASSERT_TRUE_WAIT(test_finish_, kTimeout);
|
||||||
|
EXPECT_EQ(last_fd_count, GetFDCount());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@ -947,7 +947,7 @@ bool ChannelManager::SetAudioOptions(const AudioOptions& options) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelManager::StartAecDump(FILE* file) {
|
bool ChannelManager::StartAecDump(talk_base::PlatformFile file) {
|
||||||
return worker_thread_->Invoke<bool>(
|
return worker_thread_->Invoke<bool>(
|
||||||
Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
|
Bind(&MediaEngineInterface::StartAecDump, media_engine_.get(), file));
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "talk/base/criticalsection.h"
|
#include "talk/base/criticalsection.h"
|
||||||
|
#include "talk/base/fileutils.h"
|
||||||
#include "talk/base/sigslotrepeater.h"
|
#include "talk/base/sigslotrepeater.h"
|
||||||
#include "talk/base/thread.h"
|
#include "talk/base/thread.h"
|
||||||
#include "talk/media/base/capturemanager.h"
|
#include "talk/media/base/capturemanager.h"
|
||||||
@ -215,7 +216,7 @@ class ChannelManager : public talk_base::MessageHandler,
|
|||||||
const VideoFormat& max_format);
|
const VideoFormat& max_format);
|
||||||
|
|
||||||
// Starts AEC dump using existing file.
|
// Starts AEC dump using existing file.
|
||||||
bool StartAecDump(FILE* file);
|
bool StartAecDump(talk_base::PlatformFile file);
|
||||||
|
|
||||||
sigslot::repeater0<> SignalDevicesChange;
|
sigslot::repeater0<> SignalDevicesChange;
|
||||||
sigslot::signal2<VideoCapturer*, CaptureState> SignalVideoCaptureStateChange;
|
sigslot::signal2<VideoCapturer*, CaptureState> SignalVideoCaptureStateChange;
|
||||||
|
@ -44,54 +44,8 @@ const char kPresenting[] = "s";
|
|||||||
const char kNotPresenting[] = "o";
|
const char kNotPresenting[] = "o";
|
||||||
const char kEmpty[] = "";
|
const char kEmpty[] = "";
|
||||||
|
|
||||||
const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem) {
|
|
||||||
if (item_elem == NULL) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
// Knows how to handle specific states and XML.
|
|
||||||
template <typename C>
|
|
||||||
class PubSubStateSerializer {
|
|
||||||
public:
|
|
||||||
virtual ~PubSubStateSerializer() {}
|
|
||||||
virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
|
|
||||||
virtual C Parse(const XmlElement* state_elem) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Knows how to create "keys" for states, which determines their
|
|
||||||
// uniqueness. Most states are per-nick, but block is
|
|
||||||
// per-blocker-and-blockee. This is independent of itemid, especially
|
|
||||||
// in the case of presenter state.
|
|
||||||
class PubSubStateKeySerializer {
|
|
||||||
public:
|
|
||||||
virtual ~PubSubStateKeySerializer() {}
|
|
||||||
virtual std::string GetKey(const std::string& publisher_nick,
|
|
||||||
const std::string& published_nick) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PublishedNickKeySerializer : public PubSubStateKeySerializer {
|
|
||||||
public:
|
|
||||||
virtual std::string GetKey(const std::string& publisher_nick,
|
|
||||||
const std::string& published_nick) {
|
|
||||||
return published_nick;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PublisherAndPublishedNicksKeySerializer
|
|
||||||
: public PubSubStateKeySerializer {
|
|
||||||
public:
|
|
||||||
virtual std::string GetKey(const std::string& publisher_nick,
|
|
||||||
const std::string& published_nick) {
|
|
||||||
return publisher_nick + ":" + published_nick;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// A simple serialiazer where presence of item => true, lack of item
|
// A simple serialiazer where presence of item => true, lack of item
|
||||||
// => false.
|
// => false.
|
||||||
class BoolStateSerializer : public PubSubStateSerializer<bool> {
|
class BoolStateSerializer : public PubSubStateSerializer<bool> {
|
||||||
@ -103,195 +57,11 @@ class BoolStateSerializer : public PubSubStateSerializer<bool> {
|
|||||||
return new XmlElement(state_name, true);
|
return new XmlElement(state_name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool Parse(const XmlElement* state_elem) {
|
virtual void Parse(const XmlElement* state_elem, bool *state_out) {
|
||||||
return state_elem != NULL;
|
*state_out = state_elem != NULL;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Adapts PubSubClient to be specifically suited for pub sub call
|
|
||||||
// states. Signals state changes and keeps track of keys, which are
|
|
||||||
// normally nicks.
|
|
||||||
// TODO: Expose this as a generally useful class, not just
|
|
||||||
// private to hangouts.
|
|
||||||
template <typename C>
|
|
||||||
class PubSubStateClient : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
// Gets ownership of the serializers, but not the client.
|
|
||||||
PubSubStateClient(const std::string& publisher_nick,
|
|
||||||
PubSubClient* client,
|
|
||||||
const QName& state_name,
|
|
||||||
C default_state,
|
|
||||||
PubSubStateKeySerializer* key_serializer,
|
|
||||||
PubSubStateSerializer<C>* state_serializer)
|
|
||||||
: publisher_nick_(publisher_nick),
|
|
||||||
client_(client),
|
|
||||||
state_name_(state_name),
|
|
||||||
default_state_(default_state) {
|
|
||||||
key_serializer_.reset(key_serializer);
|
|
||||||
state_serializer_.reset(state_serializer);
|
|
||||||
client_->SignalItems.connect(
|
|
||||||
this, &PubSubStateClient<C>::OnItems);
|
|
||||||
client_->SignalPublishResult.connect(
|
|
||||||
this, &PubSubStateClient<C>::OnPublishResult);
|
|
||||||
client_->SignalPublishError.connect(
|
|
||||||
this, &PubSubStateClient<C>::OnPublishError);
|
|
||||||
client_->SignalRetractResult.connect(
|
|
||||||
this, &PubSubStateClient<C>::OnRetractResult);
|
|
||||||
client_->SignalRetractError.connect(
|
|
||||||
this, &PubSubStateClient<C>::OnRetractError);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~PubSubStateClient() {}
|
|
||||||
|
|
||||||
virtual void Publish(const std::string& published_nick,
|
|
||||||
const C& state,
|
|
||||||
std::string* task_id_out) {
|
|
||||||
std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
|
|
||||||
std::string itemid = state_name_.LocalPart() + ":" + key;
|
|
||||||
if (StatesEqual(state, default_state_)) {
|
|
||||||
client_->RetractItem(itemid, task_id_out);
|
|
||||||
} else {
|
|
||||||
XmlElement* state_elem = state_serializer_->Write(state_name_, state);
|
|
||||||
state_elem->AddAttr(QN_NICK, published_nick);
|
|
||||||
client_->PublishItem(itemid, state_elem, task_id_out);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
|
|
||||||
// Signal (task_id, item). item is NULL for retract.
|
|
||||||
sigslot::signal2<const std::string&,
|
|
||||||
const XmlElement*> SignalPublishResult;
|
|
||||||
// Signal (task_id, item, error stanza). item is NULL for retract.
|
|
||||||
sigslot::signal3<const std::string&,
|
|
||||||
const XmlElement*,
|
|
||||||
const XmlElement*> SignalPublishError;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// return false if retracted item (no info or state given)
|
|
||||||
virtual bool ParseStateItem(const PubSubItem& item,
|
|
||||||
StateItemInfo* info_out,
|
|
||||||
bool* state_out) {
|
|
||||||
const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
|
|
||||||
if (state_elem == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
info_out->publisher_nick = GetPublisherNickFromPubSubItem(item.elem);
|
|
||||||
info_out->published_nick = state_elem->Attr(QN_NICK);
|
|
||||||
*state_out = state_serializer_->Parse(state_elem);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual bool StatesEqual(C state1, C state2) {
|
|
||||||
return state1 == state2;
|
|
||||||
}
|
|
||||||
|
|
||||||
PubSubClient* client() { return client_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnItems(PubSubClient* pub_sub_client,
|
|
||||||
const std::vector<PubSubItem>& items) {
|
|
||||||
for (std::vector<PubSubItem>::const_iterator item = items.begin();
|
|
||||||
item != items.end(); ++item) {
|
|
||||||
OnItem(*item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnItem(const PubSubItem& item) {
|
|
||||||
const std::string& itemid = item.itemid;
|
|
||||||
StateItemInfo info;
|
|
||||||
C new_state;
|
|
||||||
|
|
||||||
bool retracted = !ParseStateItem(item, &info, &new_state);
|
|
||||||
if (retracted) {
|
|
||||||
bool known_itemid =
|
|
||||||
(info_by_itemid_.find(itemid) != info_by_itemid_.end());
|
|
||||||
if (!known_itemid) {
|
|
||||||
// Nothing to retract, and nothing to publish.
|
|
||||||
// Probably a different state type.
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
info = info_by_itemid_[itemid];
|
|
||||||
info_by_itemid_.erase(itemid);
|
|
||||||
new_state = default_state_;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: Assert new key matches the known key. It
|
|
||||||
// shouldn't change!
|
|
||||||
info_by_itemid_[itemid] = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string key = key_serializer_->GetKey(
|
|
||||||
info.publisher_nick, info.published_nick);
|
|
||||||
bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
|
|
||||||
C old_state = has_old_state ? state_by_key_[key] : default_state_;
|
|
||||||
if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
|
|
||||||
// Nothing change, so don't bother signalling.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retracted || StatesEqual(new_state, default_state_)) {
|
|
||||||
// We treat a default state similar to a retract.
|
|
||||||
state_by_key_.erase(key);
|
|
||||||
} else {
|
|
||||||
state_by_key_[key] = new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
PubSubStateChange<C> change;
|
|
||||||
if (!retracted) {
|
|
||||||
// Retracts do not have publisher information.
|
|
||||||
change.publisher_nick = info.publisher_nick;
|
|
||||||
}
|
|
||||||
change.published_nick = info.published_nick;
|
|
||||||
change.old_state = old_state;
|
|
||||||
change.new_state = new_state;
|
|
||||||
SignalStateChange(change);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPublishResult(PubSubClient* pub_sub_client,
|
|
||||||
const std::string& task_id,
|
|
||||||
const XmlElement* item) {
|
|
||||||
SignalPublishResult(task_id, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPublishError(PubSubClient* pub_sub_client,
|
|
||||||
const std::string& task_id,
|
|
||||||
const buzz::XmlElement* item,
|
|
||||||
const buzz::XmlElement* stanza) {
|
|
||||||
SignalPublishError(task_id, item, stanza);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnRetractResult(PubSubClient* pub_sub_client,
|
|
||||||
const std::string& task_id) {
|
|
||||||
// There's no point in differentiating between publish and retract
|
|
||||||
// errors, so we simplify by making them both signal a publish
|
|
||||||
// result.
|
|
||||||
const XmlElement* item = NULL;
|
|
||||||
SignalPublishResult(task_id, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnRetractError(PubSubClient* pub_sub_client,
|
|
||||||
const std::string& task_id,
|
|
||||||
const buzz::XmlElement* stanza) {
|
|
||||||
// There's no point in differentiating between publish and retract
|
|
||||||
// errors, so we simplify by making them both signal a publish
|
|
||||||
// error.
|
|
||||||
const XmlElement* item = NULL;
|
|
||||||
SignalPublishError(task_id, item, stanza);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string publisher_nick_;
|
|
||||||
PubSubClient* client_;
|
|
||||||
const QName state_name_;
|
|
||||||
C default_state_;
|
|
||||||
talk_base::scoped_ptr<PubSubStateKeySerializer> key_serializer_;
|
|
||||||
talk_base::scoped_ptr<PubSubStateSerializer<C> > state_serializer_;
|
|
||||||
// key => state
|
|
||||||
std::map<std::string, C> state_by_key_;
|
|
||||||
// itemid => StateItemInfo
|
|
||||||
std::map<std::string, StateItemInfo> info_by_itemid_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PresenterStateClient : public PubSubStateClient<bool> {
|
class PresenterStateClient : public PubSubStateClient<bool> {
|
||||||
public:
|
public:
|
||||||
PresenterStateClient(const std::string& publisher_nick,
|
PresenterStateClient(const std::string& publisher_nick,
|
||||||
@ -336,15 +106,17 @@ class PresenterStateClient : public PubSubStateClient<bool> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
info_out->publisher_nick = GetPublisherNickFromPubSubItem(item.elem);
|
info_out->publisher_nick =
|
||||||
|
client()->GetPublisherNickFromPubSubItem(item.elem);
|
||||||
info_out->published_nick = presenter_elem->Attr(QN_NICK);
|
info_out->published_nick = presenter_elem->Attr(QN_NICK);
|
||||||
*state_out = (presentation_item_elem->Attr(
|
*state_out = (presentation_item_elem->Attr(
|
||||||
QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
|
QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool StatesEqual(bool state1, bool state2) {
|
virtual bool StatesEqual(const bool& state1, const bool& state2) {
|
||||||
return false; // Make every item trigger an event, even if state doesn't change.
|
// Make every item trigger an event, even if state doesn't change.
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "talk/base/sigslotrepeater.h"
|
#include "talk/base/sigslotrepeater.h"
|
||||||
#include "talk/xmpp/jid.h"
|
#include "talk/xmpp/jid.h"
|
||||||
#include "talk/xmpp/pubsubclient.h"
|
#include "talk/xmpp/pubsubclient.h"
|
||||||
|
#include "talk/xmpp/pubsubstateclient.h"
|
||||||
|
|
||||||
// Gives a high-level API for MUC call PubSub needs such as
|
// Gives a high-level API for MUC call PubSub needs such as
|
||||||
// presenter state, recording state, mute state, and remote mute.
|
// presenter state, recording state, mute state, and remote mute.
|
||||||
@ -47,30 +48,6 @@ class Jid;
|
|||||||
class XmlElement;
|
class XmlElement;
|
||||||
class XmppTaskParentInterface;
|
class XmppTaskParentInterface;
|
||||||
|
|
||||||
// To handle retracts correctly, we need to remember certain details
|
|
||||||
// about an item. We could just cache the entire XML element, but
|
|
||||||
// that would take more memory and require re-parsing.
|
|
||||||
struct StateItemInfo {
|
|
||||||
std::string published_nick;
|
|
||||||
std::string publisher_nick;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Represents a PubSub state change. Usually, the key is the nick,
|
|
||||||
// but not always. It's a per-state-type thing. Currently documented
|
|
||||||
// at https://docs.google.com/a/google.com/document/d/
|
|
||||||
// 1QyHu_ufyVdf0VICdfc_DtJbrOdrdIUm4eM73RZqnivI/edit?hl=en_US
|
|
||||||
template <typename C>
|
|
||||||
struct PubSubStateChange {
|
|
||||||
// The nick of the user changing the state.
|
|
||||||
std::string publisher_nick;
|
|
||||||
// The nick of the user whose state is changing.
|
|
||||||
std::string published_nick;
|
|
||||||
C old_state;
|
|
||||||
C new_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename C> class PubSubStateClient;
|
|
||||||
|
|
||||||
// A client tied to a specific MUC jid and local nick. Provides ways
|
// A client tied to a specific MUC jid and local nick. Provides ways
|
||||||
// to get updates and publish state and events. Must call
|
// to get updates and publish state and events. Must call
|
||||||
// RequestAll() to start getting updates.
|
// RequestAll() to start getting updates.
|
||||||
|
@ -134,4 +134,13 @@ void PubSubClient::OnRetractError(IqTask* task,
|
|||||||
SignalRetractError(this, retract_task->task_id(), stanza);
|
SignalRetractError(this, retract_task->task_id(), stanza);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string PubSubClient::GetPublisherNickFromPubSubItem(
|
||||||
|
const XmlElement* item_elem) {
|
||||||
|
if (item_elem == NULL) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource();
|
||||||
|
}
|
||||||
} // namespace buzz
|
} // namespace buzz
|
||||||
|
@ -101,6 +101,9 @@ class PubSubClient : public sigslot::has_slots<> {
|
|||||||
void RetractItem(const std::string& itemid,
|
void RetractItem(const std::string& itemid,
|
||||||
std::string* task_id_out);
|
std::string* task_id_out);
|
||||||
|
|
||||||
|
// Get the publisher nick if it exists from the pubsub item.
|
||||||
|
const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnRequestError(IqTask* task,
|
void OnRequestError(IqTask* task,
|
||||||
const XmlElement* stanza);
|
const XmlElement* stanza);
|
||||||
|
42
talk/xmpp/pubsubstateclient.cc
Normal file
42
talk/xmpp/pubsubstateclient.cc
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/xmpp/pubsubstateclient.h"
|
||||||
|
|
||||||
|
namespace buzz {
|
||||||
|
|
||||||
|
std::string PublishedNickKeySerializer::GetKey(
|
||||||
|
const std::string& publisher_nick, const std::string& published_nick) {
|
||||||
|
return published_nick;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PublisherAndPublishedNicksKeySerializer::GetKey(
|
||||||
|
const std::string& publisher_nick, const std::string& published_nick) {
|
||||||
|
return publisher_nick + ":" + published_nick;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace buzz
|
287
talk/xmpp/pubsubstateclient.h
Normal file
287
talk/xmpp/pubsubstateclient.h
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_XMPP_PUBSUBSTATECLIENT_H_
|
||||||
|
#define TALK_XMPP_PUBSUBSTATECLIENT_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/base/sigslotrepeater.h"
|
||||||
|
#include "talk/xmpp/constants.h"
|
||||||
|
#include "talk/xmpp/jid.h"
|
||||||
|
#include "talk/xmpp/pubsubclient.h"
|
||||||
|
#include "talk/xmllite/qname.h"
|
||||||
|
#include "talk/xmllite/xmlelement.h"
|
||||||
|
|
||||||
|
namespace buzz {
|
||||||
|
|
||||||
|
// To handle retracts correctly, we need to remember certain details
|
||||||
|
// about an item. We could just cache the entire XML element, but
|
||||||
|
// that would take more memory and require re-parsing.
|
||||||
|
struct StateItemInfo {
|
||||||
|
std::string published_nick;
|
||||||
|
std::string publisher_nick;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents a PubSub state change. Usually, the key is the nick,
|
||||||
|
// but not always. It's a per-state-type thing. Look below on how keys are
|
||||||
|
// computed.
|
||||||
|
template <typename C>
|
||||||
|
struct PubSubStateChange {
|
||||||
|
// The nick of the user changing the state.
|
||||||
|
std::string publisher_nick;
|
||||||
|
// The nick of the user whose state is changing.
|
||||||
|
std::string published_nick;
|
||||||
|
C old_state;
|
||||||
|
C new_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Knows how to handle specific states and XML.
|
||||||
|
template <typename C>
|
||||||
|
class PubSubStateSerializer {
|
||||||
|
public:
|
||||||
|
virtual ~PubSubStateSerializer() {}
|
||||||
|
virtual XmlElement* Write(const QName& state_name, const C& state) = 0;
|
||||||
|
virtual void Parse(const XmlElement* state_elem, C* state_out) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Knows how to create "keys" for states, which determines their
|
||||||
|
// uniqueness. Most states are per-nick, but block is
|
||||||
|
// per-blocker-and-blockee. This is independent of itemid, especially
|
||||||
|
// in the case of presenter state.
|
||||||
|
class PubSubStateKeySerializer {
|
||||||
|
public:
|
||||||
|
virtual ~PubSubStateKeySerializer() {}
|
||||||
|
virtual std::string GetKey(const std::string& publisher_nick,
|
||||||
|
const std::string& published_nick) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PublishedNickKeySerializer : public PubSubStateKeySerializer {
|
||||||
|
public:
|
||||||
|
virtual std::string GetKey(const std::string& publisher_nick,
|
||||||
|
const std::string& published_nick);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PublisherAndPublishedNicksKeySerializer
|
||||||
|
: public PubSubStateKeySerializer {
|
||||||
|
public:
|
||||||
|
virtual std::string GetKey(const std::string& publisher_nick,
|
||||||
|
const std::string& published_nick);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Adapts PubSubClient to be specifically suited for pub sub call
|
||||||
|
// states. Signals state changes and keeps track of keys, which are
|
||||||
|
// normally nicks.
|
||||||
|
template <typename C>
|
||||||
|
class PubSubStateClient : public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
// Gets ownership of the serializers, but not the client.
|
||||||
|
PubSubStateClient(const std::string& publisher_nick,
|
||||||
|
PubSubClient* client,
|
||||||
|
const QName& state_name,
|
||||||
|
C default_state,
|
||||||
|
PubSubStateKeySerializer* key_serializer,
|
||||||
|
PubSubStateSerializer<C>* state_serializer)
|
||||||
|
: publisher_nick_(publisher_nick),
|
||||||
|
client_(client),
|
||||||
|
state_name_(state_name),
|
||||||
|
default_state_(default_state) {
|
||||||
|
key_serializer_.reset(key_serializer);
|
||||||
|
state_serializer_.reset(state_serializer);
|
||||||
|
client_->SignalItems.connect(
|
||||||
|
this, &PubSubStateClient<C>::OnItems);
|
||||||
|
client_->SignalPublishResult.connect(
|
||||||
|
this, &PubSubStateClient<C>::OnPublishResult);
|
||||||
|
client_->SignalPublishError.connect(
|
||||||
|
this, &PubSubStateClient<C>::OnPublishError);
|
||||||
|
client_->SignalRetractResult.connect(
|
||||||
|
this, &PubSubStateClient<C>::OnRetractResult);
|
||||||
|
client_->SignalRetractError.connect(
|
||||||
|
this, &PubSubStateClient<C>::OnRetractError);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~PubSubStateClient() {}
|
||||||
|
|
||||||
|
virtual void Publish(const std::string& published_nick,
|
||||||
|
const C& state,
|
||||||
|
std::string* task_id_out) {
|
||||||
|
std::string key = key_serializer_->GetKey(publisher_nick_, published_nick);
|
||||||
|
std::string itemid = state_name_.LocalPart() + ":" + key;
|
||||||
|
if (StatesEqual(state, default_state_)) {
|
||||||
|
client_->RetractItem(itemid, task_id_out);
|
||||||
|
} else {
|
||||||
|
XmlElement* state_elem = state_serializer_->Write(state_name_, state);
|
||||||
|
state_elem->AddAttr(QN_NICK, published_nick);
|
||||||
|
client_->PublishItem(itemid, state_elem, task_id_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange;
|
||||||
|
// Signal (task_id, item). item is NULL for retract.
|
||||||
|
sigslot::signal2<const std::string&,
|
||||||
|
const XmlElement*> SignalPublishResult;
|
||||||
|
// Signal (task_id, item, error stanza). item is NULL for retract.
|
||||||
|
sigslot::signal3<const std::string&,
|
||||||
|
const XmlElement*,
|
||||||
|
const XmlElement*> SignalPublishError;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// return false if retracted item (no info or state given)
|
||||||
|
virtual bool ParseStateItem(const PubSubItem& item,
|
||||||
|
StateItemInfo* info_out,
|
||||||
|
C* state_out) {
|
||||||
|
const XmlElement* state_elem = item.elem->FirstNamed(state_name_);
|
||||||
|
if (state_elem == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
info_out->publisher_nick =
|
||||||
|
client_->GetPublisherNickFromPubSubItem(item.elem);
|
||||||
|
info_out->published_nick = state_elem->Attr(QN_NICK);
|
||||||
|
state_serializer_->Parse(state_elem, state_out);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool StatesEqual(const C& state1, const C& state2) {
|
||||||
|
return state1 == state2;
|
||||||
|
}
|
||||||
|
|
||||||
|
PubSubClient* client() { return client_; }
|
||||||
|
const QName& state_name() { return state_name_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnItems(PubSubClient* pub_sub_client,
|
||||||
|
const std::vector<PubSubItem>& items) {
|
||||||
|
for (std::vector<PubSubItem>::const_iterator item = items.begin();
|
||||||
|
item != items.end(); ++item) {
|
||||||
|
OnItem(*item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnItem(const PubSubItem& item) {
|
||||||
|
const std::string& itemid = item.itemid;
|
||||||
|
StateItemInfo info;
|
||||||
|
C new_state;
|
||||||
|
|
||||||
|
bool retracted = !ParseStateItem(item, &info, &new_state);
|
||||||
|
if (retracted) {
|
||||||
|
bool known_itemid =
|
||||||
|
(info_by_itemid_.find(itemid) != info_by_itemid_.end());
|
||||||
|
if (!known_itemid) {
|
||||||
|
// Nothing to retract, and nothing to publish.
|
||||||
|
// Probably a different state type.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
info = info_by_itemid_[itemid];
|
||||||
|
info_by_itemid_.erase(itemid);
|
||||||
|
new_state = default_state_;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: Assert new key matches the known key. It
|
||||||
|
// shouldn't change!
|
||||||
|
info_by_itemid_[itemid] = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key = key_serializer_->GetKey(
|
||||||
|
info.publisher_nick, info.published_nick);
|
||||||
|
bool has_old_state = (state_by_key_.find(key) != state_by_key_.end());
|
||||||
|
C old_state = has_old_state ? state_by_key_[key] : default_state_;
|
||||||
|
if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) {
|
||||||
|
// Nothing change, so don't bother signalling.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retracted || StatesEqual(new_state, default_state_)) {
|
||||||
|
// We treat a default state similar to a retract.
|
||||||
|
state_by_key_.erase(key);
|
||||||
|
} else {
|
||||||
|
state_by_key_[key] = new_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
PubSubStateChange<C> change;
|
||||||
|
if (!retracted) {
|
||||||
|
// Retracts do not have publisher information.
|
||||||
|
change.publisher_nick = info.publisher_nick;
|
||||||
|
}
|
||||||
|
change.published_nick = info.published_nick;
|
||||||
|
change.old_state = old_state;
|
||||||
|
change.new_state = new_state;
|
||||||
|
SignalStateChange(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPublishResult(PubSubClient* pub_sub_client,
|
||||||
|
const std::string& task_id,
|
||||||
|
const XmlElement* item) {
|
||||||
|
SignalPublishResult(task_id, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPublishError(PubSubClient* pub_sub_client,
|
||||||
|
const std::string& task_id,
|
||||||
|
const buzz::XmlElement* item,
|
||||||
|
const buzz::XmlElement* stanza) {
|
||||||
|
SignalPublishError(task_id, item, stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRetractResult(PubSubClient* pub_sub_client,
|
||||||
|
const std::string& task_id) {
|
||||||
|
// There's no point in differentiating between publish and retract
|
||||||
|
// errors, so we simplify by making them both signal a publish
|
||||||
|
// result.
|
||||||
|
const XmlElement* item = NULL;
|
||||||
|
SignalPublishResult(task_id, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRetractError(PubSubClient* pub_sub_client,
|
||||||
|
const std::string& task_id,
|
||||||
|
const buzz::XmlElement* stanza) {
|
||||||
|
// There's no point in differentiating between publish and retract
|
||||||
|
// errors, so we simplify by making them both signal a publish
|
||||||
|
// error.
|
||||||
|
const XmlElement* item = NULL;
|
||||||
|
SignalPublishError(task_id, item, stanza);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string publisher_nick_;
|
||||||
|
PubSubClient* client_;
|
||||||
|
const QName state_name_;
|
||||||
|
C default_state_;
|
||||||
|
talk_base::scoped_ptr<PubSubStateKeySerializer> key_serializer_;
|
||||||
|
talk_base::scoped_ptr<PubSubStateSerializer<C> > state_serializer_;
|
||||||
|
// key => state
|
||||||
|
std::map<std::string, C> state_by_key_;
|
||||||
|
// itemid => StateItemInfo
|
||||||
|
std::map<std::string, StateItemInfo> info_by_itemid_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(PubSubStateClient);
|
||||||
|
};
|
||||||
|
} // namespace buzz
|
||||||
|
|
||||||
|
#endif // TALK_XMPP_PUBSUBSTATECLIENT_H_
|
Loading…
x
Reference in New Issue
Block a user