chromium/chromecast/media/audio/mixer_service/control_connection.h

// Copyright 2019 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_MIXER_SERVICE_CONTROL_CONNECTION_H_
#define CHROMECAST_MEDIA_AUDIO_MIXER_SERVICE_CONTROL_CONNECTION_H_

#include <list>
#include <memory>
#include <string>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "chromecast/media/audio/mixer_service/mixer_connection.h"
#include "chromecast/media/audio/mixer_service/mixer_socket.h"
#include "chromecast/public/volume_control.h"

namespace chromecast {
namespace media {
namespace mixer_service {

// Mixer service connection for controlling general mixer properties, such as
// device volume and postprocessor configuration. Not thread-safe; all usage of
// a given instance must be on the same sequence. Must be created on an IO
// thread.
class ControlConnection : public MixerConnection, public MixerSocket::Delegate {
 public:
  using ConnectedCallback = base::RepeatingClosure;

  // Callback to receive mixer stream count changes.
  using StreamCountCallback =
      base::RepeatingCallback<void(int primary_streams, int sfx_streams)>;

  // Callback that handles ListPostProcessors response.
  using ListPostprocessorsCallback =
      base::OnceCallback<void(const std::vector<std::string>&)>;

  ControlConnection();

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

  ~ControlConnection() override;

  // Connects to the mixer. If the mixer connection is lost, this will
  // automatically reconnect. If |callback| is nonempty, it will be called each
  // time a connection is (re)established with the mixer. This can be used to
  // re-send postprocessor messages, since they are not persisted across
  // disconnects.
  void Connect(ConnectedCallback callback = ConnectedCallback());

  // Sets volume multiplier for all streams of a given content type.
  void SetVolume(AudioContentType type, float volume_multiplier);

  // Sets mute state all streams of a given content type.
  void SetMuted(AudioContentType type, bool muted);

  // Sets the maximum effective volume multiplier for a given content type.
  void SetVolumeLimit(AudioContentType type, float max_volume_multiplier);

  // Returns a set of registered builtin post-processors.
  void ListPostprocessors(ListPostprocessorsCallback callback);

  // Sends arbitrary config data to a specific postprocessor. Config is saved
  // for each unique |name| and will be resent if the mixer disconnects and then
  // reconnects. If the |postprocessor_name| contains a '?', that character and
  // the remainder of the name string will not be sent to the mixer; this is
  // useful for configuring multiple subprocessors (eg for the dynamic range
  // processor).
  void ConfigurePostprocessor(std::string postprocessor_name,
                              std::string config);

  // Sends a message a specific postprocessor. Messages are not saved and will
  // not be resent if the mixer disconnects and then reconnects.
  void SendPostprocessorMessage(std::string postprocessor_name,
                                std::string message);

  // Instructs the mixer to reload postprocessors based on the config file.
  void ReloadPostprocessors();

  // Sets a callback to receive mixer stream count changes. |callback| may be an
  // empty callback to remove it.
  void SetStreamCountCallback(StreamCountCallback callback);

  // Sets the desired number of output channels used by the mixer. This will
  // cause an audio interruption on any currently active streams. The actual
  // output channel count is determined by the output implementation and may not
  // match |num_channels|.
  void SetNumOutputChannels(int num_channels);

 private:
  bool SendPostprocessorMessageInternal(std::string postprocessor_name,
                                        std::string message);
  void OnSendFailed();

  // MixerConnection implementation:
  void OnConnected(std::unique_ptr<MixerSocket> socket) override;
  void OnConnectionError() override;

  // MixerSocket::Delegate implementation:
  bool HandleMetadata(const Generic& message) override;

  std::unique_ptr<MixerSocket> socket_;

  ConnectedCallback connect_callback_;

  base::flat_map<AudioContentType, float> volume_;
  base::flat_map<AudioContentType, bool> muted_;
  base::flat_map<AudioContentType, float> volume_limit_;

  base::flat_map<std::string, std::string> postprocessor_config_;

  StreamCountCallback stream_count_callback_;
  // Uses std::list to trigger callbacks in FIFO order.
  std::list<ListPostprocessorsCallback> list_postprocessors_callbacks_;
  int num_output_channels_ = 0;
};

}  // namespace mixer_service
}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_AUDIO_MIXER_SERVICE_CONTROL_CONNECTION_H_