| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| #include "media/cast/cast_sender_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/logging.h" |
| #include "base/message_loop/message_loop.h" |
| #include "media/base/video_frame.h" |
| |
| namespace media { |
| namespace cast { |
| |
| // The LocalFrameInput class posts all incoming frames; audio and video to the |
| // main cast thread for processing. |
| // This make the cast sender interface thread safe. |
| class LocalFrameInput : public FrameInput { |
| public: |
| LocalFrameInput(scoped_refptr<CastEnvironment> cast_environment, |
| base::WeakPtr<AudioSender> audio_sender, |
| base::WeakPtr<VideoSender> video_sender) |
| : cast_environment_(cast_environment), |
| audio_sender_(audio_sender), |
| video_sender_(video_sender) {} |
| |
| virtual void InsertRawVideoFrame( |
| const scoped_refptr<media::VideoFrame>& video_frame, |
| const base::TimeTicks& capture_time) OVERRIDE { |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&VideoSender::InsertRawVideoFrame, video_sender_, |
| video_frame, capture_time)); |
| } |
| |
| virtual void InsertCodedVideoFrame(const EncodedVideoFrame* video_frame, |
| const base::TimeTicks& capture_time, |
| const base::Closure callback) OVERRIDE { |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&VideoSender::InsertCodedVideoFrame, video_sender_, |
| video_frame, capture_time, callback)); |
| } |
| |
| virtual void InsertAudio(const AudioBus* audio_bus, |
| const base::TimeTicks& recorded_time, |
| const base::Closure& done_callback) OVERRIDE { |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&AudioSender::InsertAudio, audio_sender_, |
| audio_bus, recorded_time, done_callback)); |
| } |
| |
| virtual void InsertCodedAudioFrame(const EncodedAudioFrame* audio_frame, |
| const base::TimeTicks& recorded_time, |
| const base::Closure callback) OVERRIDE { |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&AudioSender::InsertCodedAudioFrame, audio_sender_, |
| audio_frame, recorded_time, callback)); |
| } |
| |
| protected: |
| virtual ~LocalFrameInput() {} |
| |
| private: |
| friend class base::RefCountedThreadSafe<LocalFrameInput>; |
| |
| scoped_refptr<CastEnvironment> cast_environment_; |
| base::WeakPtr<AudioSender> audio_sender_; |
| base::WeakPtr<VideoSender> video_sender_; |
| }; |
| |
| // LocalCastSenderPacketReceiver handle the incoming packets to the cast sender |
| // it's only expected to receive RTCP feedback packets from the remote cast |
| // receiver. The class verifies that that it is a RTCP packet and based on the |
| // SSRC of the incoming packet route the packet to the correct sender; audio or |
| // video. |
| // |
| // Definition of SSRC as defined in RFC 3550. |
| // Synchronization source (SSRC): The source of a stream of RTP |
| // packets, identified by a 32-bit numeric SSRC identifier carried in |
| // the RTP header so as not to be dependent upon the network address. |
| // All packets from a synchronization source form part of the same |
| // timing and sequence number space, so a receiver groups packets by |
| // synchronization source for playback. Examples of synchronization |
| // sources include the sender of a stream of packets derived from a |
| // signal source such as a microphone or a camera, or an RTP mixer |
| // (see below). A synchronization source may change its data format, |
| // e.g., audio encoding, over time. The SSRC identifier is a |
| // randomly chosen value meant to be globally unique within a |
| // particular RTP session (see Section 8). A participant need not |
| // use the same SSRC identifier for all the RTP sessions in a |
| // multimedia session; the binding of the SSRC identifiers is |
| // provided through RTCP (see Section 6.5.1). If a participant |
| // generates multiple streams in one RTP session, for example from |
| // separate video cameras, each MUST be identified as a different |
| // SSRC. |
| |
| class LocalCastSenderPacketReceiver : public PacketReceiver { |
| public: |
| LocalCastSenderPacketReceiver(scoped_refptr<CastEnvironment> cast_environment, |
| base::WeakPtr<AudioSender> audio_sender, |
| base::WeakPtr<VideoSender> video_sender, |
| uint32 ssrc_of_audio_sender, |
| uint32 ssrc_of_video_sender) |
| : cast_environment_(cast_environment), |
| audio_sender_(audio_sender), |
| video_sender_(video_sender), |
| ssrc_of_audio_sender_(ssrc_of_audio_sender), |
| ssrc_of_video_sender_(ssrc_of_video_sender) {} |
| |
| virtual void ReceivedPacket(const uint8* packet, |
| size_t length, |
| const base::Closure callback) OVERRIDE { |
| if (!Rtcp::IsRtcpPacket(packet, length)) { |
| // We should have no incoming RTP packets. |
| // No action; just log and call the callback informing that we are done |
| // with the packet. |
| VLOG(1) << "Unexpectedly received a RTP packet in the cast sender"; |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback); |
| return; |
| } |
| uint32 ssrc_of_sender = Rtcp::GetSsrcOfSender(packet, length); |
| if (ssrc_of_sender == ssrc_of_audio_sender_) { |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&AudioSender::IncomingRtcpPacket, audio_sender_, |
| packet, length, callback)); |
| } else if (ssrc_of_sender == ssrc_of_video_sender_) { |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&VideoSender::IncomingRtcpPacket, video_sender_, |
| packet, length, callback)); |
| } else { |
| // No action; just log and call the callback informing that we are done |
| // with the packet. |
| VLOG(1) << "Received a RTCP packet with a non matching sender SSRC " |
| << ssrc_of_sender; |
| |
| cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback); |
| } |
| } |
| |
| protected: |
| virtual ~LocalCastSenderPacketReceiver() {} |
| |
| private: |
| friend class base::RefCountedThreadSafe<LocalCastSenderPacketReceiver>; |
| |
| scoped_refptr<CastEnvironment> cast_environment_; |
| base::WeakPtr<AudioSender> audio_sender_; |
| base::WeakPtr<VideoSender> video_sender_; |
| const uint32 ssrc_of_audio_sender_; |
| const uint32 ssrc_of_video_sender_; |
| }; |
| |
| CastSender* CastSender::CreateCastSender( |
| scoped_refptr<CastEnvironment> cast_environment, |
| const AudioSenderConfig& audio_config, |
| const VideoSenderConfig& video_config, |
| VideoEncoderController* const video_encoder_controller, |
| PacketSender* const packet_sender) { |
| return new CastSenderImpl(cast_environment, |
| audio_config, |
| video_config, |
| video_encoder_controller, |
| packet_sender); |
| } |
| |
| CastSenderImpl::CastSenderImpl( |
| scoped_refptr<CastEnvironment> cast_environment, |
| const AudioSenderConfig& audio_config, |
| const VideoSenderConfig& video_config, |
| VideoEncoderController* const video_encoder_controller, |
| PacketSender* const packet_sender) |
| : pacer_(cast_environment, packet_sender), |
| audio_sender_(cast_environment, audio_config, &pacer_), |
| video_sender_(cast_environment, video_config, video_encoder_controller, |
| &pacer_), |
| frame_input_(new LocalFrameInput(cast_environment, |
| audio_sender_.AsWeakPtr(), |
| video_sender_.AsWeakPtr())), |
| packet_receiver_(new LocalCastSenderPacketReceiver(cast_environment, |
| audio_sender_.AsWeakPtr(), video_sender_.AsWeakPtr(), |
| audio_config.incoming_feedback_ssrc, |
| video_config.incoming_feedback_ssrc)) {} |
| |
| CastSenderImpl::~CastSenderImpl() {} |
| |
| scoped_refptr<FrameInput> CastSenderImpl::frame_input() { |
| return frame_input_; |
| } |
| |
| scoped_refptr<PacketReceiver> CastSenderImpl::packet_receiver() { |
| return packet_receiver_; |
| } |
| |
| } // namespace cast |
| } // namespace media |