chromium/chromecast/media/cma/backend/mixer/mixer_pipeline.h

// 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_CMA_BACKEND_MIXER_MIXER_PIPELINE_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_PIPELINE_H_

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

#include "base/containers/flat_map.h"
#include "chromecast/public/media/audio_post_processor_shlib.h"
#include "chromecast/public/media/media_pipeline_backend.h"

namespace base {
class Value;
}  // namespace base

namespace chromecast {
namespace media {

class FilterGroup;
class PostProcessingPipelineParser;
class PostProcessingPipelineFactory;

// Provides mixer and post-processing functionality for StreamMixer.
// Internally, MixerPipeline is a tree of post processors with two taps -
// LoopbackOutput and Output. Calling MixAndFilter causes the pipeline to pull
// data from inputs, mixing and filtering as described in cast_audio.json.
class MixerPipeline {
 public:
  // Attempts to create a pipeline from |config|.
  // Returns nullptr if config fails to parse.
  static std::unique_ptr<MixerPipeline> CreateMixerPipeline(
      PostProcessingPipelineParser* parser,
      PostProcessingPipelineFactory* factory,
      int expected_input_channels);

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

  ~MixerPipeline();

  // Sets the sample rate of all processors.
  void Initialize(int samples_per_second, int frames_per_write);

  // Returns the FilterGroup that should process a stream with |device_id| or
  // |nullptr| if no matching FilterGroup is found.
  FilterGroup* GetInputGroup(const std::string& device_id);

  // Polls |MixerInput|s for |frames_per_write| frames of audio data, mixes the
  // inputs, and applies PostProcessors.
  // |rendering_delay| is the rendering delay of the output device, and is used
  // to calculate the delay from various points in the pipeline.
  void MixAndFilter(
      int frames_per_write,
      MediaPipelineBackend::AudioDecoder::RenderingDelay rendering_delay);

  // Returns the output data from the "mix" group.
  float* GetLoopbackOutput();

  // Returns the output data from the "linearize" group.
  float* GetOutput();

  // Returns the number of channels that will be present in GetLoopbackOutput().
  int GetLoopbackChannelCount() const;

  // Returns the number of channels that will be present in GetOutput().
  int GetOutputChannelCount() const;

  // Attempts to send |config| to PostProcessors with |name|.
  void SetPostProcessorConfig(const std::string& name,
                              const std::string& config);

  // Returns the rendering delay between audio coming from GetLoopbackOutput()
  // and GetOutput(), i.e. the group delay of PostProcessors in "linearize"
  int64_t GetPostLoopbackRenderingDelayMicroseconds() const;

  // Determines whether the pipeline is still ringing out after all input
  // streams have stopped playing.
  bool IsRinging() const;

 private:
  // External classes should call CreateMixerPipeline.
  MixerPipeline();

  // Attempts to build a pipeline using |config|. Returns |true| IFF successful.
  bool BuildPipeline(PostProcessingPipelineParser* config,
                     PostProcessingPipelineFactory* factory,
                     int expected_input_channels);

  // Adds |ids| to the list of DeviceIds |filter_group| can process.
  bool SetGroupDeviceIds(const base::Value* ids, FilterGroup* filter_group);

  std::vector<std::unique_ptr<FilterGroup>> filter_groups_;
  base::flat_map<std::string, FilterGroup*> stream_sinks_;
  FilterGroup* loopback_output_group_ = nullptr;
  FilterGroup* output_group_ = nullptr;
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_PIPELINE_H_