chromium/chromecast/media/cma/backend/alsa/alsa_volume_control.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_ALSA_VOLUME_CONTROL_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_ALSA_VOLUME_CONTROL_H_

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/timer/timer.h"
#include "chromecast/media/cma/backend/system_volume_control.h"
#include "media/audio/alsa/alsa_wrapper.h"

namespace chromecast {
namespace media {
class ScopedAlsaMixer;

// SystemVolumeControl implementation for ALSA.
class AlsaVolumeControl : public SystemVolumeControl {
 public:
  AlsaVolumeControl(Delegate* delegate,
                    std::unique_ptr<::media::AlsaWrapper> alsa);

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

  ~AlsaVolumeControl() override;

  // SystemVolumeControl interface.
  float GetRoundtripVolume(float volume) override;
  float DbToVolumeLevel(float db_volume) override;
  float VolumeLevelToDb(float level) override;
  float GetVolume() override;
  void SetVolume(float level) override;
  bool IsMuted() override;
  void SetMuted(bool muted) override;
  void SetPowerSave(bool power_save_on) override;
  void SetLimit(float limit) override;

 private:
  static std::string GetVolumeElementName();
  static std::string GetVolumeDeviceName();
  static std::string GetMuteElementName(::media::AlsaWrapper* alsa,
                                        const std::string& mixer_card_name,
                                        const std::string& mixer_element_name,
                                        const std::string& mute_card_name);
  static std::string GetMuteDeviceName();
  static std::vector<std::string> GetAmpElementNames();
  static std::string GetAmpDeviceName();

  static int VolumeOrMuteChangeCallback(snd_mixer_elem_t* elem,
                                        unsigned int mask);

  bool SetElementMuted(ScopedAlsaMixer* mixer, bool muted);
  // Returns true if all channels are muted, returns std::nullopt if element
  // state is not accessible.
  std::optional<bool> IsElementAllMuted(ScopedAlsaMixer* mixer);

  void OnVolumeOrMuteChanged();

  void CheckPowerSave();

  Delegate* const delegate_;

  const std::unique_ptr<::media::AlsaWrapper> alsa_;
  const std::string volume_mixer_device_name_;
  const std::string volume_mixer_element_name_;
  const std::string mute_mixer_device_name_;
  const std::string mute_mixer_element_name_;
  const std::string amp_mixer_device_name_;
  const std::vector<std::string> amp_mixer_element_names_;

  long volume_range_min_;  // NOLINT(runtime/int)
  long volume_range_max_;  // NOLINT(runtime/int)

  std::unique_ptr<ScopedAlsaMixer> volume_mixer_;
  std::unique_ptr<ScopedAlsaMixer> mute_mixer_;
  ScopedAlsaMixer* mute_mixer_ptr_;
  std::vector<std::unique_ptr<ScopedAlsaMixer>> amp_mixers_;

  bool last_power_save_on_ = false;
  base::OneShotTimer power_save_timer_;
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_ALSA_VOLUME_CONTROL_H_