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
3 // found in the LICENSE file.
4 #include "media/cast/cast_sender_impl.h"
7 #include "base/callback.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/base/video_frame.h"
15 // The LocalVideoFrameInput class posts all incoming video frames to the main
16 // cast thread for processing.
17 class LocalVideoFrameInput
: public VideoFrameInput
{
19 LocalVideoFrameInput(scoped_refptr
<CastEnvironment
> cast_environment
,
20 base::WeakPtr
<VideoSender
> video_sender
)
21 : cast_environment_(cast_environment
), video_sender_(video_sender
) {}
23 virtual void InsertRawVideoFrame(
24 const scoped_refptr
<media::VideoFrame
>& video_frame
,
25 const base::TimeTicks
& capture_time
) OVERRIDE
{
26 cast_environment_
->PostTask(CastEnvironment::MAIN
,
28 base::Bind(&VideoSender::InsertRawVideoFrame
,
35 virtual ~LocalVideoFrameInput() {}
38 friend class base::RefCountedThreadSafe
<LocalVideoFrameInput
>;
40 scoped_refptr
<CastEnvironment
> cast_environment_
;
41 base::WeakPtr
<VideoSender
> video_sender_
;
43 DISALLOW_COPY_AND_ASSIGN(LocalVideoFrameInput
);
46 // The LocalAudioFrameInput class posts all incoming audio frames to the main
47 // cast thread for processing. Therefore frames can be inserted from any thread.
48 class LocalAudioFrameInput
: public AudioFrameInput
{
50 LocalAudioFrameInput(scoped_refptr
<CastEnvironment
> cast_environment
,
51 base::WeakPtr
<AudioSender
> audio_sender
)
52 : cast_environment_(cast_environment
), audio_sender_(audio_sender
) {}
54 virtual void InsertAudio(scoped_ptr
<AudioBus
> audio_bus
,
55 const base::TimeTicks
& recorded_time
) OVERRIDE
{
56 cast_environment_
->PostTask(CastEnvironment::MAIN
,
58 base::Bind(&AudioSender::InsertAudio
,
60 base::Passed(&audio_bus
),
65 virtual ~LocalAudioFrameInput() {}
68 friend class base::RefCountedThreadSafe
<LocalAudioFrameInput
>;
70 scoped_refptr
<CastEnvironment
> cast_environment_
;
71 base::WeakPtr
<AudioSender
> audio_sender_
;
73 DISALLOW_COPY_AND_ASSIGN(LocalAudioFrameInput
);
76 scoped_ptr
<CastSender
> CastSender::Create(
77 scoped_refptr
<CastEnvironment
> cast_environment
,
78 transport::CastTransportSender
* const transport_sender
) {
79 CHECK(cast_environment
);
80 return scoped_ptr
<CastSender
>(
81 new CastSenderImpl(cast_environment
, transport_sender
));
84 CastSenderImpl::CastSenderImpl(
85 scoped_refptr
<CastEnvironment
> cast_environment
,
86 transport::CastTransportSender
* const transport_sender
)
87 : cast_environment_(cast_environment
),
88 transport_sender_(transport_sender
),
90 CHECK(cast_environment
);
93 void CastSenderImpl::InitializeAudio(
94 const AudioSenderConfig
& audio_config
,
95 const CastInitializationCallback
& cast_initialization_cb
) {
96 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
97 CHECK(audio_config
.use_external_encoder
||
98 cast_environment_
->HasAudioThread());
101 new AudioSender(cast_environment_
, audio_config
, transport_sender_
));
103 CastInitializationStatus status
= audio_sender_
->InitializationResult();
105 if (status
== STATUS_AUDIO_INITIALIZED
) {
106 ssrc_of_audio_sender_
= audio_config
.incoming_feedback_ssrc
;
108 new LocalAudioFrameInput(cast_environment_
, audio_sender_
->AsWeakPtr());
110 cast_initialization_cb
.Run(status
);
113 void CastSenderImpl::InitializeVideo(
114 const VideoSenderConfig
& video_config
,
115 const CastInitializationCallback
& cast_initialization_cb
,
116 const CreateVideoEncodeAcceleratorCallback
& create_vea_cb
,
117 const CreateVideoEncodeMemoryCallback
& create_video_encode_mem_cb
) {
118 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
119 CHECK(video_config
.use_external_encoder
||
120 cast_environment_
->HasVideoThread());
121 VLOG(1) << "CastSender::ctor";
123 video_sender_
.reset(new VideoSender(cast_environment_
,
126 create_video_encode_mem_cb
,
127 cast_initialization_cb
,
130 ssrc_of_video_sender_
= video_config
.incoming_feedback_ssrc
;
132 new LocalVideoFrameInput(cast_environment_
, video_sender_
->AsWeakPtr());
135 CastSenderImpl::~CastSenderImpl() {
136 VLOG(1) << "CastSender::dtor";
139 // ReceivedPacket handle the incoming packets to the cast sender
140 // it's only expected to receive RTCP feedback packets from the remote cast
141 // receiver. The class verifies that that it is a RTCP packet and based on the
142 // SSRC of the incoming packet route the packet to the correct sender; audio or
145 // Definition of SSRC as defined in RFC 3550.
146 // Synchronization source (SSRC): The source of a stream of RTP
147 // packets, identified by a 32-bit numeric SSRC identifier carried in
148 // the RTP header so as not to be dependent upon the network address.
149 // All packets from a synchronization source form part of the same
150 // timing and sequence number space, so a receiver groups packets by
151 // synchronization source for playback. Examples of synchronization
152 // sources include the sender of a stream of packets derived from a
153 // signal source such as a microphone or a camera, or an RTP mixer
154 // (see below). A synchronization source may change its data format,
155 // e.g., audio encoding, over time. The SSRC identifier is a
156 // randomly chosen value meant to be globally unique within a
157 // particular RTP session (see Section 8). A participant need not
158 // use the same SSRC identifier for all the RTP sessions in a
159 // multimedia session; the binding of the SSRC identifiers is
160 // provided through RTCP (see Section 6.5.1). If a participant
161 // generates multiple streams in one RTP session, for example from
162 // separate video cameras, each MUST be identified as a different
164 void CastSenderImpl::ReceivedPacket(scoped_ptr
<Packet
> packet
) {
165 DCHECK(cast_environment_
);
166 size_t length
= packet
->size();
167 const uint8_t* data
= &packet
->front();
168 if (!Rtcp::IsRtcpPacket(data
, length
)) {
169 // We should have no incoming RTP packets.
170 VLOG(1) << "Unexpectedly received a RTP packet in the cast sender";
173 uint32 ssrc_of_sender
= Rtcp::GetSsrcOfSender(data
, length
);
174 if (ssrc_of_sender
== ssrc_of_audio_sender_
) {
175 if (!audio_sender_
) {
179 cast_environment_
->PostTask(CastEnvironment::MAIN
,
181 base::Bind(&AudioSender::IncomingRtcpPacket
,
182 audio_sender_
->AsWeakPtr(),
183 base::Passed(&packet
)));
184 } else if (ssrc_of_sender
== ssrc_of_video_sender_
) {
185 if (!video_sender_
) {
189 cast_environment_
->PostTask(CastEnvironment::MAIN
,
191 base::Bind(&VideoSender::IncomingRtcpPacket
,
192 video_sender_
->AsWeakPtr(),
193 base::Passed(&packet
)));
195 VLOG(1) << "Received a RTCP packet with a non matching sender SSRC "
200 scoped_refptr
<AudioFrameInput
> CastSenderImpl::audio_frame_input() {
201 return audio_frame_input_
;
204 scoped_refptr
<VideoFrameInput
> CastSenderImpl::video_frame_input() {
205 return video_frame_input_
;
208 transport::PacketReceiverCallback
CastSenderImpl::packet_receiver() {
209 return base::Bind(&CastSenderImpl::ReceivedPacket
,
210 weak_factory_
.GetWeakPtr());