1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_ALSA_H_
6#define CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_ALSA_H_
7#pragma once
8
9#include "base/basictypes.h"
10#include "base/callback.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/synchronization/lock.h"
13#include "base/synchronization/waitable_event.h"
14#include "base/threading/thread.h"
15#include "chrome/browser/chromeos/audio_mixer.h"
16
17class PrefService;
18
19struct _snd_mixer_elem;
20struct _snd_mixer;
21
22namespace chromeos {
23
24class AudioMixerAlsa : public AudioMixer {
25 public:
26  AudioMixerAlsa();
27  virtual ~AudioMixerAlsa();
28
29  // Implementation of AudioMixer
30  virtual void Init(InitDoneCallback* callback);
31  virtual bool InitSync();
32  virtual double GetVolumeDb() const;
33  virtual bool GetVolumeLimits(double* vol_min, double* vol_max);
34  virtual void SetVolumeDb(double vol_db);
35  virtual bool IsMute() const;
36  virtual void SetMute(bool mute);
37  virtual State GetState() const;
38
39  // Registers volume and mute in preferences
40  static void RegisterPrefs(PrefService* local_state);
41
42 private:
43  // Called to do initialization in background from worker thread.
44  void DoInit(InitDoneCallback* callback);
45
46  // Helper functions to get our message loop thread and prefs initialized.
47  bool InitThread();
48  void InitPrefs();
49
50  // Try to connect to the ALSA mixer through their simple controls interface,
51  // and cache mixer handle and mixer elements we'll be using.
52  bool InitializeAlsaMixer();
53  void FreeAlsaMixer();
54  void DoSetVolumeMute(double pref_volume, int pref_mute);
55
56  // Access to PrefMember variables must be done on UI thread.
57  void RestoreVolumeMuteOnUIThread();
58
59  // All these internal volume commands must be called with the lock held.
60  double DoGetVolumeDb_Locked() const;
61  void DoSetVolumeDb_Locked(double vol_db);
62
63  _snd_mixer_elem* FindElementWithName_Locked(_snd_mixer* handle,
64                                              const char* element_name) const;
65
66  bool GetElementVolume_Locked(_snd_mixer_elem* elem,
67                               double* current_vol) const;
68
69  // Since volume is done in steps, we may not get the exact volume asked for,
70  // so actual_vol will contain the true volume that was set.  This information
71  // can be used to further refine the volume by adjust a different mixer
72  // element.  The rounding_bias is added in before rounding to the nearest
73  // volume step (use 0.5 to round to nearest).
74  bool SetElementVolume_Locked(_snd_mixer_elem* elem,
75                               double new_vol,
76                               double* actual_vol,
77                               double rounding_bias);
78
79  // In ALSA, the mixer element's 'switch' is turned off to mute.
80  // GetElementMuted_Locked() returns false on failure.
81  bool GetElementMuted_Locked(_snd_mixer_elem* elem) const;
82  void SetElementMuted_Locked(_snd_mixer_elem* elem, bool mute);
83
84  // Volume range limits are computed once during InitializeAlsaMixer.
85  double min_volume_;
86  double max_volume_;
87
88  // Muting is done by setting volume to minimum, so we must save the original.
89  // This is the only state information kept in this object.  In some cases,
90  // ALSA can report it has a volume switch and we can turn it off, but it has
91  // no effect.
92  double save_volume_;
93
94  mutable base::Lock mixer_state_lock_;
95  mutable State mixer_state_;
96
97  // Cached contexts for use in ALSA calls.
98  _snd_mixer* alsa_mixer_;
99  _snd_mixer_elem* elem_master_;
100  _snd_mixer_elem* elem_pcm_;
101
102  PrefService* prefs_;
103  base::WaitableEvent done_event_;
104
105  scoped_ptr<base::Thread> thread_;
106
107  DISALLOW_COPY_AND_ASSIGN(AudioMixerAlsa);
108};
109
110}  // namespace chromeos
111
112DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::AudioMixerAlsa);
113
114#endif  // CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_ALSA_H_
115