Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Unified Diff: webrtc/libjingle/xmpp/hangoutpubsubclient.cc

Issue 2618633003: Revert of Remove webrtc/libjingle/{xmllite,xmpp} (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/libjingle/xmpp/hangoutpubsubclient.h ('k') | webrtc/libjingle/xmpp/hangoutpubsubclient_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/libjingle/xmpp/hangoutpubsubclient.cc
diff --git a/webrtc/libjingle/xmpp/hangoutpubsubclient.cc b/webrtc/libjingle/xmpp/hangoutpubsubclient.cc
new file mode 100644
index 0000000000000000000000000000000000000000..db1ac31491abc8b78e96e203865ff147d31f1122
--- /dev/null
+++ b/webrtc/libjingle/xmpp/hangoutpubsubclient.cc
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2011 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h"
+
+#include "webrtc/libjingle/xmllite/qname.h"
+#include "webrtc/libjingle/xmllite/xmlelement.h"
+#include "webrtc/libjingle/xmpp/constants.h"
+#include "webrtc/libjingle/xmpp/jid.h"
+#include "webrtc/base/logging.h"
+
+
+// Gives a high-level API for MUC call PubSub needs such as
+// presenter state, recording state, mute state, and remote mute.
+
+namespace buzz {
+
+namespace {
+const char kPresenting[] = "s";
+const char kNotPresenting[] = "o";
+
+} // namespace
+
+// A simple serialiazer where presence of item => true, lack of item
+// => false.
+class BoolStateSerializer : public PubSubStateSerializer<bool> {
+ virtual XmlElement* Write(const QName& state_name, const bool& state) {
+ if (!state) {
+ return NULL;
+ }
+
+ return new XmlElement(state_name, true);
+ }
+
+ virtual void Parse(const XmlElement* state_elem, bool *state_out) {
+ *state_out = state_elem != NULL;
+ }
+};
+
+class PresenterStateClient : public PubSubStateClient<bool> {
+ public:
+ PresenterStateClient(const std::string& publisher_nick,
+ PubSubClient* client,
+ const QName& state_name,
+ bool default_state)
+ : PubSubStateClient<bool>(
+ publisher_nick, client, state_name, default_state,
+ new PublishedNickKeySerializer(), NULL) {
+ }
+
+ virtual void Publish(const std::string& published_nick,
+ const bool& state,
+ std::string* task_id_out) {
+ XmlElement* presenter_elem = new XmlElement(QN_PRESENTER_PRESENTER, true);
+ presenter_elem->AddAttr(QN_NICK, published_nick);
+
+ XmlElement* presentation_item_elem =
+ new XmlElement(QN_PRESENTER_PRESENTATION_ITEM, false);
+ const std::string& presentation_type = state ? kPresenting : kNotPresenting;
+ presentation_item_elem->AddAttr(
+ QN_PRESENTER_PRESENTATION_TYPE, presentation_type);
+
+ // The Presenter state is kind of dumb in that it doesn't always use
+ // retracts. It relies on setting the "type" to a special value.
+ std::string itemid = published_nick;
+ std::vector<XmlElement*> children;
+ children.push_back(presenter_elem);
+ children.push_back(presentation_item_elem);
+ client()->PublishItem(itemid, children, task_id_out);
+ }
+
+ protected:
+ virtual bool ParseStateItem(const PubSubItem& item,
+ StateItemInfo* info_out,
+ bool* state_out) {
+ const XmlElement* presenter_elem =
+ item.elem->FirstNamed(QN_PRESENTER_PRESENTER);
+ const XmlElement* presentation_item_elem =
+ item.elem->FirstNamed(QN_PRESENTER_PRESENTATION_ITEM);
+ if (presentation_item_elem == NULL || presenter_elem == NULL) {
+ return false;
+ }
+
+ info_out->publisher_nick =
+ client()->GetPublisherNickFromPubSubItem(item.elem);
+ info_out->published_nick = presenter_elem->Attr(QN_NICK);
+ *state_out = (presentation_item_elem->Attr(
+ QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
+ return true;
+ }
+
+ virtual bool StatesEqual(const bool& state1, const bool& state2) {
+ // Make every item trigger an event, even if state doesn't change.
+ return false;
+ }
+};
+
+HangoutPubSubClient::HangoutPubSubClient(XmppTaskParentInterface* parent,
+ const Jid& mucjid,
+ const std::string& nick)
+ : mucjid_(mucjid),
+ nick_(nick) {
+ presenter_client_.reset(new PubSubClient(parent, mucjid, NS_PRESENTER));
+ presenter_client_->SignalRequestError.connect(
+ this, &HangoutPubSubClient::OnPresenterRequestError);
+
+ media_client_.reset(new PubSubClient(parent, mucjid, NS_GOOGLE_MUC_MEDIA));
+ media_client_->SignalRequestError.connect(
+ this, &HangoutPubSubClient::OnMediaRequestError);
+
+ presenter_state_client_.reset(new PresenterStateClient(
+ nick_, presenter_client_.get(), QN_PRESENTER_PRESENTER, false));
+ presenter_state_client_->SignalStateChange.connect(
+ this, &HangoutPubSubClient::OnPresenterStateChange);
+ presenter_state_client_->SignalPublishResult.connect(
+ this, &HangoutPubSubClient::OnPresenterPublishResult);
+ presenter_state_client_->SignalPublishError.connect(
+ this, &HangoutPubSubClient::OnPresenterPublishError);
+
+ audio_mute_state_client_.reset(new PubSubStateClient<bool>(
+ nick_, media_client_.get(), QN_GOOGLE_MUC_AUDIO_MUTE, false,
+ new PublishedNickKeySerializer(), new BoolStateSerializer()));
+ // Can't just repeat because we need to watch for remote mutes.
+ audio_mute_state_client_->SignalStateChange.connect(
+ this, &HangoutPubSubClient::OnAudioMuteStateChange);
+ audio_mute_state_client_->SignalPublishResult.connect(
+ this, &HangoutPubSubClient::OnAudioMutePublishResult);
+ audio_mute_state_client_->SignalPublishError.connect(
+ this, &HangoutPubSubClient::OnAudioMutePublishError);
+
+ video_mute_state_client_.reset(new PubSubStateClient<bool>(
+ nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_MUTE, false,
+ new PublishedNickKeySerializer(), new BoolStateSerializer()));
+ // Can't just repeat because we need to watch for remote mutes.
+ video_mute_state_client_->SignalStateChange.connect(
+ this, &HangoutPubSubClient::OnVideoMuteStateChange);
+ video_mute_state_client_->SignalPublishResult.connect(
+ this, &HangoutPubSubClient::OnVideoMutePublishResult);
+ video_mute_state_client_->SignalPublishError.connect(
+ this, &HangoutPubSubClient::OnVideoMutePublishError);
+
+ video_pause_state_client_.reset(new PubSubStateClient<bool>(
+ nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_PAUSE, false,
+ new PublishedNickKeySerializer(), new BoolStateSerializer()));
+ video_pause_state_client_->SignalStateChange.connect(
+ this, &HangoutPubSubClient::OnVideoPauseStateChange);
+ video_pause_state_client_->SignalPublishResult.connect(
+ this, &HangoutPubSubClient::OnVideoPausePublishResult);
+ video_pause_state_client_->SignalPublishError.connect(
+ this, &HangoutPubSubClient::OnVideoPausePublishError);
+
+ recording_state_client_.reset(new PubSubStateClient<bool>(
+ nick_, media_client_.get(), QN_GOOGLE_MUC_RECORDING, false,
+ new PublishedNickKeySerializer(), new BoolStateSerializer()));
+ recording_state_client_->SignalStateChange.connect(
+ this, &HangoutPubSubClient::OnRecordingStateChange);
+ recording_state_client_->SignalPublishResult.connect(
+ this, &HangoutPubSubClient::OnRecordingPublishResult);
+ recording_state_client_->SignalPublishError.connect(
+ this, &HangoutPubSubClient::OnRecordingPublishError);
+
+ media_block_state_client_.reset(new PubSubStateClient<bool>(
+ nick_, media_client_.get(), QN_GOOGLE_MUC_MEDIA_BLOCK, false,
+ new PublisherAndPublishedNicksKeySerializer(),
+ new BoolStateSerializer()));
+ media_block_state_client_->SignalStateChange.connect(
+ this, &HangoutPubSubClient::OnMediaBlockStateChange);
+ media_block_state_client_->SignalPublishResult.connect(
+ this, &HangoutPubSubClient::OnMediaBlockPublishResult);
+ media_block_state_client_->SignalPublishError.connect(
+ this, &HangoutPubSubClient::OnMediaBlockPublishError);
+}
+
+HangoutPubSubClient::~HangoutPubSubClient() {
+}
+
+void HangoutPubSubClient::RequestAll() {
+ presenter_client_->RequestItems();
+ media_client_->RequestItems();
+}
+
+void HangoutPubSubClient::OnPresenterRequestError(
+ PubSubClient* client, const XmlElement* stanza) {
+ SignalRequestError(client->node(), stanza);
+}
+
+void HangoutPubSubClient::OnMediaRequestError(
+ PubSubClient* client, const XmlElement* stanza) {
+ SignalRequestError(client->node(), stanza);
+}
+
+void HangoutPubSubClient::PublishPresenterState(
+ bool presenting, std::string* task_id_out) {
+ presenter_state_client_->Publish(nick_, presenting, task_id_out);
+}
+
+void HangoutPubSubClient::PublishAudioMuteState(
+ bool muted, std::string* task_id_out) {
+ audio_mute_state_client_->Publish(nick_, muted, task_id_out);
+}
+
+void HangoutPubSubClient::PublishVideoMuteState(
+ bool muted, std::string* task_id_out) {
+ video_mute_state_client_->Publish(nick_, muted, task_id_out);
+}
+
+void HangoutPubSubClient::PublishVideoPauseState(
+ bool paused, std::string* task_id_out) {
+ video_pause_state_client_->Publish(nick_, paused, task_id_out);
+}
+
+void HangoutPubSubClient::PublishRecordingState(
+ bool recording, std::string* task_id_out) {
+ recording_state_client_->Publish(nick_, recording, task_id_out);
+}
+
+// Remote mute is accomplished by setting another client's mute state.
+void HangoutPubSubClient::RemoteMute(
+ const std::string& mutee_nick, std::string* task_id_out) {
+ audio_mute_state_client_->Publish(mutee_nick, true, task_id_out);
+}
+
+// Block media is accomplished by setting another client's block
+// state, kind of like remote mute.
+void HangoutPubSubClient::BlockMedia(
+ const std::string& blockee_nick, std::string* task_id_out) {
+ media_block_state_client_->Publish(blockee_nick, true, task_id_out);
+}
+
+void HangoutPubSubClient::OnPresenterStateChange(
+ const PubSubStateChange<bool>& change) {
+ SignalPresenterStateChange(
+ change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnPresenterPublishResult(
+ const std::string& task_id, const XmlElement* item) {
+ SignalPublishPresenterResult(task_id);
+}
+
+void HangoutPubSubClient::OnPresenterPublishError(
+ const std::string& task_id, const XmlElement* item,
+ const XmlElement* stanza) {
+ SignalPublishPresenterError(task_id, stanza);
+}
+
+// Since a remote mute is accomplished by another client setting our
+// mute state, if our state changes to muted, we should mute ourselves.
+// Note that remote un-muting is disallowed by the RoomServer.
+void HangoutPubSubClient::OnAudioMuteStateChange(
+ const PubSubStateChange<bool>& change) {
+ bool was_muted = change.old_state;
+ bool is_muted = change.new_state;
+ bool remote_action = (!change.publisher_nick.empty() &&
+ (change.publisher_nick != change.published_nick));
+
+ if (remote_action) {
+ const std::string& mutee_nick = change.published_nick;
+ const std::string& muter_nick = change.publisher_nick;
+ if (!is_muted) {
+ // The server should prevent remote un-mute.
+ LOG(LS_WARNING) << muter_nick << " remote unmuted " << mutee_nick;
+ return;
+ }
+ bool should_mute_locally = (mutee_nick == nick_);
+ SignalRemoteMute(mutee_nick, muter_nick, should_mute_locally);
+ }
+ SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted);
+}
+
+const std::string GetAudioMuteNickFromItem(const XmlElement* item) {
+ if (item != NULL) {
+ const XmlElement* audio_mute_state =
+ item->FirstNamed(QN_GOOGLE_MUC_AUDIO_MUTE);
+ if (audio_mute_state != NULL) {
+ return audio_mute_state->Attr(QN_NICK);
+ }
+ }
+ return std::string();
+}
+
+const std::string GetBlockeeNickFromItem(const XmlElement* item) {
+ if (item != NULL) {
+ const XmlElement* media_block_state =
+ item->FirstNamed(QN_GOOGLE_MUC_MEDIA_BLOCK);
+ if (media_block_state != NULL) {
+ return media_block_state->Attr(QN_NICK);
+ }
+ }
+ return std::string();
+}
+
+void HangoutPubSubClient::OnAudioMutePublishResult(
+ const std::string& task_id, const XmlElement* item) {
+ const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
+ if (mutee_nick != nick_) {
+ SignalRemoteMuteResult(task_id, mutee_nick);
+ } else {
+ SignalPublishAudioMuteResult(task_id);
+ }
+}
+
+void HangoutPubSubClient::OnAudioMutePublishError(
+ const std::string& task_id, const XmlElement* item,
+ const XmlElement* stanza) {
+ const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
+ if (mutee_nick != nick_) {
+ SignalRemoteMuteError(task_id, mutee_nick, stanza);
+ } else {
+ SignalPublishAudioMuteError(task_id, stanza);
+ }
+}
+
+void HangoutPubSubClient::OnVideoMuteStateChange(
+ const PubSubStateChange<bool>& change) {
+ SignalVideoMuteStateChange(
+ change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnVideoMutePublishResult(
+ const std::string& task_id, const XmlElement* item) {
+ SignalPublishVideoMuteResult(task_id);
+}
+
+void HangoutPubSubClient::OnVideoMutePublishError(
+ const std::string& task_id, const XmlElement* item,
+ const XmlElement* stanza) {
+ SignalPublishVideoMuteError(task_id, stanza);
+}
+
+void HangoutPubSubClient::OnVideoPauseStateChange(
+ const PubSubStateChange<bool>& change) {
+ SignalVideoPauseStateChange(
+ change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnVideoPausePublishResult(
+ const std::string& task_id, const XmlElement* item) {
+ SignalPublishVideoPauseResult(task_id);
+}
+
+void HangoutPubSubClient::OnVideoPausePublishError(
+ const std::string& task_id, const XmlElement* item,
+ const XmlElement* stanza) {
+ SignalPublishVideoPauseError(task_id, stanza);
+}
+
+void HangoutPubSubClient::OnRecordingStateChange(
+ const PubSubStateChange<bool>& change) {
+ SignalRecordingStateChange(
+ change.published_nick, change.old_state, change.new_state);
+}
+
+void HangoutPubSubClient::OnRecordingPublishResult(
+ const std::string& task_id, const XmlElement* item) {
+ SignalPublishRecordingResult(task_id);
+}
+
+void HangoutPubSubClient::OnRecordingPublishError(
+ const std::string& task_id, const XmlElement* item,
+ const XmlElement* stanza) {
+ SignalPublishRecordingError(task_id, stanza);
+}
+
+void HangoutPubSubClient::OnMediaBlockStateChange(
+ const PubSubStateChange<bool>& change) {
+ const std::string& blockee_nick = change.published_nick;
+ const std::string& blocker_nick = change.publisher_nick;
+
+ bool was_blockee = change.old_state;
+ bool is_blockee = change.new_state;
+ if (!was_blockee && is_blockee) {
+ SignalMediaBlock(blockee_nick, blocker_nick);
+ }
+ // TODO: Should we bother signaling unblock? Currently
+ // it isn't allowed, but it might happen when a participant leaves
+ // the room and the item is retracted.
+}
+
+void HangoutPubSubClient::OnMediaBlockPublishResult(
+ const std::string& task_id, const XmlElement* item) {
+ const std::string& blockee_nick = GetBlockeeNickFromItem(item);
+ SignalMediaBlockResult(task_id, blockee_nick);
+}
+
+void HangoutPubSubClient::OnMediaBlockPublishError(
+ const std::string& task_id, const XmlElement* item,
+ const XmlElement* stanza) {
+ const std::string& blockee_nick = GetBlockeeNickFromItem(item);
+ SignalMediaBlockError(task_id, blockee_nick, stanza);
+}
+
+} // namespace buzz
« no previous file with comments | « webrtc/libjingle/xmpp/hangoutpubsubclient.h ('k') | webrtc/libjingle/xmpp/hangoutpubsubclient_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698