chromium/chromecast/media/cma/backend/alsa/mixer_output_stream_alsa.h

// Copyright 2017 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_CMA_BACKEND_ALSA_MIXER_OUTPUT_STREAM_ALSA_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_MIXER_OUTPUT_STREAM_ALSA_H_

#include <alsa/asoundlib.h>

#include <cstdint>
#include <vector>

#include "chromecast/public/media/mixer_output_stream.h"

namespace chromecast {
namespace media {

class AlsaWrapper;

// MixerOutputStream implementation for ALSA
class MixerOutputStreamAlsa : public MixerOutputStream {
 public:
  MixerOutputStreamAlsa();

  MixerOutputStreamAlsa(const MixerOutputStreamAlsa&) = delete;
  MixerOutputStreamAlsa& operator=(const MixerOutputStreamAlsa&) = delete;

  ~MixerOutputStreamAlsa() override;

  void SetAlsaWrapperForTest(std::unique_ptr<AlsaWrapper> alsa);

  // MixerOutputStream implementation:
  bool Start(int requested_sample_rate, int channels) override;
  int GetNumChannels() override;
  int GetSampleRate() override;
  MediaPipelineBackend::AudioDecoder::RenderingDelay GetRenderingDelay()
      override;
  int OptimalWriteFramesCount() override;
  bool Write(const float* data,
             int data_size,
             bool* out_playback_interrupted) override;
  void Stop() override;

 private:
  // Reads the buffer size, period size, start threshold, and avail min value
  // from the provided command line flags or uses default values if no flags are
  // provided.
  void DefineAlsaParameters();

  // Takes the provided ALSA config and sets all ALSA output hardware/software
  // playback parameters.  It will try to select sane fallback parameters based
  // on what the output hardware supports and will log warnings if it does so.
  // If any ALSA function returns an unexpected error code, the error code will
  // be returned by this function. Otherwise, it will return 0.
  int SetAlsaPlaybackParams(int requested_rate);

  // Determines output sample rate based on the requested rate and the sample
  // rate the device supports.
  int DetermineOutputRate(int requested_rate);

  void UpdateRenderingDelay();

  // Checks ALSA output for current state and if it's suspended, tries to
  // recover.
  // Returns true if ALSA device is recovered successfully.
  bool MaybeRecoverDeviceFromSuspendedState();

  std::unique_ptr<AlsaWrapper> alsa_;

  snd_pcm_t* pcm_ = nullptr;
  snd_pcm_hw_params_t* pcm_hw_params_ = nullptr;
  snd_pcm_status_t* pcm_status_ = nullptr;
  snd_pcm_format_t pcm_format_ = SND_PCM_FORMAT_UNKNOWN;

  int num_output_channels_ = 0;
  int sample_rate_ = kInvalidSampleRate;

  // User-configurable ALSA parameters. This caches the results, so the code
  // only has to interact with the command line parameters once.
  snd_pcm_uframes_t alsa_buffer_size_ = 0;
  snd_pcm_uframes_t alsa_period_size_ = 0;
  snd_pcm_uframes_t alsa_start_threshold_ = 0;
  snd_pcm_uframes_t alsa_avail_min_ = 0;

  bool first_write_ = false;
  MediaPipelineBackend::AudioDecoder::RenderingDelay rendering_delay_;

  std::vector<uint8_t> output_buffer_;
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_MIXER_OUTPUT_STREAM_ALSA_H_