| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/cast/audio_sender/audio_sender.h" | 5 #include "media/cast/audio_sender/audio_sender.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "media/cast/audio_sender/audio_encoder.h" | 10 #include "media/cast/audio_sender/audio_encoder.h" |
| 11 #include "media/cast/transport/cast_transport_defines.h" | 11 #include "media/cast/transport/cast_transport_defines.h" |
| 12 | 12 |
| 13 namespace media { | 13 namespace media { |
| 14 namespace cast { | 14 namespace cast { |
| 15 | 15 |
| 16 const int64 kMinSchedulingDelayMs = 1; | 16 const int64 kMinSchedulingDelayMs = 1; |
| 17 | 17 |
| 18 class LocalRtcpAudioSenderFeedback : public RtcpSenderFeedback { | 18 class LocalRtcpAudioSenderFeedback : public RtcpSenderFeedback { |
| 19 public: | 19 public: |
| 20 explicit LocalRtcpAudioSenderFeedback(AudioSender* audio_sender) | 20 explicit LocalRtcpAudioSenderFeedback(AudioSender* audio_sender) |
| 21 : audio_sender_(audio_sender) { | 21 : audio_sender_(audio_sender) {} |
| 22 } | |
| 23 | 22 |
| 24 virtual void OnReceivedCastFeedback( | 23 virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) |
| 25 const RtcpCastMessage& cast_feedback) OVERRIDE { | 24 OVERRIDE { |
| 26 if (!cast_feedback.missing_frames_and_packets_.empty()) { | 25 if (!cast_feedback.missing_frames_and_packets_.empty()) { |
| 27 audio_sender_->ResendPackets(cast_feedback.missing_frames_and_packets_); | 26 audio_sender_->ResendPackets(cast_feedback.missing_frames_and_packets_); |
| 28 } | 27 } |
| 29 VLOG(1) << "Received audio ACK " | 28 VLOG(1) << "Received audio ACK " |
| 30 << static_cast<int>(cast_feedback.ack_frame_id_); | 29 << static_cast<int>(cast_feedback.ack_frame_id_); |
| 31 } | 30 } |
| 32 | 31 |
| 33 private: | 32 private: |
| 34 AudioSender* audio_sender_; | 33 AudioSender* audio_sender_; |
| 35 }; | 34 }; |
| 36 | 35 |
| 37 class LocalRtpSenderStatistics : public RtpSenderStatistics { | 36 class LocalRtpSenderStatistics : public RtpSenderStatistics { |
| 38 public: | 37 public: |
| 39 explicit LocalRtpSenderStatistics( | 38 explicit LocalRtpSenderStatistics( |
| 40 transport::CastTransportSender* const transport_sender) | 39 transport::CastTransportSender* const transport_sender) |
| 41 : transport_sender_(transport_sender) { | 40 : transport_sender_(transport_sender) {} |
| 42 } | |
| 43 | 41 |
| 44 virtual void GetStatistics(const base::TimeTicks& now, | 42 virtual void GetStatistics(const base::TimeTicks& now, |
| 45 transport::RtcpSenderInfo* sender_info) OVERRIDE { | 43 transport::RtcpSenderInfo* sender_info) OVERRIDE { |
| 46 transport_sender_->RtpAudioStatistics(now, sender_info); | 44 transport_sender_->RtpAudioStatistics(now, sender_info); |
| 47 } | 45 } |
| 48 | 46 |
| 49 private: | 47 private: |
| 50 transport::CastTransportSender* const transport_sender_; | 48 transport::CastTransportSender* const transport_sender_; |
| 51 | 49 |
| 52 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtpSenderStatistics); | 50 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtpSenderStatistics); |
| 53 }; | 51 }; |
| 54 | 52 |
| 55 // TODO(mikhal): Reduce heap allocation when not needed. | 53 // TODO(mikhal): Reduce heap allocation when not needed. |
| 56 AudioSender::AudioSender( | 54 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, |
| 57 scoped_refptr<CastEnvironment> cast_environment, | 55 const AudioSenderConfig& audio_config, |
| 58 const AudioSenderConfig& audio_config, | 56 transport::CastTransportSender* const transport_sender) |
| 59 transport::CastTransportSender* const transport_sender) | 57 : cast_environment_(cast_environment), |
| 60 : cast_environment_(cast_environment), | 58 transport_sender_(transport_sender), |
| 61 transport_sender_(transport_sender), | 59 rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)), |
| 62 rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)), | 60 rtp_audio_sender_statistics_( |
| 63 rtp_audio_sender_statistics_( | 61 new LocalRtpSenderStatistics(transport_sender_)), |
| 64 new LocalRtpSenderStatistics(transport_sender_)), | 62 rtcp_(cast_environment, |
| 65 rtcp_(cast_environment, | 63 rtcp_feedback_.get(), |
| 66 rtcp_feedback_.get(), | 64 transport_sender_, |
| 67 transport_sender_, | 65 NULL, // paced sender. |
| 68 NULL, // paced sender. | 66 rtp_audio_sender_statistics_.get(), |
| 69 rtp_audio_sender_statistics_.get(), | 67 NULL, |
| 70 NULL, | 68 audio_config.rtcp_mode, |
| 71 audio_config.rtcp_mode, | 69 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), |
| 72 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), | 70 audio_config.sender_ssrc, |
| 73 audio_config.sender_ssrc, | 71 audio_config.incoming_feedback_ssrc, |
| 74 audio_config.incoming_feedback_ssrc, | 72 audio_config.rtcp_c_name), |
| 75 audio_config.rtcp_c_name), | 73 timers_initialized_(false), |
| 76 timers_initialized_(false), | 74 initialization_status_(STATUS_INITIALIZED), |
| 77 initialization_status_(STATUS_INITIALIZED), | 75 weak_factory_(this) { |
| 78 weak_factory_(this) { | |
| 79 if (!audio_config.use_external_encoder) { | 76 if (!audio_config.use_external_encoder) { |
| 80 audio_encoder_ = new AudioEncoder( | 77 audio_encoder_ = |
| 81 cast_environment, audio_config, | 78 new AudioEncoder(cast_environment, |
| 82 base::Bind(&AudioSender::SendEncodedAudioFrame, | 79 audio_config, |
| 83 weak_factory_.GetWeakPtr())); | 80 base::Bind(&AudioSender::SendEncodedAudioFrame, |
| 81 weak_factory_.GetWeakPtr())); |
| 84 initialization_status_ = audio_encoder_->InitializationResult(); | 82 initialization_status_ = audio_encoder_->InitializationResult(); |
| 85 } | 83 } |
| 86 } | 84 } |
| 87 | 85 |
| 88 AudioSender::~AudioSender() {} | 86 AudioSender::~AudioSender() {} |
| 89 | 87 |
| 90 void AudioSender::InitializeTimers() { | 88 void AudioSender::InitializeTimers() { |
| 91 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 89 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 92 if (!timers_initialized_) { | 90 if (!timers_initialized_) { |
| 93 timers_initialized_ = true; | 91 timers_initialized_ = true; |
| 94 ScheduleNextRtcpReport(); | 92 ScheduleNextRtcpReport(); |
| 95 } | 93 } |
| 96 } | 94 } |
| 97 | 95 |
| 98 void AudioSender::InsertAudio(const AudioBus* audio_bus, | 96 void AudioSender::InsertAudio(const AudioBus* audio_bus, |
| 99 const base::TimeTicks& recorded_time, | 97 const base::TimeTicks& recorded_time, |
| 100 const base::Closure& done_callback) { | 98 const base::Closure& done_callback) { |
| 101 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 99 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 102 DCHECK(audio_encoder_.get()) << "Invalid internal state"; | 100 DCHECK(audio_encoder_.get()) << "Invalid internal state"; |
| 103 // TODO(mikhal): Resolve calculation of the audio rtp_timestamp for logging. | 101 // TODO(mikhal): Resolve calculation of the audio rtp_timestamp for logging. |
| 104 // This is a tmp solution to allow the code to build. | 102 // This is a tmp solution to allow the code to build. |
| 105 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 103 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 106 cast_environment_->Logging()->InsertFrameEvent(now, kAudioFrameReceived, | 104 cast_environment_->Logging()->InsertFrameEvent( |
| 107 GetVideoRtpTimestamp(recorded_time), kFrameIdUnknown); | 105 now, |
| 106 kAudioFrameReceived, |
| 107 GetVideoRtpTimestamp(recorded_time), |
| 108 kFrameIdUnknown); |
| 108 audio_encoder_->InsertAudio(audio_bus, recorded_time, done_callback); | 109 audio_encoder_->InsertAudio(audio_bus, recorded_time, done_callback); |
| 109 } | 110 } |
| 110 | 111 |
| 111 void AudioSender::SendEncodedAudioFrame( | 112 void AudioSender::SendEncodedAudioFrame( |
| 112 scoped_ptr<transport::EncodedAudioFrame> audio_frame, | 113 scoped_ptr<transport::EncodedAudioFrame> audio_frame, |
| 113 const base::TimeTicks& recorded_time) { | 114 const base::TimeTicks& recorded_time) { |
| 114 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 115 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 115 InitializeTimers(); | 116 InitializeTimers(); |
| 116 cast_environment_->PostTask( | 117 cast_environment_->PostTask( |
| 117 CastEnvironment::TRANSPORT, FROM_HERE, | 118 CastEnvironment::TRANSPORT, |
| 119 FROM_HERE, |
| 118 base::Bind(&AudioSender::SendEncodedAudioFrameToTransport, | 120 base::Bind(&AudioSender::SendEncodedAudioFrameToTransport, |
| 119 base::Unretained(this), base::Passed(&audio_frame), | 121 base::Unretained(this), |
| 122 base::Passed(&audio_frame), |
| 120 recorded_time)); | 123 recorded_time)); |
| 121 } | 124 } |
| 122 | 125 |
| 123 void AudioSender::SendEncodedAudioFrameToTransport( | 126 void AudioSender::SendEncodedAudioFrameToTransport( |
| 124 scoped_ptr<transport::EncodedAudioFrame> audio_frame, | 127 scoped_ptr<transport::EncodedAudioFrame> audio_frame, |
| 125 const base::TimeTicks& recorded_time) { | 128 const base::TimeTicks& recorded_time) { |
| 126 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::TRANSPORT)); | 129 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::TRANSPORT)); |
| 127 transport_sender_->InsertCodedAudioFrame(audio_frame.get(), recorded_time); | 130 transport_sender_->InsertCodedAudioFrame(audio_frame.get(), recorded_time); |
| 128 } | 131 } |
| 129 | 132 |
| 130 void AudioSender::ResendPackets( | 133 void AudioSender::ResendPackets( |
| 131 const MissingFramesAndPacketsMap& missing_frames_and_packets) { | 134 const MissingFramesAndPacketsMap& missing_frames_and_packets) { |
| 132 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 135 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 133 cast_environment_->PostTask( | 136 cast_environment_->PostTask( |
| 134 CastEnvironment::TRANSPORT, FROM_HERE, | 137 CastEnvironment::TRANSPORT, |
| 138 FROM_HERE, |
| 135 base::Bind(&AudioSender::ResendPacketsOnTransportThread, | 139 base::Bind(&AudioSender::ResendPacketsOnTransportThread, |
| 136 base::Unretained(this), missing_frames_and_packets)); | 140 base::Unretained(this), |
| 141 missing_frames_and_packets)); |
| 137 } | 142 } |
| 138 | 143 |
| 139 void AudioSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { | 144 void AudioSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { |
| 140 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 145 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 141 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | 146 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); |
| 142 } | 147 } |
| 143 | 148 |
| 144 void AudioSender::ScheduleNextRtcpReport() { | 149 void AudioSender::ScheduleNextRtcpReport() { |
| 145 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 150 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 146 base::TimeDelta time_to_next = | 151 base::TimeDelta time_to_next = |
| 147 rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks(); | 152 rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks(); |
| 148 | 153 |
| 149 time_to_next = std::max(time_to_next, | 154 time_to_next = std::max( |
| 150 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 155 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
| 151 | 156 |
| 152 cast_environment_->PostDelayedTask( | 157 cast_environment_->PostDelayedTask( |
| 153 CastEnvironment::MAIN, FROM_HERE, | 158 CastEnvironment::MAIN, |
| 159 FROM_HERE, |
| 154 base::Bind(&AudioSender::SendRtcpReport, weak_factory_.GetWeakPtr()), | 160 base::Bind(&AudioSender::SendRtcpReport, weak_factory_.GetWeakPtr()), |
| 155 time_to_next); | 161 time_to_next); |
| 156 } | 162 } |
| 157 | 163 |
| 158 void AudioSender::SendRtcpReport() { | 164 void AudioSender::SendRtcpReport() { |
| 159 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 165 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 160 // We don't send audio logging messages since all captured audio frames will | 166 // We don't send audio logging messages since all captured audio frames will |
| 161 // be sent. | 167 // be sent. |
| 162 transport::RtcpSenderLogMessage empty_msg; | 168 transport::RtcpSenderLogMessage empty_msg; |
| 163 rtcp_.SendRtcpFromRtpSender(empty_msg); | 169 rtcp_.SendRtcpFromRtpSender(empty_msg); |
| 164 ScheduleNextRtcpReport(); | 170 ScheduleNextRtcpReport(); |
| 165 } | 171 } |
| 166 | 172 |
| 167 void AudioSender::ResendPacketsOnTransportThread( | 173 void AudioSender::ResendPacketsOnTransportThread( |
| 168 const transport::MissingFramesAndPacketsMap& missing_packets) { | 174 const transport::MissingFramesAndPacketsMap& missing_packets) { |
| 169 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::TRANSPORT)); | 175 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::TRANSPORT)); |
| 170 transport_sender_->ResendPackets(true, missing_packets); | 176 transport_sender_->ResendPackets(true, missing_packets); |
| 171 } | 177 } |
| 172 | 178 |
| 173 } // namespace cast | 179 } // namespace cast |
| 174 } // namespace media | 180 } // namespace media |
| OLD | NEW |