// 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_receiver_impl.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
namespace media {
namespace cast {
// The video and audio receivers should only be called from the main thread.
// LocalFrameReciever posts tasks to the main thread, making the cast interface
// thread safe.
class LocalFrameReceiver : public FrameReceiver {
public:
LocalFrameReceiver(scoped_refptr<CastEnvironment> cast_environment,
AudioReceiver* audio_receiver,
VideoReceiver* video_receiver)
: cast_environment_(cast_environment),
audio_receiver_(audio_receiver),
video_receiver_(video_receiver) {}
virtual void GetRawVideoFrame(
const VideoFrameDecodedCallback& callback) OVERRIDE {
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::Bind(&VideoReceiver::GetRawVideoFrame,
video_receiver_->AsWeakPtr(), callback));
}
virtual void GetEncodedVideoFrame(
const VideoFrameEncodedCallback& callback) OVERRIDE {
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::Bind(&VideoReceiver::GetEncodedVideoFrame,
video_receiver_->AsWeakPtr(), callback));
}
virtual void GetRawAudioFrame(
int number_of_10ms_blocks,
int desired_frequency,
const AudioFrameDecodedCallback& callback) OVERRIDE {
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, base::Bind(
&AudioReceiver::GetRawAudioFrame, audio_receiver_->AsWeakPtr(),
number_of_10ms_blocks, desired_frequency, callback));
}
virtual void GetCodedAudioFrame(
const AudioFrameEncodedCallback& callback) OVERRIDE {
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::Bind(&AudioReceiver::GetEncodedAudioFrame,
audio_receiver_->AsWeakPtr(), callback));
}
protected:
virtual ~LocalFrameReceiver() {}
private:
friend class base::RefCountedThreadSafe<LocalFrameReceiver>;
scoped_refptr<CastEnvironment> cast_environment_;
AudioReceiver* audio_receiver_;
VideoReceiver* video_receiver_;
};
// The video and audio receivers should only be called from the main thread.
class LocalPacketReceiver : public PacketReceiver {
public:
LocalPacketReceiver(scoped_refptr<CastEnvironment> cast_environment,
AudioReceiver* audio_receiver,
VideoReceiver* video_receiver,
uint32 ssrc_of_audio_sender,
uint32 ssrc_of_video_sender)
: cast_environment_(cast_environment),
audio_receiver_(audio_receiver),
video_receiver_(video_receiver),
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 (length < kMinLengthOfRtcp) {
// No action; just log and call the callback informing that we are done
// with the packet.
VLOG(1) << "Received a packet which is too short " << length;
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
return;
}
uint32 ssrc_of_sender;
if (!Rtcp::IsRtcpPacket(packet, length)) {
if (length < kMinLengthOfRtp) {
// No action; just log and call the callback informing that we are done
// with the packet.
VLOG(1) << "Received a RTP packet which is too short " << length;
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
return;
}
ssrc_of_sender = RtpReceiver::GetSsrcOfSender(packet, length);
} else {
ssrc_of_sender = Rtcp::GetSsrcOfSender(packet, length);
}
if (ssrc_of_sender == ssrc_of_audio_sender_) {
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::Bind(&AudioReceiver::IncomingPacket,
audio_receiver_->AsWeakPtr(), packet, length, callback));
} else if (ssrc_of_sender == ssrc_of_video_sender_) {
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::Bind(&VideoReceiver::IncomingPacket,
video_receiver_->AsWeakPtr(), packet, length, callback));
} else {
// No action; just log and call the callback informing that we are done
// with the packet.
VLOG(1) << "Received a packet with a non matching sender SSRC "
<< ssrc_of_sender;
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
}
}
protected:
virtual ~LocalPacketReceiver() {}
private:
friend class base::RefCountedThreadSafe<LocalPacketReceiver>;
scoped_refptr<CastEnvironment> cast_environment_;
AudioReceiver* audio_receiver_;
VideoReceiver* video_receiver_;
const uint32 ssrc_of_audio_sender_;
const uint32 ssrc_of_video_sender_;
};
CastReceiver* CastReceiver::CreateCastReceiver(
scoped_refptr<CastEnvironment> cast_environment,
const AudioReceiverConfig& audio_config,
const VideoReceiverConfig& video_config,
PacketSender* const packet_sender) {
return new CastReceiverImpl(cast_environment,
audio_config,
video_config,
packet_sender);
}
CastReceiverImpl::CastReceiverImpl(
scoped_refptr<CastEnvironment> cast_environment,
const AudioReceiverConfig& audio_config,
const VideoReceiverConfig& video_config,
PacketSender* const packet_sender)
: pacer_(cast_environment, packet_sender),
audio_receiver_(cast_environment, audio_config, &pacer_),
video_receiver_(cast_environment, video_config, &pacer_),
frame_receiver_(new LocalFrameReceiver(cast_environment,
&audio_receiver_,
&video_receiver_)),
packet_receiver_(new LocalPacketReceiver(cast_environment,
&audio_receiver_,
&video_receiver_,
audio_config.incoming_ssrc,
video_config.incoming_ssrc)) {}
CastReceiverImpl::~CastReceiverImpl() {}
scoped_refptr<PacketReceiver> CastReceiverImpl::packet_receiver() {
return packet_receiver_;
}
scoped_refptr<FrameReceiver> CastReceiverImpl::frame_receiver() {
return frame_receiver_;
}
} // namespace cast
} // namespace media