Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Unified Diff: media/cast/audio_sender/audio_encoder.cc

Issue 388663003: Cast: Reshuffle files under media/cast (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: missing includes Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/cast/audio_sender/audio_encoder.h ('k') | media/cast/audio_sender/audio_encoder_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/cast/audio_sender/audio_encoder.cc
diff --git a/media/cast/audio_sender/audio_encoder.cc b/media/cast/audio_sender/audio_encoder.cc
deleted file mode 100644
index 8f7977b6c336982cdf5a72b8cf721a25f155f517..0000000000000000000000000000000000000000
--- a/media/cast/audio_sender/audio_encoder.cc
+++ /dev/null
@@ -1,385 +0,0 @@
-// 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_encoder.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/location.h"
-#include "base/stl_util.h"
-#include "base/sys_byteorder.h"
-#include "base/time/time.h"
-#include "media/base/audio_bus.h"
-#include "media/cast/cast_defines.h"
-#include "media/cast/cast_environment.h"
-#include "third_party/opus/src/include/opus.h"
-
-namespace media {
-namespace cast {
-
-namespace {
-
-// The fixed number of audio frames per second and, inversely, the duration of
-// one frame's worth of samples.
-const int kFramesPerSecond = 100;
-const int kFrameDurationMillis = 1000 / kFramesPerSecond; // No remainder!
-
-// Threshold used to decide whether audio being delivered to the encoder is
-// coming in too slow with respect to the capture timestamps.
-const int kUnderrunThresholdMillis = 3 * kFrameDurationMillis;
-
-} // namespace
-
-
-// Base class that handles the common problem of feeding one or more AudioBus'
-// data into a buffer and then, once the buffer is full, encoding the signal and
-// emitting an EncodedFrame via the FrameEncodedCallback.
-//
-// Subclasses complete the implementation by handling the actual encoding
-// details.
-class AudioEncoder::ImplBase
- : public base::RefCountedThreadSafe<AudioEncoder::ImplBase> {
- public:
- ImplBase(const scoped_refptr<CastEnvironment>& cast_environment,
- transport::Codec codec,
- int num_channels,
- int sampling_rate,
- const FrameEncodedCallback& callback)
- : cast_environment_(cast_environment),
- codec_(codec),
- num_channels_(num_channels),
- samples_per_frame_(sampling_rate / kFramesPerSecond),
- callback_(callback),
- cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED),
- buffer_fill_end_(0),
- frame_id_(0),
- frame_rtp_timestamp_(0) {
- // Support for max sampling rate of 48KHz, 2 channels, 100 ms duration.
- const int kMaxSamplesTimesChannelsPerFrame = 48 * 2 * 100;
- if (num_channels_ <= 0 || samples_per_frame_ <= 0 ||
- sampling_rate % kFramesPerSecond != 0 ||
- samples_per_frame_ * num_channels_ > kMaxSamplesTimesChannelsPerFrame) {
- cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION;
- }
- }
-
- CastInitializationStatus InitializationResult() const {
- return cast_initialization_status_;
- }
-
- void EncodeAudio(scoped_ptr<AudioBus> audio_bus,
- const base::TimeTicks& recorded_time) {
- DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED);
- DCHECK(!recorded_time.is_null());
-
- // Determine whether |recorded_time| is consistent with the amount of audio
- // data having been processed in the past. Resolve the underrun problem by
- // dropping data from the internal buffer and skipping ahead the next
- // frame's RTP timestamp by the estimated number of frames missed. On the
- // other hand, don't attempt to resolve overruns: A receiver should
- // gracefully deal with an excess of audio data.
- const base::TimeDelta frame_duration =
- base::TimeDelta::FromMilliseconds(kFrameDurationMillis);
- base::TimeDelta buffer_fill_duration =
- buffer_fill_end_ * frame_duration / samples_per_frame_;
- if (!frame_capture_time_.is_null()) {
- const base::TimeDelta amount_ahead_by =
- recorded_time - (frame_capture_time_ + buffer_fill_duration);
- if (amount_ahead_by >
- base::TimeDelta::FromMilliseconds(kUnderrunThresholdMillis)) {
- buffer_fill_end_ = 0;
- buffer_fill_duration = base::TimeDelta();
- const int64 num_frames_missed = amount_ahead_by /
- base::TimeDelta::FromMilliseconds(kFrameDurationMillis);
- frame_rtp_timestamp_ +=
- static_cast<uint32>(num_frames_missed * samples_per_frame_);
- DVLOG(1) << "Skipping RTP timestamp ahead to account for "
- << num_frames_missed * samples_per_frame_
- << " samples' worth of underrun.";
- }
- }
- frame_capture_time_ = recorded_time - buffer_fill_duration;
-
- // Encode all audio in |audio_bus| into zero or more frames.
- int src_pos = 0;
- while (src_pos < audio_bus->frames()) {
- const int num_samples_to_xfer = std::min(
- samples_per_frame_ - buffer_fill_end_, audio_bus->frames() - src_pos);
- DCHECK_EQ(audio_bus->channels(), num_channels_);
- TransferSamplesIntoBuffer(
- audio_bus.get(), src_pos, buffer_fill_end_, num_samples_to_xfer);
- src_pos += num_samples_to_xfer;
- buffer_fill_end_ += num_samples_to_xfer;
-
- if (buffer_fill_end_ < samples_per_frame_)
- break;
-
- scoped_ptr<transport::EncodedFrame> audio_frame(
- new transport::EncodedFrame());
- audio_frame->dependency = transport::EncodedFrame::KEY;
- audio_frame->frame_id = frame_id_;
- audio_frame->referenced_frame_id = frame_id_;
- audio_frame->rtp_timestamp = frame_rtp_timestamp_;
- audio_frame->reference_time = frame_capture_time_;
-
- if (EncodeFromFilledBuffer(&audio_frame->data)) {
- cast_environment_->PostTask(
- CastEnvironment::MAIN,
- FROM_HERE,
- base::Bind(callback_, base::Passed(&audio_frame)));
- }
-
- // Reset the internal buffer, frame ID, and timestamps for the next frame.
- buffer_fill_end_ = 0;
- ++frame_id_;
- frame_rtp_timestamp_ += samples_per_frame_;
- frame_capture_time_ += frame_duration;
- }
- }
-
- protected:
- friend class base::RefCountedThreadSafe<ImplBase>;
- virtual ~ImplBase() {}
-
- virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
- int source_offset,
- int buffer_fill_offset,
- int num_samples) = 0;
- virtual bool EncodeFromFilledBuffer(std::string* out) = 0;
-
- const scoped_refptr<CastEnvironment> cast_environment_;
- const transport::Codec codec_;
- const int num_channels_;
- const int samples_per_frame_;
- const FrameEncodedCallback callback_;
-
- // Subclass' ctor is expected to set this to STATUS_AUDIO_INITIALIZED.
- CastInitializationStatus cast_initialization_status_;
-
- private:
- // In the case where a call to EncodeAudio() cannot completely fill the
- // buffer, this points to the position at which to populate data in a later
- // call.
- int buffer_fill_end_;
-
- // A counter used to label EncodedFrames.
- uint32 frame_id_;
-
- // The RTP timestamp for the next frame of encoded audio. This is defined as
- // the number of audio samples encoded so far, plus the estimated number of
- // samples that were missed due to data underruns. A receiver uses this value
- // to detect gaps in the audio signal data being provided. Per the spec, RTP
- // timestamp values are allowed to overflow and roll around past zero.
- uint32 frame_rtp_timestamp_;
-
- // The local system time associated with the start of the next frame of
- // encoded audio. This value is passed on to a receiver as a reference clock
- // timestamp for the purposes of synchronizing audio and video. Its
- // progression is expected to drift relative to the elapsed time implied by
- // the RTP timestamps.
- base::TimeTicks frame_capture_time_;
-
- DISALLOW_COPY_AND_ASSIGN(ImplBase);
-};
-
-class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase {
- public:
- OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment,
- int num_channels,
- int sampling_rate,
- int bitrate,
- const FrameEncodedCallback& callback)
- : ImplBase(cast_environment,
- transport::CODEC_AUDIO_OPUS,
- num_channels,
- sampling_rate,
- callback),
- encoder_memory_(new uint8[opus_encoder_get_size(num_channels)]),
- opus_encoder_(reinterpret_cast<OpusEncoder*>(encoder_memory_.get())),
- buffer_(new float[num_channels * samples_per_frame_]) {
- if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED)
- return;
- if (opus_encoder_init(opus_encoder_,
- sampling_rate,
- num_channels,
- OPUS_APPLICATION_AUDIO) != OPUS_OK) {
- ImplBase::cast_initialization_status_ =
- STATUS_INVALID_AUDIO_CONFIGURATION;
- return;
- }
- ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED;
-
- if (bitrate <= 0) {
- // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a
- // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms
- // frame size. The opus library authors may, of course, adjust this in
- // later versions.
- bitrate = OPUS_AUTO;
- }
- CHECK_EQ(opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)),
- OPUS_OK);
- }
-
- private:
- virtual ~OpusImpl() {}
-
- virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
- int source_offset,
- int buffer_fill_offset,
- int num_samples) OVERRIDE {
- // Opus requires channel-interleaved samples in a single array.
- for (int ch = 0; ch < audio_bus->channels(); ++ch) {
- const float* src = audio_bus->channel(ch) + source_offset;
- const float* const src_end = src + num_samples;
- float* dest = buffer_.get() + buffer_fill_offset * num_channels_ + ch;
- for (; src < src_end; ++src, dest += num_channels_)
- *dest = *src;
- }
- }
-
- virtual bool EncodeFromFilledBuffer(std::string* out) OVERRIDE {
- out->resize(kOpusMaxPayloadSize);
- const opus_int32 result =
- opus_encode_float(opus_encoder_,
- buffer_.get(),
- samples_per_frame_,
- reinterpret_cast<uint8*>(string_as_array(out)),
- kOpusMaxPayloadSize);
- if (result > 1) {
- out->resize(result);
- return true;
- } else if (result < 0) {
- LOG(ERROR) << "Error code from opus_encode_float(): " << result;
- return false;
- } else {
- // Do nothing: The documentation says that a return value of zero or
- // one byte means the packet does not need to be transmitted.
- return false;
- }
- }
-
- const scoped_ptr<uint8[]> encoder_memory_;
- OpusEncoder* const opus_encoder_;
- const scoped_ptr<float[]> buffer_;
-
- // This is the recommended value, according to documentation in
- // third_party/opus/src/include/opus.h, so that the Opus encoder does not
- // degrade the audio due to memory constraints.
- //
- // Note: Whereas other RTP implementations do not, the cast library is
- // perfectly capable of transporting larger than MTU-sized audio frames.
- static const int kOpusMaxPayloadSize = 4000;
-
- DISALLOW_COPY_AND_ASSIGN(OpusImpl);
-};
-
-class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase {
- public:
- Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment,
- int num_channels,
- int sampling_rate,
- const FrameEncodedCallback& callback)
- : ImplBase(cast_environment,
- transport::CODEC_AUDIO_PCM16,
- num_channels,
- sampling_rate,
- callback),
- buffer_(new int16[num_channels * samples_per_frame_]) {
- if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED)
- return;
- cast_initialization_status_ = STATUS_AUDIO_INITIALIZED;
- }
-
- private:
- virtual ~Pcm16Impl() {}
-
- virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
- int source_offset,
- int buffer_fill_offset,
- int num_samples) OVERRIDE {
- audio_bus->ToInterleavedPartial(
- source_offset,
- num_samples,
- sizeof(int16),
- buffer_.get() + buffer_fill_offset * num_channels_);
- }
-
- virtual bool EncodeFromFilledBuffer(std::string* out) OVERRIDE {
- // Output 16-bit PCM integers in big-endian byte order.
- out->resize(num_channels_ * samples_per_frame_ * sizeof(int16));
- const int16* src = buffer_.get();
- const int16* const src_end = src + num_channels_ * samples_per_frame_;
- uint16* dest = reinterpret_cast<uint16*>(&out->at(0));
- for (; src < src_end; ++src, ++dest)
- *dest = base::HostToNet16(*src);
- return true;
- }
-
- private:
- const scoped_ptr<int16[]> buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(Pcm16Impl);
-};
-
-AudioEncoder::AudioEncoder(
- const scoped_refptr<CastEnvironment>& cast_environment,
- int num_channels,
- int sampling_rate,
- int bitrate,
- transport::Codec codec,
- const FrameEncodedCallback& frame_encoded_callback)
- : cast_environment_(cast_environment) {
- // Note: It doesn't matter which thread constructs AudioEncoder, just so long
- // as all calls to InsertAudio() are by the same thread.
- insert_thread_checker_.DetachFromThread();
- switch (codec) {
- case transport::CODEC_AUDIO_OPUS:
- impl_ = new OpusImpl(cast_environment,
- num_channels,
- sampling_rate,
- bitrate,
- frame_encoded_callback);
- break;
- case transport::CODEC_AUDIO_PCM16:
- impl_ = new Pcm16Impl(cast_environment,
- num_channels,
- sampling_rate,
- frame_encoded_callback);
- break;
- default:
- NOTREACHED() << "Unsupported or unspecified codec for audio encoder";
- break;
- }
-}
-
-AudioEncoder::~AudioEncoder() {}
-
-CastInitializationStatus AudioEncoder::InitializationResult() const {
- DCHECK(insert_thread_checker_.CalledOnValidThread());
- if (impl_) {
- return impl_->InitializationResult();
- }
- return STATUS_UNSUPPORTED_AUDIO_CODEC;
-}
-
-void AudioEncoder::InsertAudio(scoped_ptr<AudioBus> audio_bus,
- const base::TimeTicks& recorded_time) {
- DCHECK(insert_thread_checker_.CalledOnValidThread());
- DCHECK(audio_bus.get());
- if (!impl_) {
- NOTREACHED();
- return;
- }
- cast_environment_->PostTask(CastEnvironment::AUDIO,
- FROM_HERE,
- base::Bind(&AudioEncoder::ImplBase::EncodeAudio,
- impl_,
- base::Passed(&audio_bus),
- recorded_time));
-}
-
-} // namespace cast
-} // namespace media
« no previous file with comments | « media/cast/audio_sender/audio_encoder.h ('k') | media/cast/audio_sender/audio_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698