pepper_talk_host.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/renderer_host/pepper/pepper_talk_host.h"
6
7#include "base/bind.h"
8#include "content/public/browser/browser_ppapi_host.h"
9#include "content/public/browser/browser_thread.h"
10#include "content/public/browser/render_frame_host.h"
11#include "grit/generated_resources.h"
12#include "ppapi/c/pp_errors.h"
13#include "ppapi/host/dispatch_host_message.h"
14#include "ppapi/host/host_message_context.h"
15#include "ppapi/host/ppapi_host.h"
16#include "ppapi/proxy/ppapi_messages.h"
17#include "ui/base/l10n/l10n_util.h"
18
19#if defined(USE_ASH)
20#include "ash/shell.h"
21#include "ash/shell_window_ids.h"
22#include "ash/system/tray/system_tray_notifier.h"
23#include "chrome/browser/ui/simple_message_box.h"
24#include "ui/aura/window.h"
25#endif
26
27namespace chrome {
28
29namespace {
30
31ppapi::host::ReplyMessageContext GetPermissionOnUIThread(
32    PP_TalkPermission permission,
33    int render_process_id,
34    int render_frame_id,
35    ppapi::host::ReplyMessageContext reply) {
36  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
37  reply.params.set_result(0);
38
39  content::RenderFrameHost* render_frame_host =
40      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
41  if (!render_frame_host)
42    return reply;  // RFH destroyed while task was pending.
43
44#if defined(USE_ASH)
45  base::string16 title;
46  base::string16 message;
47
48  switch (permission) {
49    case PP_TALKPERMISSION_SCREENCAST:
50      title = l10n_util::GetStringUTF16(IDS_GTALK_SCREEN_SHARE_DIALOG_TITLE);
51      message = l10n_util::GetStringUTF16(
52          IDS_GTALK_SCREEN_SHARE_DIALOG_MESSAGE);
53      break;
54    case PP_TALKPERMISSION_REMOTING:
55      title = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_TITLE);
56      message = l10n_util::GetStringUTF16(
57          IDS_GTALK_REMOTING_DIALOG_MESSAGE);
58      break;
59    case PP_TALKPERMISSION_REMOTING_CONTINUE:
60      title = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_TITLE);
61      message = l10n_util::GetStringUTF16(
62          IDS_GTALK_REMOTING_CONTINUE_DIALOG_MESSAGE);
63      break;
64    default:
65      NOTREACHED();
66      return reply;
67  }
68
69  // TODO(brettw). We should not be grabbing the active toplevel window, we
70  // should use the toplevel window associated with the render view.
71  aura::Window* parent =
72      ash::Shell::GetContainer(ash::Shell::GetTargetRootWindow(),
73                               ash::kShellWindowId_SystemModalContainer);
74  reply.params.set_result(static_cast<int32_t>(
75      chrome::ShowMessageBox(parent, title, message,
76                             chrome::MESSAGE_BOX_TYPE_QUESTION) ==
77      chrome::MESSAGE_BOX_RESULT_YES));
78#else
79  NOTIMPLEMENTED();
80#endif
81  return reply;
82}
83
84#if defined(USE_ASH) && defined(OS_CHROMEOS)
85void OnTerminateRemotingEventOnUIThread(const base::Closure& stop_callback) {
86  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
87                                   stop_callback);
88}
89#endif  // defined(USE_ASH) && defined(OS_CHROMEOS)
90
91ppapi::host::ReplyMessageContext StartRemotingOnUIThread(
92    const base::Closure& stop_callback,
93    int render_process_id,
94    int render_frame_id,
95    ppapi::host::ReplyMessageContext reply) {
96  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
97  content::RenderFrameHost* render_frame_host =
98      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
99  if (!render_frame_host) {
100    reply.params.set_result(PP_ERROR_FAILED);
101    return reply;  // RFH destroyed while task was pending.
102  }
103
104#if defined(USE_ASH) && defined(OS_CHROMEOS)
105  base::Closure stop_callback_ui_thread = base::Bind(
106      &OnTerminateRemotingEventOnUIThread,
107      stop_callback);
108
109  ash::Shell::GetInstance()->system_tray_notifier()->NotifyScreenShareStart(
110      stop_callback_ui_thread, base::string16());
111  reply.params.set_result(PP_OK);
112#else
113  NOTIMPLEMENTED();
114  reply.params.set_result(PP_ERROR_NOTSUPPORTED);
115#endif
116  return reply;
117}
118
119void StopRemotingOnUIThread() {
120  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
121#if defined(USE_ASH) && defined(OS_CHROMEOS)
122  if (ash::Shell::GetInstance()) {
123    ash::Shell::GetInstance()->system_tray_notifier()->NotifyScreenShareStop();
124  }
125#else
126  NOTIMPLEMENTED();
127#endif
128}
129
130ppapi::host::ReplyMessageContext StopRemotingOnUIThreadWithResult(
131    ppapi::host::ReplyMessageContext reply) {
132  reply.params.set_result(PP_OK);
133  StopRemotingOnUIThread();
134  return reply;
135}
136
137}  // namespace
138
139PepperTalkHost::PepperTalkHost(content::BrowserPpapiHost* host,
140                               PP_Instance instance,
141                               PP_Resource resource)
142    : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource),
143      browser_ppapi_host_(host),
144      remoting_started_(false),
145      weak_factory_(this) {
146}
147
148PepperTalkHost::~PepperTalkHost() {
149  if (remoting_started_) {
150    content::BrowserThread::PostTask(
151        content::BrowserThread::UI, FROM_HERE,
152        base::Bind(&StopRemotingOnUIThread));
153  }
154}
155
156int32_t PepperTalkHost::OnResourceMessageReceived(
157    const IPC::Message& msg,
158    ppapi::host::HostMessageContext* context) {
159  IPC_BEGIN_MESSAGE_MAP(PepperTalkHost, msg)
160    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Talk_RequestPermission,
161                                      OnRequestPermission)
162    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Talk_StartRemoting,
163                                        OnStartRemoting)
164    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Talk_StopRemoting,
165                                        OnStopRemoting)
166  IPC_END_MESSAGE_MAP()
167  return PP_ERROR_FAILED;
168}
169
170int32_t PepperTalkHost::OnRequestPermission(
171    ppapi::host::HostMessageContext* context,
172    PP_TalkPermission permission) {
173  if (permission < PP_TALKPERMISSION_SCREENCAST ||
174      permission >= PP_TALKPERMISSION_NUM_PERMISSIONS)
175    return PP_ERROR_BADARGUMENT;
176
177  int render_process_id = 0;
178  int render_frame_id = 0;
179  browser_ppapi_host_->GetRenderFrameIDsForInstance(
180      pp_instance(), &render_process_id, &render_frame_id);
181
182  content::BrowserThread::PostTaskAndReplyWithResult(
183      content::BrowserThread::UI, FROM_HERE,
184      base::Bind(&GetPermissionOnUIThread, permission, render_process_id,
185                 render_frame_id, context->MakeReplyMessageContext()),
186      base::Bind(&PepperTalkHost::OnRequestPermissionCompleted,
187                 weak_factory_.GetWeakPtr()));
188  return PP_OK_COMPLETIONPENDING;
189}
190
191int32_t PepperTalkHost::OnStartRemoting(
192    ppapi::host::HostMessageContext* context) {
193  int render_process_id = 0;
194  int render_frame_id = 0;
195  browser_ppapi_host_->GetRenderFrameIDsForInstance(
196      pp_instance(), &render_process_id, &render_frame_id);
197
198  base::Closure remoting_stop_callback = base::Bind(
199      &PepperTalkHost::OnRemotingStopEvent,
200      weak_factory_.GetWeakPtr());
201
202  content::BrowserThread::PostTaskAndReplyWithResult(
203      content::BrowserThread::UI, FROM_HERE,
204      base::Bind(&StartRemotingOnUIThread, remoting_stop_callback,
205                 render_process_id, render_frame_id,
206                 context->MakeReplyMessageContext()),
207      base::Bind(&PepperTalkHost::OnStartRemotingCompleted,
208                 weak_factory_.GetWeakPtr()));
209  return PP_OK_COMPLETIONPENDING;
210}
211
212int32_t PepperTalkHost::OnStopRemoting(
213    ppapi::host::HostMessageContext* context) {
214  content::BrowserThread::PostTaskAndReplyWithResult(
215      content::BrowserThread::UI, FROM_HERE,
216      base::Bind(&StopRemotingOnUIThreadWithResult,
217                 context->MakeReplyMessageContext()),
218      base::Bind(&PepperTalkHost::OnStopRemotingCompleted,
219                 weak_factory_.GetWeakPtr()));
220  return PP_OK_COMPLETIONPENDING;
221}
222
223void PepperTalkHost::OnRemotingStopEvent() {
224  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
225  remoting_started_ = false;
226  host()->SendUnsolicitedReply(
227      pp_resource(), PpapiPluginMsg_Talk_NotifyEvent(PP_TALKEVENT_TERMINATE));
228}
229
230void PepperTalkHost::OnRequestPermissionCompleted(
231    ppapi::host::ReplyMessageContext reply) {
232  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
233  host()->SendReply(reply, PpapiPluginMsg_Talk_RequestPermissionReply());
234}
235
236void PepperTalkHost::OnStartRemotingCompleted(
237    ppapi::host::ReplyMessageContext reply) {
238  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
239  // Remember to hide remoting UI when resource is deleted.
240  if (reply.params.result() == PP_OK)
241    remoting_started_ = true;
242
243  host()->SendReply(reply, PpapiPluginMsg_Talk_StartRemotingReply());
244}
245
246void PepperTalkHost::OnStopRemotingCompleted(
247    ppapi::host::ReplyMessageContext reply) {
248  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
249  remoting_started_ = false;
250  host()->SendReply(reply, PpapiPluginMsg_Talk_StopRemotingReply());
251}
252
253}  // namespace chrome
254