summaryrefslogtreecommitdiff
path: root/chromium/media/cast/audio_sender/audio_sender.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/cast/audio_sender/audio_sender.cc')
-rw-r--r--chromium/media/cast/audio_sender/audio_sender.cc168
1 files changed, 168 insertions, 0 deletions
diff --git a/chromium/media/cast/audio_sender/audio_sender.cc b/chromium/media/cast/audio_sender/audio_sender.cc
new file mode 100644
index 00000000000..39fccda6370
--- /dev/null
+++ b/chromium/media/cast/audio_sender/audio_sender.cc
@@ -0,0 +1,168 @@
+// 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 OnReceivedSendReportRequest() OVERRIDE {
+ DCHECK(false) << "Invalid callback";
+ }
+
+ virtual void OnReceivedReportBlock(
+ const RtcpReportBlock& report_block) OVERRIDE {
+ DCHECK(false) << "Invalid callback";
+ }
+
+ 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<CastThread> cast_thread,
+ const AudioSenderConfig& audio_config,
+ PacedPacketSender* const paced_packet_sender)
+ : incoming_feedback_ssrc_(audio_config.incoming_feedback_ssrc),
+ cast_thread_(cast_thread),
+ rtp_sender_(&audio_config, NULL, paced_packet_sender),
+ rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
+ rtp_audio_sender_statistics_(
+ new LocalRtpSenderStatistics(&rtp_sender_)),
+ rtcp_(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),
+ clock_(&default_tick_clock_),
+ weak_factory_(this) {
+
+ rtcp_.SetRemoteSSRC(audio_config.incoming_feedback_ssrc);
+
+ if (!audio_config.use_external_encoder) {
+ audio_encoder_ = new AudioEncoder(cast_thread, 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, int length,
+ const base::Closure callback) {
+ rtcp_.IncomingRtcpPacket(packet, length);
+ cast_thread_->PostTask(CastThread::MAIN, FROM_HERE, callback);
+}
+
+void AudioSender::ScheduleNextRtcpReport() {
+ base::TimeDelta time_to_next =
+ rtcp_.TimeToSendNextRtcpReport() - clock_->NowTicks();
+
+ time_to_next = std::max(time_to_next,
+ base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
+
+ cast_thread_->PostDelayedTask(CastThread::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