blob: 560ebd990ccaf094ffbd41726762e9978c16a6aa [file] [log] [blame]
// 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/audio_sender/audio_sender.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "media/cast/audio_sender/audio_encoder.h"
#include "media/cast/rtcp/rtcp.h"
#include "media/cast/rtp_sender/rtp_sender.h"
namespace media {
namespace cast {
const int64 kMinSchedulingDelayMs = 1;
class LocalRtcpAudioSenderFeedback : public RtcpSenderFeedback {
public:
explicit LocalRtcpAudioSenderFeedback(AudioSender* audio_sender)
: audio_sender_(audio_sender) {
}
virtual void OnReceivedReportBlock(
const RtcpReportBlock& report_block) OVERRIDE {
}
virtual void OnReceivedIntraFrameRequest() OVERRIDE {
DCHECK(false) << "Invalid callback";
}
virtual void OnReceivedRpsi(uint8 payload_type,
uint64 picture_id) OVERRIDE {
DCHECK(false) << "Invalid callback";
}
virtual void OnReceivedRemb(uint32 bitrate) OVERRIDE {
DCHECK(false) << "Invalid callback";
}
virtual void OnReceivedNackRequest(
const std::list<uint16>& nack_sequence_numbers) OVERRIDE {
DCHECK(false) << "Invalid callback";
}
virtual void OnReceivedCastFeedback(
const RtcpCastMessage& cast_feedback) OVERRIDE {
if (!cast_feedback.missing_frames_and_packets_.empty()) {
audio_sender_->ResendPackets(cast_feedback.missing_frames_and_packets_);
}
VLOG(1) << "Received audio ACK "
<< static_cast<int>(cast_feedback.ack_frame_id_);
}
private:
AudioSender* audio_sender_;
};
class LocalRtpSenderStatistics : public RtpSenderStatistics {
public:
explicit LocalRtpSenderStatistics(RtpSender* rtp_sender)
: rtp_sender_(rtp_sender) {
}
virtual void GetStatistics(const base::TimeTicks& now,
RtcpSenderInfo* sender_info) OVERRIDE {
rtp_sender_->RtpStatistics(now, sender_info);
}
private:
RtpSender* rtp_sender_;
};
AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
const AudioSenderConfig& audio_config,
PacedPacketSender* const paced_packet_sender)
: incoming_feedback_ssrc_(audio_config.incoming_feedback_ssrc),
cast_environment_(cast_environment),
rtp_sender_(cast_environment->Clock(), &audio_config, NULL,
paced_packet_sender),
rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
rtp_audio_sender_statistics_(
new LocalRtpSenderStatistics(&rtp_sender_)),
rtcp_(cast_environment->Clock(),
rtcp_feedback_.get(),
paced_packet_sender,
rtp_audio_sender_statistics_.get(),
NULL,
audio_config.rtcp_mode,
base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
true,
audio_config.sender_ssrc,
audio_config.rtcp_c_name),
weak_factory_(this) {
rtcp_.SetRemoteSSRC(audio_config.incoming_feedback_ssrc);
if (!audio_config.use_external_encoder) {
audio_encoder_ = new AudioEncoder(cast_environment, audio_config);
}
ScheduleNextRtcpReport();
}
AudioSender::~AudioSender() {}
void AudioSender::InsertRawAudioFrame(
const PcmAudioFrame* audio_frame,
const base::TimeTicks& recorded_time,
const base::Closure callback) {
DCHECK(audio_encoder_.get()) << "Invalid internal state";
audio_encoder_->InsertRawAudioFrame(audio_frame, recorded_time,
base::Bind(&AudioSender::SendEncodedAudioFrame,
weak_factory_.GetWeakPtr()),
callback);
}
void AudioSender::InsertCodedAudioFrame(const EncodedAudioFrame* audio_frame,
const base::TimeTicks& recorded_time,
const base::Closure callback) {
DCHECK(audio_encoder_.get() == NULL) << "Invalid internal state";
rtp_sender_.IncomingEncodedAudioFrame(audio_frame, recorded_time);
callback.Run();
}
void AudioSender::SendEncodedAudioFrame(
scoped_ptr<EncodedAudioFrame> audio_frame,
const base::TimeTicks& recorded_time) {
rtp_sender_.IncomingEncodedAudioFrame(audio_frame.get(), recorded_time);
}
void AudioSender::ResendPackets(
const MissingFramesAndPacketsMap& missing_frames_and_packets) {
rtp_sender_.ResendPackets(missing_frames_and_packets);
}
void AudioSender::IncomingRtcpPacket(const uint8* packet, size_t length,
const base::Closure callback) {
rtcp_.IncomingRtcpPacket(packet, length);
cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
}
void AudioSender::ScheduleNextRtcpReport() {
base::TimeDelta time_to_next =
rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks();
time_to_next = std::max(time_to_next,
base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
base::Bind(&AudioSender::SendRtcpReport, weak_factory_.GetWeakPtr()),
time_to_next);
}
void AudioSender::SendRtcpReport() {
rtcp_.SendRtcpReport(incoming_feedback_ssrc_);
ScheduleNextRtcpReport();
}
} // namespace cast
} // namespace media