blob: 68ae72808d080770203396796c313477e1a2d5c0 [file] [log] [blame]
// Copyright 2018 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.
#ifndef CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_FADER_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_FADER_H_
#include <memory>
#include "base/macros.h"
namespace media {
class AudioBus;
} // namespace media
namespace chromecast {
namespace media {
// AudioFader handles smoothly fading audio in/out when a stream underruns
// (ie, when the data source does not have any data to provide when the output
// requests it). This prevents pops and clicks. Internally, it buffers enough
// data to ensure that a full fade can always take place if necessary; note that
// this increases output latency by |fade_frames| samples. All methods except
// constructor/destructor must be called on the same thread.
class AudioFader {
public:
// The source of real audio data for the fader.
class Source {
public:
// Fills at most |num_frames| frames of audio into |buffer|, starting at
// |frame_offset|. Returns the actual number of frames of audio that were
// filled (may be less than |num_frames| if the source does not have
// enough data). This method is only called synchronously from within
// a call to FillFrames().
virtual int FillFaderFrames(::media::AudioBus* buffer,
int frame_offset,
int num_frames) = 0;
protected:
virtual ~Source() = default;
};
// |fade_frames| is the number of frames over which a complete fade in/out
// will take place.
AudioFader(Source* source, int num_channels, int fade_frames);
~AudioFader();
int buffered_frames() const { return buffered_frames_; }
// Fills |buffer| with up to |num_frames| frames of data, starting at
// |write_offset| within |buffer|, and fading as appropriate to avoid
// pops/clicks. This will call through to the source to get more data. Returns
// the number of frames filled.
int FillFrames(int num_frames, ::media::AudioBus* buffer, int write_offset);
// Returns the total number of frames that will be requested from the source
// (potentially over multiple calls to source_->FillFaderFrames()) if
// FillFrames() is called to fill |num_fill_frames| frames.
int FramesNeededFromSource(int num_fill_frames) const;
// Helper methods to fade in/out an AudioBus. |buffer| contains the data to
// fade; |filled_frames| is the amount of data actually in |buffer| (if the
// buffer was partially filled, this will not be equal to buffer->frames()).
// |write_offset| is the offset within |buffer| to starting writing frames
// to. |fade_frames| is the number of frames over which a complete fade should
// happen (ie, how many frames it takes to go from a 1.0 to 0.0 multiplier).
// |fade_frames_remaining| is the number of frames left in the current fade
// (which will be less than |fade_frames| if part of the fade has already
// been completed on a previous buffer).
static void FadeInHelper(::media::AudioBus* buffer,
int filled_frames,
int write_offset,
int fade_frames,
int fade_frames_remaining);
static void FadeOutHelper(::media::AudioBus* buffer,
int filled_frames,
int write_offset,
int fade_frames,
int fade_frames_remaining);
private:
enum class State {
kSilent,
kFadingIn,
kPlaying,
kFadingOut,
};
void CompleteFill(::media::AudioBus* buffer,
int filled_frames,
int write_offset);
void IncompleteFill(::media::AudioBus* buffer,
int filled_frames,
int write_offset);
void FadeIn(::media::AudioBus* buffer, int filled_frames, int write_offset);
void FadeOut(::media::AudioBus* buffer, int filled_frames, int write_offset);
Source* const source_;
const int fade_frames_;
State state_;
std::unique_ptr<::media::AudioBus> fade_buffer_;
int buffered_frames_;
int fade_frames_remaining_;
DISALLOW_COPY_AND_ASSIGN(AudioFader);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_FADER_H_