// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_MEDIA_AUDIO_AUDIO_FADER_H_
#define CHROMECAST_MEDIA_AUDIO_AUDIO_FADER_H_
#include <cstdint>
#include <memory>
#include "base/time/time.h"
#include "chromecast/media/api/audio_provider.h"
#include "chromecast/media/audio/cast_audio_bus.h"
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 AudioProvider {
public:
AudioFader(AudioProvider* provider,
base::TimeDelta fade_time,
double playback_rate);
AudioFader(AudioProvider* provider, int fade_frames, double playback_rate);
AudioFader(const AudioFader&) = delete;
AudioFader& operator=(const AudioFader&) = delete;
~AudioFader() override;
int buffered_frames() const { return buffered_frames_; }
// AudioProvider implementation:
int FillFrames(int num_frames,
int64_t playout_timestamp,
float* const* channel_data) override;
size_t num_channels() const override;
int sample_rate() const override;
void set_playback_rate(double playback_rate) {
playback_rate_ = playback_rate;
}
// 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 a buffer. |channel_data| contains the data to
// fade; |filled_frames| is the amount of data actually in |channel_data|.
// |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(float* const* channel_data,
size_t num_channels,
int filled_frames,
int fade_frames,
int fade_frames_remaining);
static void FadeOutHelper(float* const* channel_data,
size_t num_channels,
int filled_frames,
int fade_frames,
int fade_frames_remaining);
private:
enum class State {
kSilent,
kFadingIn,
kPlaying,
kFadingOut,
};
int64_t FramesToMicroseconds(int64_t frames);
void CompleteFill(float* const* channel_data, int filled_frames);
void IncompleteFill(float* const* channel_data, int filled_frames);
void FadeIn(float* const* channel_data, int filled_frames);
void FadeOut(float* const* channel_data, int filled_frames);
AudioProvider* const provider_;
const int fade_frames_;
const size_t num_channels_;
const int sample_rate_;
double playback_rate_;
State state_ = State::kSilent;
std::unique_ptr<CastAudioBus> fade_buffer_;
int buffered_frames_ = 0;
int fade_frames_remaining_ = 0;
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_AUDIO_AUDIO_FADER_H_