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

Side by Side Diff: webrtc/libjingle/xmpp/hangoutpubsubclient.cc

Issue 2617443003: 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2011 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/libjingle/xmpp/hangoutpubsubclient.h"
12
13 #include "webrtc/libjingle/xmllite/qname.h"
14 #include "webrtc/libjingle/xmllite/xmlelement.h"
15 #include "webrtc/libjingle/xmpp/constants.h"
16 #include "webrtc/libjingle/xmpp/jid.h"
17 #include "webrtc/base/logging.h"
18
19
20 // Gives a high-level API for MUC call PubSub needs such as
21 // presenter state, recording state, mute state, and remote mute.
22
23 namespace buzz {
24
25 namespace {
26 const char kPresenting[] = "s";
27 const char kNotPresenting[] = "o";
28
29 } // namespace
30
31 // A simple serialiazer where presence of item => true, lack of item
32 // => false.
33 class BoolStateSerializer : public PubSubStateSerializer<bool> {
34 virtual XmlElement* Write(const QName& state_name, const bool& state) {
35 if (!state) {
36 return NULL;
37 }
38
39 return new XmlElement(state_name, true);
40 }
41
42 virtual void Parse(const XmlElement* state_elem, bool *state_out) {
43 *state_out = state_elem != NULL;
44 }
45 };
46
47 class PresenterStateClient : public PubSubStateClient<bool> {
48 public:
49 PresenterStateClient(const std::string& publisher_nick,
50 PubSubClient* client,
51 const QName& state_name,
52 bool default_state)
53 : PubSubStateClient<bool>(
54 publisher_nick, client, state_name, default_state,
55 new PublishedNickKeySerializer(), NULL) {
56 }
57
58 virtual void Publish(const std::string& published_nick,
59 const bool& state,
60 std::string* task_id_out) {
61 XmlElement* presenter_elem = new XmlElement(QN_PRESENTER_PRESENTER, true);
62 presenter_elem->AddAttr(QN_NICK, published_nick);
63
64 XmlElement* presentation_item_elem =
65 new XmlElement(QN_PRESENTER_PRESENTATION_ITEM, false);
66 const std::string& presentation_type = state ? kPresenting : kNotPresenting;
67 presentation_item_elem->AddAttr(
68 QN_PRESENTER_PRESENTATION_TYPE, presentation_type);
69
70 // The Presenter state is kind of dumb in that it doesn't always use
71 // retracts. It relies on setting the "type" to a special value.
72 std::string itemid = published_nick;
73 std::vector<XmlElement*> children;
74 children.push_back(presenter_elem);
75 children.push_back(presentation_item_elem);
76 client()->PublishItem(itemid, children, task_id_out);
77 }
78
79 protected:
80 virtual bool ParseStateItem(const PubSubItem& item,
81 StateItemInfo* info_out,
82 bool* state_out) {
83 const XmlElement* presenter_elem =
84 item.elem->FirstNamed(QN_PRESENTER_PRESENTER);
85 const XmlElement* presentation_item_elem =
86 item.elem->FirstNamed(QN_PRESENTER_PRESENTATION_ITEM);
87 if (presentation_item_elem == NULL || presenter_elem == NULL) {
88 return false;
89 }
90
91 info_out->publisher_nick =
92 client()->GetPublisherNickFromPubSubItem(item.elem);
93 info_out->published_nick = presenter_elem->Attr(QN_NICK);
94 *state_out = (presentation_item_elem->Attr(
95 QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting);
96 return true;
97 }
98
99 virtual bool StatesEqual(const bool& state1, const bool& state2) {
100 // Make every item trigger an event, even if state doesn't change.
101 return false;
102 }
103 };
104
105 HangoutPubSubClient::HangoutPubSubClient(XmppTaskParentInterface* parent,
106 const Jid& mucjid,
107 const std::string& nick)
108 : mucjid_(mucjid),
109 nick_(nick) {
110 presenter_client_.reset(new PubSubClient(parent, mucjid, NS_PRESENTER));
111 presenter_client_->SignalRequestError.connect(
112 this, &HangoutPubSubClient::OnPresenterRequestError);
113
114 media_client_.reset(new PubSubClient(parent, mucjid, NS_GOOGLE_MUC_MEDIA));
115 media_client_->SignalRequestError.connect(
116 this, &HangoutPubSubClient::OnMediaRequestError);
117
118 presenter_state_client_.reset(new PresenterStateClient(
119 nick_, presenter_client_.get(), QN_PRESENTER_PRESENTER, false));
120 presenter_state_client_->SignalStateChange.connect(
121 this, &HangoutPubSubClient::OnPresenterStateChange);
122 presenter_state_client_->SignalPublishResult.connect(
123 this, &HangoutPubSubClient::OnPresenterPublishResult);
124 presenter_state_client_->SignalPublishError.connect(
125 this, &HangoutPubSubClient::OnPresenterPublishError);
126
127 audio_mute_state_client_.reset(new PubSubStateClient<bool>(
128 nick_, media_client_.get(), QN_GOOGLE_MUC_AUDIO_MUTE, false,
129 new PublishedNickKeySerializer(), new BoolStateSerializer()));
130 // Can't just repeat because we need to watch for remote mutes.
131 audio_mute_state_client_->SignalStateChange.connect(
132 this, &HangoutPubSubClient::OnAudioMuteStateChange);
133 audio_mute_state_client_->SignalPublishResult.connect(
134 this, &HangoutPubSubClient::OnAudioMutePublishResult);
135 audio_mute_state_client_->SignalPublishError.connect(
136 this, &HangoutPubSubClient::OnAudioMutePublishError);
137
138 video_mute_state_client_.reset(new PubSubStateClient<bool>(
139 nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_MUTE, false,
140 new PublishedNickKeySerializer(), new BoolStateSerializer()));
141 // Can't just repeat because we need to watch for remote mutes.
142 video_mute_state_client_->SignalStateChange.connect(
143 this, &HangoutPubSubClient::OnVideoMuteStateChange);
144 video_mute_state_client_->SignalPublishResult.connect(
145 this, &HangoutPubSubClient::OnVideoMutePublishResult);
146 video_mute_state_client_->SignalPublishError.connect(
147 this, &HangoutPubSubClient::OnVideoMutePublishError);
148
149 video_pause_state_client_.reset(new PubSubStateClient<bool>(
150 nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_PAUSE, false,
151 new PublishedNickKeySerializer(), new BoolStateSerializer()));
152 video_pause_state_client_->SignalStateChange.connect(
153 this, &HangoutPubSubClient::OnVideoPauseStateChange);
154 video_pause_state_client_->SignalPublishResult.connect(
155 this, &HangoutPubSubClient::OnVideoPausePublishResult);
156 video_pause_state_client_->SignalPublishError.connect(
157 this, &HangoutPubSubClient::OnVideoPausePublishError);
158
159 recording_state_client_.reset(new PubSubStateClient<bool>(
160 nick_, media_client_.get(), QN_GOOGLE_MUC_RECORDING, false,
161 new PublishedNickKeySerializer(), new BoolStateSerializer()));
162 recording_state_client_->SignalStateChange.connect(
163 this, &HangoutPubSubClient::OnRecordingStateChange);
164 recording_state_client_->SignalPublishResult.connect(
165 this, &HangoutPubSubClient::OnRecordingPublishResult);
166 recording_state_client_->SignalPublishError.connect(
167 this, &HangoutPubSubClient::OnRecordingPublishError);
168
169 media_block_state_client_.reset(new PubSubStateClient<bool>(
170 nick_, media_client_.get(), QN_GOOGLE_MUC_MEDIA_BLOCK, false,
171 new PublisherAndPublishedNicksKeySerializer(),
172 new BoolStateSerializer()));
173 media_block_state_client_->SignalStateChange.connect(
174 this, &HangoutPubSubClient::OnMediaBlockStateChange);
175 media_block_state_client_->SignalPublishResult.connect(
176 this, &HangoutPubSubClient::OnMediaBlockPublishResult);
177 media_block_state_client_->SignalPublishError.connect(
178 this, &HangoutPubSubClient::OnMediaBlockPublishError);
179 }
180
181 HangoutPubSubClient::~HangoutPubSubClient() {
182 }
183
184 void HangoutPubSubClient::RequestAll() {
185 presenter_client_->RequestItems();
186 media_client_->RequestItems();
187 }
188
189 void HangoutPubSubClient::OnPresenterRequestError(
190 PubSubClient* client, const XmlElement* stanza) {
191 SignalRequestError(client->node(), stanza);
192 }
193
194 void HangoutPubSubClient::OnMediaRequestError(
195 PubSubClient* client, const XmlElement* stanza) {
196 SignalRequestError(client->node(), stanza);
197 }
198
199 void HangoutPubSubClient::PublishPresenterState(
200 bool presenting, std::string* task_id_out) {
201 presenter_state_client_->Publish(nick_, presenting, task_id_out);
202 }
203
204 void HangoutPubSubClient::PublishAudioMuteState(
205 bool muted, std::string* task_id_out) {
206 audio_mute_state_client_->Publish(nick_, muted, task_id_out);
207 }
208
209 void HangoutPubSubClient::PublishVideoMuteState(
210 bool muted, std::string* task_id_out) {
211 video_mute_state_client_->Publish(nick_, muted, task_id_out);
212 }
213
214 void HangoutPubSubClient::PublishVideoPauseState(
215 bool paused, std::string* task_id_out) {
216 video_pause_state_client_->Publish(nick_, paused, task_id_out);
217 }
218
219 void HangoutPubSubClient::PublishRecordingState(
220 bool recording, std::string* task_id_out) {
221 recording_state_client_->Publish(nick_, recording, task_id_out);
222 }
223
224 // Remote mute is accomplished by setting another client's mute state.
225 void HangoutPubSubClient::RemoteMute(
226 const std::string& mutee_nick, std::string* task_id_out) {
227 audio_mute_state_client_->Publish(mutee_nick, true, task_id_out);
228 }
229
230 // Block media is accomplished by setting another client's block
231 // state, kind of like remote mute.
232 void HangoutPubSubClient::BlockMedia(
233 const std::string& blockee_nick, std::string* task_id_out) {
234 media_block_state_client_->Publish(blockee_nick, true, task_id_out);
235 }
236
237 void HangoutPubSubClient::OnPresenterStateChange(
238 const PubSubStateChange<bool>& change) {
239 SignalPresenterStateChange(
240 change.published_nick, change.old_state, change.new_state);
241 }
242
243 void HangoutPubSubClient::OnPresenterPublishResult(
244 const std::string& task_id, const XmlElement* item) {
245 SignalPublishPresenterResult(task_id);
246 }
247
248 void HangoutPubSubClient::OnPresenterPublishError(
249 const std::string& task_id, const XmlElement* item,
250 const XmlElement* stanza) {
251 SignalPublishPresenterError(task_id, stanza);
252 }
253
254 // Since a remote mute is accomplished by another client setting our
255 // mute state, if our state changes to muted, we should mute ourselves.
256 // Note that remote un-muting is disallowed by the RoomServer.
257 void HangoutPubSubClient::OnAudioMuteStateChange(
258 const PubSubStateChange<bool>& change) {
259 bool was_muted = change.old_state;
260 bool is_muted = change.new_state;
261 bool remote_action = (!change.publisher_nick.empty() &&
262 (change.publisher_nick != change.published_nick));
263
264 if (remote_action) {
265 const std::string& mutee_nick = change.published_nick;
266 const std::string& muter_nick = change.publisher_nick;
267 if (!is_muted) {
268 // The server should prevent remote un-mute.
269 LOG(LS_WARNING) << muter_nick << " remote unmuted " << mutee_nick;
270 return;
271 }
272 bool should_mute_locally = (mutee_nick == nick_);
273 SignalRemoteMute(mutee_nick, muter_nick, should_mute_locally);
274 }
275 SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted);
276 }
277
278 const std::string GetAudioMuteNickFromItem(const XmlElement* item) {
279 if (item != NULL) {
280 const XmlElement* audio_mute_state =
281 item->FirstNamed(QN_GOOGLE_MUC_AUDIO_MUTE);
282 if (audio_mute_state != NULL) {
283 return audio_mute_state->Attr(QN_NICK);
284 }
285 }
286 return std::string();
287 }
288
289 const std::string GetBlockeeNickFromItem(const XmlElement* item) {
290 if (item != NULL) {
291 const XmlElement* media_block_state =
292 item->FirstNamed(QN_GOOGLE_MUC_MEDIA_BLOCK);
293 if (media_block_state != NULL) {
294 return media_block_state->Attr(QN_NICK);
295 }
296 }
297 return std::string();
298 }
299
300 void HangoutPubSubClient::OnAudioMutePublishResult(
301 const std::string& task_id, const XmlElement* item) {
302 const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
303 if (mutee_nick != nick_) {
304 SignalRemoteMuteResult(task_id, mutee_nick);
305 } else {
306 SignalPublishAudioMuteResult(task_id);
307 }
308 }
309
310 void HangoutPubSubClient::OnAudioMutePublishError(
311 const std::string& task_id, const XmlElement* item,
312 const XmlElement* stanza) {
313 const std::string& mutee_nick = GetAudioMuteNickFromItem(item);
314 if (mutee_nick != nick_) {
315 SignalRemoteMuteError(task_id, mutee_nick, stanza);
316 } else {
317 SignalPublishAudioMuteError(task_id, stanza);
318 }
319 }
320
321 void HangoutPubSubClient::OnVideoMuteStateChange(
322 const PubSubStateChange<bool>& change) {
323 SignalVideoMuteStateChange(
324 change.published_nick, change.old_state, change.new_state);
325 }
326
327 void HangoutPubSubClient::OnVideoMutePublishResult(
328 const std::string& task_id, const XmlElement* item) {
329 SignalPublishVideoMuteResult(task_id);
330 }
331
332 void HangoutPubSubClient::OnVideoMutePublishError(
333 const std::string& task_id, const XmlElement* item,
334 const XmlElement* stanza) {
335 SignalPublishVideoMuteError(task_id, stanza);
336 }
337
338 void HangoutPubSubClient::OnVideoPauseStateChange(
339 const PubSubStateChange<bool>& change) {
340 SignalVideoPauseStateChange(
341 change.published_nick, change.old_state, change.new_state);
342 }
343
344 void HangoutPubSubClient::OnVideoPausePublishResult(
345 const std::string& task_id, const XmlElement* item) {
346 SignalPublishVideoPauseResult(task_id);
347 }
348
349 void HangoutPubSubClient::OnVideoPausePublishError(
350 const std::string& task_id, const XmlElement* item,
351 const XmlElement* stanza) {
352 SignalPublishVideoPauseError(task_id, stanza);
353 }
354
355 void HangoutPubSubClient::OnRecordingStateChange(
356 const PubSubStateChange<bool>& change) {
357 SignalRecordingStateChange(
358 change.published_nick, change.old_state, change.new_state);
359 }
360
361 void HangoutPubSubClient::OnRecordingPublishResult(
362 const std::string& task_id, const XmlElement* item) {
363 SignalPublishRecordingResult(task_id);
364 }
365
366 void HangoutPubSubClient::OnRecordingPublishError(
367 const std::string& task_id, const XmlElement* item,
368 const XmlElement* stanza) {
369 SignalPublishRecordingError(task_id, stanza);
370 }
371
372 void HangoutPubSubClient::OnMediaBlockStateChange(
373 const PubSubStateChange<bool>& change) {
374 const std::string& blockee_nick = change.published_nick;
375 const std::string& blocker_nick = change.publisher_nick;
376
377 bool was_blockee = change.old_state;
378 bool is_blockee = change.new_state;
379 if (!was_blockee && is_blockee) {
380 SignalMediaBlock(blockee_nick, blocker_nick);
381 }
382 // TODO: Should we bother signaling unblock? Currently
383 // it isn't allowed, but it might happen when a participant leaves
384 // the room and the item is retracted.
385 }
386
387 void HangoutPubSubClient::OnMediaBlockPublishResult(
388 const std::string& task_id, const XmlElement* item) {
389 const std::string& blockee_nick = GetBlockeeNickFromItem(item);
390 SignalMediaBlockResult(task_id, blockee_nick);
391 }
392
393 void HangoutPubSubClient::OnMediaBlockPublishError(
394 const std::string& task_id, const XmlElement* item,
395 const XmlElement* stanza) {
396 const std::string& blockee_nick = GetBlockeeNickFromItem(item);
397 SignalMediaBlockError(task_id, blockee_nick, stanza);
398 }
399
400 } // namespace buzz
OLDNEW
« 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