1// Copyright 2014 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/media/cast_transport_host_filter.h"
6
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/net/chrome_net_log.h"
9#include "content/public/browser/power_save_blocker.h"
10#include "media/cast/net/cast_transport_sender.h"
11
12namespace {
13
14// How often to send raw events.
15const int kSendRawEventsIntervalSecs = 1;
16
17}
18
19namespace cast {
20
21CastTransportHostFilter::CastTransportHostFilter()
22    : BrowserMessageFilter(CastMsgStart),
23      weak_factory_(this) {}
24
25CastTransportHostFilter::~CastTransportHostFilter() {}
26
27bool CastTransportHostFilter::OnMessageReceived(const IPC::Message& message) {
28  bool handled = true;
29  IPC_BEGIN_MESSAGE_MAP(CastTransportHostFilter, message)
30    IPC_MESSAGE_HANDLER(CastHostMsg_New, OnNew)
31    IPC_MESSAGE_HANDLER(CastHostMsg_Delete, OnDelete)
32    IPC_MESSAGE_HANDLER(CastHostMsg_InitializeAudio, OnInitializeAudio)
33    IPC_MESSAGE_HANDLER(CastHostMsg_InitializeVideo, OnInitializeVideo)
34    IPC_MESSAGE_HANDLER(CastHostMsg_InsertFrame, OnInsertFrame)
35    IPC_MESSAGE_HANDLER(CastHostMsg_SendSenderReport,
36                        OnSendSenderReport)
37    IPC_MESSAGE_HANDLER(CastHostMsg_ResendFrameForKickstart,
38                        OnResendFrameForKickstart)
39    IPC_MESSAGE_HANDLER(CastHostMsg_CancelSendingFrames,
40                        OnCancelSendingFrames)
41    IPC_MESSAGE_UNHANDLED(handled = false);
42  IPC_END_MESSAGE_MAP();
43  return handled;
44}
45
46void CastTransportHostFilter::NotifyStatusChange(
47    int32 channel_id,
48    media::cast::CastTransportStatus status) {
49  Send(new CastMsg_NotifyStatusChange(channel_id, status));
50}
51
52void CastTransportHostFilter::SendRawEvents(
53    int32 channel_id,
54    const std::vector<media::cast::PacketEvent>& packet_events,
55    const std::vector<media::cast::FrameEvent>& frame_events) {
56  if (!packet_events.empty())
57    Send(new CastMsg_RawEvents(channel_id,
58                               packet_events,
59                               frame_events));
60}
61
62void CastTransportHostFilter::SendRtt(int32 channel_id,
63                                      uint32 ssrc,
64                                      base::TimeDelta rtt) {
65  Send(new CastMsg_Rtt(channel_id, ssrc, rtt));
66}
67
68void CastTransportHostFilter::SendCastMessage(
69    int32 channel_id,
70    uint32 ssrc,
71    const media::cast::RtcpCastMessage& cast_message) {
72  Send(new CastMsg_RtcpCastMessage(channel_id, ssrc, cast_message));
73}
74
75void CastTransportHostFilter::OnNew(
76    int32 channel_id,
77    const net::IPEndPoint& remote_end_point,
78    const base::DictionaryValue& options) {
79  if (!power_save_blocker_) {
80    DVLOG(1) << ("Preventing the application from being suspended while one or "
81                 "more transports are active for Cast Streaming.");
82    power_save_blocker_ = content::PowerSaveBlocker::Create(
83        content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
84        "Cast is streaming content to a remote receiver.").Pass();
85  }
86
87  if (id_map_.Lookup(channel_id)) {
88    id_map_.Remove(channel_id);
89  }
90
91  scoped_ptr<media::cast::CastTransportSender> sender =
92      media::cast::CastTransportSender::Create(
93          g_browser_process->net_log(),
94          &clock_,
95          remote_end_point,
96          make_scoped_ptr(options.DeepCopy()),
97          base::Bind(&CastTransportHostFilter::NotifyStatusChange,
98                     weak_factory_.GetWeakPtr(),
99                     channel_id),
100          base::Bind(&CastTransportHostFilter::SendRawEvents,
101                     weak_factory_.GetWeakPtr(),
102                     channel_id),
103          base::TimeDelta::FromSeconds(kSendRawEventsIntervalSecs),
104          base::MessageLoopProxy::current());
105  id_map_.AddWithID(sender.release(), channel_id);
106}
107
108void CastTransportHostFilter::OnDelete(int32 channel_id) {
109  media::cast::CastTransportSender* sender =
110      id_map_.Lookup(channel_id);
111  if (sender) {
112    id_map_.Remove(channel_id);
113  } else {
114    DVLOG(1) << "CastTransportHostFilter::Delete called "
115             << "on non-existing channel";
116  }
117
118  if (id_map_.IsEmpty()) {
119    DVLOG_IF(1, power_save_blocker_) <<
120        ("Releasing the block on application suspension since no transports "
121         "are active anymore for Cast Streaming.");
122    power_save_blocker_.reset();
123  }
124}
125
126void CastTransportHostFilter::OnInitializeAudio(
127    int32 channel_id,
128    const media::cast::CastTransportRtpConfig& config) {
129  media::cast::CastTransportSender* sender =
130      id_map_.Lookup(channel_id);
131  if (sender) {
132    sender->InitializeAudio(
133        config,
134        base::Bind(&CastTransportHostFilter::SendCastMessage,
135                   weak_factory_.GetWeakPtr(),
136                   channel_id, config.ssrc),
137        base::Bind(&CastTransportHostFilter::SendRtt,
138                   weak_factory_.GetWeakPtr(),
139                   channel_id, config.ssrc));
140  } else {
141    DVLOG(1)
142        << "CastTransportHostFilter::OnInitializeAudio on non-existing channel";
143  }
144}
145
146void CastTransportHostFilter::OnInitializeVideo(
147    int32 channel_id,
148    const media::cast::CastTransportRtpConfig& config) {
149  media::cast::CastTransportSender* sender =
150      id_map_.Lookup(channel_id);
151  if (sender) {
152    sender->InitializeVideo(
153        config,
154        base::Bind(&CastTransportHostFilter::SendCastMessage,
155                   weak_factory_.GetWeakPtr(),
156                   channel_id, config.ssrc),
157        base::Bind(&CastTransportHostFilter::SendRtt,
158                   weak_factory_.GetWeakPtr(),
159                   channel_id, config.ssrc));
160  } else {
161    DVLOG(1)
162        << "CastTransportHostFilter::OnInitializeVideo on non-existing channel";
163  }
164}
165
166void CastTransportHostFilter::OnInsertFrame(
167    int32 channel_id,
168    uint32 ssrc,
169    const media::cast::EncodedFrame& frame) {
170  media::cast::CastTransportSender* sender =
171      id_map_.Lookup(channel_id);
172  if (sender) {
173    sender->InsertFrame(ssrc, frame);
174  } else {
175    DVLOG(1)
176        << "CastTransportHostFilter::OnInsertFrame on non-existing channel";
177  }
178}
179
180void CastTransportHostFilter::OnCancelSendingFrames(
181    int32 channel_id, uint32 ssrc,
182    const std::vector<uint32>& frame_ids) {
183  media::cast::CastTransportSender* sender =
184      id_map_.Lookup(channel_id);
185  if (sender) {
186    sender->CancelSendingFrames(ssrc, frame_ids);
187  } else {
188    DVLOG(1)
189        << "CastTransportHostFilter::OnCancelSendingFrames "
190        << "on non-existing channel";
191  }
192}
193
194void CastTransportHostFilter::OnResendFrameForKickstart(
195    int32 channel_id, uint32 ssrc, uint32 frame_id) {
196  media::cast::CastTransportSender* sender =
197      id_map_.Lookup(channel_id);
198  if (sender) {
199    sender->ResendFrameForKickstart(ssrc, frame_id);
200  } else {
201    DVLOG(1)
202        << "CastTransportHostFilter::OnResendFrameForKickstart "
203        << "on non-existing channel";
204  }
205}
206
207void CastTransportHostFilter::OnSendSenderReport(
208    int32 channel_id,
209    uint32 ssrc,
210    base::TimeTicks current_time,
211    uint32 current_time_as_rtp_timestamp) {
212  media::cast::CastTransportSender* sender =
213      id_map_.Lookup(channel_id);
214  if (sender) {
215    sender->SendSenderReport(ssrc,
216                             current_time,
217                             current_time_as_rtp_timestamp);
218  } else {
219    DVLOG(1)
220        << "CastTransportHostFilter::OnSendSenderReport "
221        << "on non-existing channel";
222  }
223}
224
225}  // namespace cast
226