OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/media/cast_session_delegate.h" | 5 #include "chrome/renderer/media/cast_session_delegate.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
| 9 #include "content/public/renderer/p2p_socket_client.h" |
9 #include "content/public/renderer/render_thread.h" | 10 #include "content/public/renderer/render_thread.h" |
| 11 #include "media/cast/cast_config.h" |
10 #include "media/cast/cast_environment.h" | 12 #include "media/cast/cast_environment.h" |
11 #include "media/cast/cast_sender.h" | 13 #include "media/cast/cast_sender.h" |
12 #include "media/cast/logging/logging_defines.h" | 14 #include "media/cast/logging/logging_defines.h" |
13 | 15 |
14 using media::cast::AudioSenderConfig; | 16 using media::cast::AudioSenderConfig; |
15 using media::cast::CastEnvironment; | 17 using media::cast::CastEnvironment; |
16 using media::cast::CastSender; | 18 using media::cast::CastSender; |
17 using media::cast::VideoSenderConfig; | 19 using media::cast::VideoSenderConfig; |
18 | 20 |
19 CastSessionDelegate::CastSessionDelegate() | 21 CastSessionDelegate::CastSessionDelegate() |
20 : audio_encode_thread_("CastAudioEncodeThread"), | 22 : audio_encode_thread_("CastAudioEncodeThread"), |
21 video_encode_thread_("CastVideoEncodeThread"), | 23 video_encode_thread_("CastVideoEncodeThread"), |
22 audio_configured_(false), | 24 audio_configured_(false), |
23 video_configured_(false), | 25 video_configured_(false), |
24 io_message_loop_proxy_( | 26 io_message_loop_proxy_( |
25 content::RenderThread::Get()->GetIOMessageLoopProxy()) { | 27 content::RenderThread::Get()->GetIOMessageLoopProxy()) { |
26 } | 28 } |
27 | 29 |
28 CastSessionDelegate::~CastSessionDelegate() { | 30 CastSessionDelegate::~CastSessionDelegate() { |
29 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 31 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
30 } | 32 } |
31 | 33 |
| 34 void CastSessionDelegate::SetSocketFactory( |
| 35 scoped_ptr<CastSession::P2PSocketFactory> socket_factory, |
| 36 const net::IPEndPoint& remote_address) { |
| 37 socket_factory_ = socket_factory.Pass(); |
| 38 remote_address_ = remote_address; |
| 39 } |
| 40 |
32 void CastSessionDelegate::StartAudio(const AudioSenderConfig& config) { | 41 void CastSessionDelegate::StartAudio(const AudioSenderConfig& config) { |
33 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 42 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
34 | 43 |
35 audio_configured_ = true; | 44 audio_configured_ = true; |
36 audio_config_ = config; | 45 audio_config_ = config; |
37 MaybeStartSending(); | 46 MaybeStartSending(); |
38 } | 47 } |
39 | 48 |
40 void CastSessionDelegate::StartVideo(const VideoSenderConfig& config) { | 49 void CastSessionDelegate::StartVideo(const VideoSenderConfig& config) { |
41 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 50 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
42 | 51 |
43 video_configured_ = true; | 52 video_configured_ = true; |
44 video_config_ = config; | 53 video_config_ = config; |
45 MaybeStartSending(); | 54 MaybeStartSending(); |
46 } | 55 } |
47 | 56 |
48 void CastSessionDelegate::StartSending() { | 57 void CastSessionDelegate::StartSending() { |
49 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 58 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
50 | 59 |
51 if (cast_environment_) | 60 if (cast_environment_) |
52 return; | 61 return; |
53 | 62 |
| 63 if (!socket_factory_) { |
| 64 // TODO(hubbe): Post an error back to the user |
| 65 return; |
| 66 } |
| 67 |
| 68 socket_ = socket_factory_->Create(); |
| 69 socket_->SetDelegate(this); |
| 70 |
54 audio_encode_thread_.Start(); | 71 audio_encode_thread_.Start(); |
55 video_encode_thread_.Start(); | 72 video_encode_thread_.Start(); |
56 | 73 |
57 // CastSender uses the renderer's IO thread as the main thread. This reduces | 74 // CastSender uses the renderer's IO thread as the main thread. This reduces |
58 // thread hopping for incoming video frames and outgoing network packets. | 75 // thread hopping for incoming video frames and outgoing network packets. |
59 // There's no need to decode so no thread assigned for decoding. | 76 // There's no need to decode so no thread assigned for decoding. |
60 // Get default logging: All disabled. | 77 // Get default logging: All disabled. |
61 cast_environment_ = new CastEnvironment( | 78 cast_environment_ = new CastEnvironment( |
62 &clock_, | 79 &clock_, |
63 base::MessageLoopProxy::current(), | 80 base::MessageLoopProxy::current(), |
64 audio_encode_thread_.message_loop_proxy(), | 81 audio_encode_thread_.message_loop_proxy(), |
65 NULL, | 82 NULL, |
66 video_encode_thread_.message_loop_proxy(), | 83 video_encode_thread_.message_loop_proxy(), |
67 NULL, | 84 NULL, |
68 media::cast::GetDefaultCastLoggingConfig()); | 85 media::cast::GetDefaultCastLoggingConfig()); |
69 | 86 |
70 // TODO(hclam): A couple things need to be done here: | 87 // TODO(hclam): Implement VideoEncoderController to configure hardware |
71 // 1. Connect media::cast::PacketSender to net::Socket interface. | 88 // encoder. |
72 // 2. Implement VideoEncoderController to configure hardware encoder. | |
73 cast_sender_.reset(CastSender::CreateCastSender( | 89 cast_sender_.reset(CastSender::CreateCastSender( |
74 cast_environment_, | 90 cast_environment_, |
75 audio_config_, | 91 audio_config_, |
76 video_config_, | 92 video_config_, |
77 NULL, | 93 NULL, |
78 NULL)); | 94 this)); |
| 95 } |
| 96 |
| 97 // media::cast::PacketSender Implementation |
| 98 bool CastSessionDelegate::SendPacket( |
| 99 const media::cast::Packet& packet) { |
| 100 // TODO(hubbe): Make sure audio and video packets gets the right DSCP. |
| 101 socket_->SendWithDscp( |
| 102 remote_address_, |
| 103 *reinterpret_cast<const std::vector<char> *>(&packet), |
| 104 net::DSCP_AF41); |
| 105 return true; |
| 106 } |
| 107 |
| 108 bool CastSessionDelegate::SendPackets( |
| 109 const media::cast::PacketList& packets) { |
| 110 // TODO(hubbe): Add ability to send multiple packets in one IPC message. |
| 111 for (size_t i = 0; i < packets.size(); i++) { |
| 112 SendPacket(packets[i]); |
| 113 } |
| 114 return true; |
| 115 } |
| 116 |
| 117 // content::P2PSocketClient::Delegate Implementation |
| 118 void CastSessionDelegate::OnOpen( |
| 119 const net::IPEndPoint& address) { |
| 120 // Called once Init completes. Ignored. |
| 121 } |
| 122 |
| 123 void CastSessionDelegate::OnIncomingTcpConnection( |
| 124 const net::IPEndPoint& address, |
| 125 content::P2PSocketClient* client) { |
| 126 // We only support UDP sockets. This function should not be called |
| 127 // for UDP sockets. |
| 128 NOTREACHED(); |
| 129 } |
| 130 |
| 131 void CastSessionDelegate::OnSendComplete() { |
| 132 // Ignored for now. |
| 133 } |
| 134 |
| 135 void CastSessionDelegate::OnError() { |
| 136 // TODO(hubbe): Report this back to the user. |
| 137 } |
| 138 |
| 139 void CastSessionDelegate::OnDataReceived(const net::IPEndPoint& address, |
| 140 const std::vector<char>& data) { |
| 141 uint8 *packet_copy = new uint8[data.size()]; |
| 142 memcpy(packet_copy, &data[0], data.size()); |
| 143 cast_sender_->packet_receiver()->ReceivedPacket( |
| 144 packet_copy, |
| 145 data.size(), |
| 146 base::Bind(&media::cast::PacketReceiver::DeletePacket, |
| 147 packet_copy)); |
79 } | 148 } |
80 | 149 |
81 void CastSessionDelegate::MaybeStartSending() { | 150 void CastSessionDelegate::MaybeStartSending() { |
82 if (!audio_configured_ || !video_configured_) | 151 if (!audio_configured_ || !video_configured_) |
83 return; | 152 return; |
84 StartSending(); | 153 StartSending(); |
85 } | 154 } |
OLD | NEW |