Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chromeos / audio / cras_audio_handler.cc
1 // Copyright (c) 2013 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 #include "chromeos/audio/cras_audio_handler.h"
6
7 #include <algorithm>
8 #include <cmath>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/logging.h"
13 #include "chromeos/audio/audio_devices_pref_handler.h"
14 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16
17 using std::max;
18 using std::min;
19
20 namespace chromeos {
21
22 namespace {
23
24 // Default value for unmuting, as a percent in the range [0, 100].
25 // Used when sound is unmuted, but volume was less than kMuteThresholdPercent.
26 const int kDefaultUnmuteVolumePercent = 4;
27
28 // Volume value which should be considered as muted in range [0, 100].
29 const int kMuteThresholdPercent = 1;
30
31 static CrasAudioHandler* g_cras_audio_handler = NULL;
32
33 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) {
34   return a.id == b.id && a.is_input == b.is_input && a.type == b.type
35       && a.device_name == b.device_name;
36 }
37
38 bool IsInNodeList(uint64 node_id, const CrasAudioHandler::NodeIdList& id_list) {
39   return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end();
40 }
41
42 }  // namespace
43
44 CrasAudioHandler::AudioObserver::AudioObserver() {
45 }
46
47 CrasAudioHandler::AudioObserver::~AudioObserver() {
48 }
49
50 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() {
51 }
52
53 void CrasAudioHandler::AudioObserver::OnInputGainChanged() {
54 }
55
56 void CrasAudioHandler::AudioObserver::OnOutputMuteChanged() {
57 }
58
59 void CrasAudioHandler::AudioObserver::OnInputMuteChanged() {
60 }
61
62 void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() {
63 }
64
65 void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() {
66 }
67
68 void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() {
69 }
70
71 // static
72 void CrasAudioHandler::Initialize(
73     scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler) {
74   CHECK(!g_cras_audio_handler);
75   g_cras_audio_handler = new CrasAudioHandler(audio_pref_handler);
76 }
77
78 // static
79 void CrasAudioHandler::InitializeForTesting() {
80   CHECK(!g_cras_audio_handler);
81   CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub());
82 }
83
84 // static
85 void CrasAudioHandler::Shutdown() {
86   CHECK(g_cras_audio_handler);
87   delete g_cras_audio_handler;
88   g_cras_audio_handler = NULL;
89 }
90
91 // static
92 bool CrasAudioHandler::IsInitialized() {
93   return g_cras_audio_handler != NULL;
94 }
95
96 // static
97 CrasAudioHandler* CrasAudioHandler::Get() {
98   CHECK(g_cras_audio_handler)
99       << "CrasAudioHandler::Get() called before Initialize().";
100   return g_cras_audio_handler;
101 }
102
103 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) {
104   observers_.AddObserver(observer);
105 }
106
107 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) {
108   observers_.RemoveObserver(observer);
109 }
110
111 bool CrasAudioHandler::HasKeyboardMic() {
112   return GetKeyboardMic() != NULL;
113 }
114
115 bool CrasAudioHandler::IsOutputMuted() {
116   return output_mute_on_;
117 }
118
119 bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id) {
120   const AudioDevice* device = GetDeviceFromId(device_id);
121   if (!device)
122     return false;
123   DCHECK(!device->is_input);
124   return audio_pref_handler_->GetMuteValue(*device);
125 }
126
127 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLevel() {
128   return output_volume_ <= kMuteThresholdPercent;
129 }
130
131 bool CrasAudioHandler::IsInputMuted() {
132   return input_mute_on_;
133 }
134
135 bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) {
136   const AudioDevice* device = GetDeviceFromId(device_id);
137   if (!device)
138     return false;
139   DCHECK(device->is_input);
140   // We don't record input mute state for each device in the prefs,
141   // for any non-active input device, we assume mute is off.
142   if (device->id == active_input_node_id_)
143     return input_mute_on_;
144   return false;
145 }
146
147 int CrasAudioHandler::GetOutputDefaultVolumeMuteThreshold() {
148   return kMuteThresholdPercent;
149 }
150
151 int CrasAudioHandler::GetOutputVolumePercent() {
152   return output_volume_;
153 }
154
155 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64 device_id) {
156   if (device_id == active_output_node_id_) {
157     return output_volume_;
158   } else {
159     const AudioDevice* device = GetDeviceFromId(device_id);
160     return static_cast<int>(audio_pref_handler_->GetOutputVolumeValue(device));
161   }
162 }
163
164 int CrasAudioHandler::GetInputGainPercent() {
165   return input_gain_;
166 }
167
168 int CrasAudioHandler::GetInputGainPercentForDevice(uint64 device_id) {
169   if (device_id == active_input_node_id_) {
170     return input_gain_;
171   } else {
172     const AudioDevice* device = GetDeviceFromId(device_id);
173     return static_cast<int>(audio_pref_handler_->GetInputGainValue(device));
174   }
175 }
176
177 uint64 CrasAudioHandler::GetPrimaryActiveOutputNode() const {
178   return active_output_node_id_;
179 }
180
181 uint64 CrasAudioHandler::GetPrimaryActiveInputNode() const {
182   return active_input_node_id_;
183 }
184
185 void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const {
186   device_list->clear();
187   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
188        it != audio_devices_.end(); ++it)
189     device_list->push_back(it->second);
190 }
191
192 bool CrasAudioHandler::GetPrimaryActiveOutputDevice(AudioDevice* device) const {
193   const AudioDevice* active_device = GetDeviceFromId(active_output_node_id_);
194   if (!active_device || !device)
195     return false;
196   *device = *active_device;
197   return true;
198 }
199
200 void CrasAudioHandler::SetKeyboardMicActive(bool active) {
201   const AudioDevice* keyboard_mic = GetKeyboardMic();
202   if (!keyboard_mic)
203     return;
204   // Keyboard mic is invisible to chromeos users. It is always added or removed
205   // as additional active node.
206   DCHECK(active_input_node_id_ && active_input_node_id_ != keyboard_mic->id);
207   if (active)
208     AddActiveNode(keyboard_mic->id, true);
209   else
210     RemoveActiveNodeInternal(keyboard_mic->id, true);
211 }
212
213 void CrasAudioHandler::AddActiveNode(uint64 node_id, bool notify) {
214   const AudioDevice* device = GetDeviceFromId(node_id);
215   if (!device) {
216     VLOG(1) << "AddActiveInputNode: Cannot find device id="
217             << "0x" << std::hex << node_id;
218     return;
219   }
220
221   // If there is no primary active device, set |node_id| to primary active node.
222   if ((device->is_input && !active_input_node_id_) ||
223       (!device->is_input && !active_output_node_id_)) {
224     SwitchToDevice(*device, notify);
225     return;
226   }
227
228   AddAdditionalActiveNode(node_id, notify);
229 }
230
231 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) {
232   // Flags for whether there are input or output nodes passed in from
233   // |new_active_ids|. If there are no input nodes passed in, we will not
234   // make any change for input nodes; same for the output nodes.
235   bool request_input_change = false;
236   bool request_output_change = false;
237
238   // Flags for whether we will actually change active status of input
239   // or output nodes.
240   bool make_input_change = false;
241   bool make_output_change = false;
242
243   NodeIdList nodes_to_activate;
244   for (size_t i = 0; i < new_active_ids.size(); ++i) {
245     const AudioDevice* device = GetDeviceFromId(new_active_ids[i]);
246     if (device) {
247       if (device->is_input)
248         request_input_change = true;
249       else
250         request_output_change = true;
251
252       // If the new active device is already active, keep it as active.
253       if (device->active)
254         continue;
255
256       nodes_to_activate.push_back(new_active_ids[i]);
257       if (device->is_input)
258         make_input_change = true;
259       else
260         make_output_change = true;
261     }
262   }
263
264   // Remove all existing active devices that are not in the |new_active_ids|
265   // list.
266   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
267        it != audio_devices_.end(); ++it) {
268     AudioDevice device = it->second;
269     // Remove the existing active input or output nodes that are not in the new
270     // active node list if there are new input or output nodes specified.
271     if (device.active) {
272       if ((device.is_input && request_input_change &&
273            !IsInNodeList(device.id, new_active_ids))) {
274         make_input_change = true;
275         RemoveActiveNodeInternal(device.id, false);  // no notification.
276       } else if (!device.is_input && request_output_change &&
277                  !IsInNodeList(device.id, new_active_ids)) {
278         make_output_change = true;
279         RemoveActiveNodeInternal(device.id, false);  // no notification.
280       }
281     }
282   }
283
284   // Adds the new active devices.
285   for (size_t i = 0; i < nodes_to_activate.size(); ++i)
286     AddActiveNode(nodes_to_activate[i], false);  // no notification.
287
288   // Notify the active nodes change now.
289   if (make_input_change)
290     NotifyActiveNodeChanged(true);
291   if (make_output_change)
292     NotifyActiveNodeChanged(false);
293 }
294
295 void CrasAudioHandler::SwapInternalSpeakerLeftRightChannel(bool swap) {
296   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
297        it != audio_devices_.end();
298        ++it) {
299     const AudioDevice& device = it->second;
300     if (!device.is_input && device.type == AUDIO_TYPE_INTERNAL_SPEAKER) {
301       chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->SwapLeftRight(
302           device.id, swap);
303       break;
304     }
305   }
306 }
307
308 bool CrasAudioHandler::has_alternative_input() const {
309   return has_alternative_input_;
310 }
311
312 bool CrasAudioHandler::has_alternative_output() const {
313   return has_alternative_output_;
314 }
315
316 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) {
317   // Set all active devices to the same volume.
318   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
319        it != audio_devices_.end();
320        it++) {
321     const AudioDevice& device = it->second;
322     if (!device.is_input && device.active)
323       SetOutputNodeVolumePercent(device.id, volume_percent);
324   }
325 }
326
327 // TODO: Rename the 'Percent' to something more meaningful.
328 void CrasAudioHandler::SetInputGainPercent(int gain_percent) {
329   // TODO(jennyz): Should we set all input devices' gain to the same level?
330   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
331        it != audio_devices_.end();
332        it++) {
333     const AudioDevice& device = it->second;
334     if (device.is_input && device.active)
335       SetInputNodeGainPercent(active_input_node_id_, gain_percent);
336   }
337 }
338
339 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) {
340   SetOutputVolumePercent(output_volume_ + adjust_by_percent);
341 }
342
343 void CrasAudioHandler::SetOutputMute(bool mute_on) {
344   if (!SetOutputMuteInternal(mute_on))
345     return;
346
347   // Save the mute state for all active output audio devices.
348   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
349        it != audio_devices_.end();
350        it++) {
351     const AudioDevice& device = it->second;
352     if (!device.is_input && device.active) {
353       audio_pref_handler_->SetMuteValue(device, output_mute_on_);
354     }
355   }
356
357   FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged());
358 }
359
360 void CrasAudioHandler::AdjustOutputVolumeToAudibleLevel() {
361   if (output_volume_ <= kMuteThresholdPercent) {
362     // Avoid the situation when sound has been unmuted, but the volume
363     // is set to a very low value, so user still can't hear any sound.
364     SetOutputVolumePercent(kDefaultUnmuteVolumePercent);
365   }
366 }
367
368 void CrasAudioHandler::SetInputMute(bool mute_on) {
369   if (!SetInputMuteInternal(mute_on))
370     return;
371
372   FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputMuteChanged());
373 }
374
375 void CrasAudioHandler::SetActiveOutputNode(uint64 node_id, bool notify) {
376   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
377       SetActiveOutputNode(node_id);
378   if (notify)
379     NotifyActiveNodeChanged(false);
380 }
381
382 void CrasAudioHandler::SetActiveInputNode(uint64 node_id, bool notify) {
383   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
384       SetActiveInputNode(node_id);
385   if (notify)
386     NotifyActiveNodeChanged(true);
387 }
388
389 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64 device_id,
390                                                      int value) {
391   const AudioDevice* device = GetDeviceFromId(device_id);
392   if (!device)
393     return;
394
395   if (device->is_input)
396     SetInputNodeGainPercent(device_id, value);
397   else
398     SetOutputNodeVolumePercent(device_id, value);
399 }
400
401 void CrasAudioHandler::SetMuteForDevice(uint64 device_id, bool mute_on) {
402   if (device_id == active_output_node_id_) {
403     SetOutputMute(mute_on);
404     return;
405   } else if (device_id == active_input_node_id_) {
406     VLOG(1) << "SetMuteForDevice sets active input device id="
407             << "0x" << std::hex << device_id << " mute=" << mute_on;
408     SetInputMute(mute_on);
409     return;
410   }
411
412   const AudioDevice* device = GetDeviceFromId(device_id);
413   // Input device's mute state is not recorded in the pref. crbug.com/365050.
414   if (device && !device->is_input)
415     audio_pref_handler_->SetMuteValue(*device, mute_on);
416 }
417
418 void CrasAudioHandler::LogErrors() {
419   log_errors_ = true;
420 }
421
422 CrasAudioHandler::CrasAudioHandler(
423     scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler)
424     : audio_pref_handler_(audio_pref_handler),
425       output_mute_on_(false),
426       input_mute_on_(false),
427       output_volume_(0),
428       input_gain_(0),
429       active_output_node_id_(0),
430       active_input_node_id_(0),
431       has_alternative_input_(false),
432       has_alternative_output_(false),
433       output_mute_locked_(false),
434       input_mute_locked_(false),
435       log_errors_(false),
436       weak_ptr_factory_(this) {
437   if (!audio_pref_handler.get())
438     return;
439   // If the DBusThreadManager or the CrasAudioClient aren't available, there
440   // isn't much we can do. This should only happen when running tests.
441   if (!chromeos::DBusThreadManager::IsInitialized() ||
442       !chromeos::DBusThreadManager::Get() ||
443       !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
444     return;
445   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this);
446   audio_pref_handler_->AddAudioPrefObserver(this);
447   if (chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) {
448     chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
449         AddObserver(this);
450   }
451   InitializeAudioState();
452 }
453
454 CrasAudioHandler::~CrasAudioHandler() {
455   if (!chromeos::DBusThreadManager::IsInitialized() ||
456       !chromeos::DBusThreadManager::Get() ||
457       !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
458     return;
459   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
460       RemoveObserver(this);
461   chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
462       RemoveObserver(this);
463   if (audio_pref_handler_.get())
464     audio_pref_handler_->RemoveAudioPrefObserver(this);
465   audio_pref_handler_ = NULL;
466 }
467
468 void CrasAudioHandler::AudioClientRestarted() {
469   // Make sure the logging is enabled in case cras server
470   // restarts after crashing.
471   LogErrors();
472   InitializeAudioState();
473 }
474
475 void CrasAudioHandler::NodesChanged() {
476   // Refresh audio nodes data.
477   GetNodes();
478 }
479
480 void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id) {
481   if (active_output_node_id_ == node_id)
482     return;
483
484   // Active audio output device should always be changed by chrome.
485   // During system boot, cras may change active input to unknown device 0x1,
486   // we don't need to log it, since it is not an valid device.
487   if (GetDeviceFromId(node_id)) {
488     LOG_IF(WARNING, log_errors_)
489         << "Active output node changed unexpectedly by system node_id="
490         << "0x" << std::hex << node_id;
491   }
492 }
493
494 void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id) {
495   if (active_input_node_id_ == node_id)
496     return;
497
498   // Active audio input device should always be changed by chrome.
499   // During system boot, cras may change active input to unknown device 0x2,
500   // we don't need to log it, since it is not an valid device.
501   if (GetDeviceFromId(node_id)) {
502     LOG_IF(WARNING, log_errors_)
503         << "Active input node changed unexpectedly by system node_id="
504         << "0x" << std::hex << node_id;
505   }
506 }
507
508 void CrasAudioHandler::OnAudioPolicyPrefChanged() {
509   ApplyAudioPolicy();
510 }
511
512 void CrasAudioHandler::EmitLoginPromptVisibleCalled() {
513   // Enable logging after cras server is started, which will be after
514   // EmitLoginPromptVisible.
515   LogErrors();
516 }
517
518 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64 device_id) const {
519   AudioDeviceMap::const_iterator it = audio_devices_.find(device_id);
520   if (it == audio_devices_.end())
521     return NULL;
522
523   return &(it->second);
524 }
525
526 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const {
527   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
528        it != audio_devices_.end(); it++) {
529     if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC)
530       return &(it->second);
531   }
532   return NULL;
533 }
534
535 void CrasAudioHandler::SetupAudioInputState() {
536   // Set the initial audio state to the ones read from audio prefs.
537   const AudioDevice* device = GetDeviceFromId(active_input_node_id_);
538   if (!device) {
539     LOG_IF(ERROR, log_errors_)
540         << "Can't set up audio state for unknown input device id ="
541         << "0x" << std::hex << active_input_node_id_;
542     return;
543   }
544   input_gain_ = audio_pref_handler_->GetInputGainValue(device);
545   VLOG(1) << "SetupAudioInputState for active device id="
546           << "0x" << std::hex << device->id << " mute=" << input_mute_on_;
547   SetInputMuteInternal(input_mute_on_);
548   // TODO(rkc,jennyz): Set input gain once we decide on how to store
549   // the gain values since the range and step are both device specific.
550 }
551
552 void CrasAudioHandler::SetupAudioOutputState() {
553   const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
554   if (!device) {
555     LOG_IF(ERROR, log_errors_)
556         << "Can't set up audio state for unknown output device id ="
557         << "0x" << std::hex << active_output_node_id_;
558     return;
559   }
560   DCHECK(!device->is_input);
561   output_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
562   output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device);
563
564   SetOutputMuteInternal(output_mute_on_);
565   SetOutputNodeVolume(active_output_node_id_, output_volume_);
566 }
567
568 // This sets up the state of an additional active node.
569 void CrasAudioHandler::SetupAdditionalActiveAudioNodeState(uint64 node_id) {
570   const AudioDevice* device = GetDeviceFromId(node_id);
571   if (!device) {
572     VLOG(1) << "Can't set up audio state for unknown device id ="
573             << "0x" << std::hex << node_id;
574     return;
575   }
576
577   DCHECK(node_id != active_output_node_id_ && node_id != active_input_node_id_);
578
579   // Note: The mute state is a system wide state, we don't set mute per device,
580   // but just keep the mute state consistent for the active node in prefs.
581   // The output volume should be set to the same value for all active output
582   // devices. For input devices, we don't restore their gain value so far.
583   // TODO(jennyz): crbug.com/417418, track the status for the decison if
584   // we should persist input gain value in prefs.
585   if (!device->is_input) {
586     audio_pref_handler_->SetMuteValue(*device, IsOutputMuted());
587     SetOutputNodeVolumePercent(node_id, GetOutputVolumePercent());
588   }
589 }
590
591 void CrasAudioHandler::InitializeAudioState() {
592   ApplyAudioPolicy();
593   GetNodes();
594 }
595
596 void CrasAudioHandler::ApplyAudioPolicy() {
597   output_mute_locked_ = false;
598   if (!audio_pref_handler_->GetAudioOutputAllowedValue()) {
599     // Mute the device, but do not update the preference.
600     SetOutputMuteInternal(true);
601     output_mute_locked_ = true;
602   } else {
603     // Restore the mute state.
604     const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
605     if (device)
606       SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device));
607   }
608
609   input_mute_locked_ = false;
610   if (audio_pref_handler_->GetAudioCaptureAllowedValue()) {
611     VLOG(1) << "Audio input allowed by policy, sets input id="
612             << "0x" << std::hex << active_input_node_id_ << " mute=false";
613     SetInputMuteInternal(false);
614   } else {
615     VLOG(0) << "Audio input NOT allowed by policy, sets input id="
616             << "0x" << std::hex << active_input_node_id_ << " mute=true";
617     SetInputMuteInternal(true);
618     input_mute_locked_ = true;
619   }
620 }
621
622 void CrasAudioHandler::SetOutputNodeVolume(uint64 node_id, int volume) {
623   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
624       SetOutputNodeVolume(node_id, volume);
625 }
626
627 void CrasAudioHandler::SetOutputNodeVolumePercent(uint64 node_id,
628                                                   int volume_percent) {
629   const AudioDevice* device = this->GetDeviceFromId(node_id);
630   if (!device || device->is_input)
631     return;
632
633   volume_percent = min(max(volume_percent, 0), 100);
634   if (volume_percent <= kMuteThresholdPercent)
635     volume_percent = 0;
636   if (node_id == active_output_node_id_)
637     output_volume_ = volume_percent;
638
639   audio_pref_handler_->SetVolumeGainValue(*device, volume_percent);
640
641   if (device->active) {
642     SetOutputNodeVolume(node_id, volume_percent);
643     FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged());
644   }
645 }
646
647 bool  CrasAudioHandler::SetOutputMuteInternal(bool mute_on) {
648   if (output_mute_locked_)
649     return false;
650
651   output_mute_on_ = mute_on;
652   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
653       SetOutputUserMute(mute_on);
654   return true;
655 }
656
657 void CrasAudioHandler::SetInputNodeGain(uint64 node_id, int gain) {
658   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
659       SetInputNodeGain(node_id, gain);
660 }
661
662 void CrasAudioHandler::SetInputNodeGainPercent(uint64 node_id,
663                                                int gain_percent) {
664   const AudioDevice* device = GetDeviceFromId(node_id);
665   if (!device || !device->is_input)
666     return;
667
668   // NOTE: We do not sanitize input gain values since the range is completely
669   // dependent on the device.
670   if (active_input_node_id_ == node_id)
671     input_gain_ = gain_percent;
672
673   audio_pref_handler_->SetVolumeGainValue(*device, gain_percent);
674
675   if (device->active) {
676     SetInputNodeGain(node_id, gain_percent);
677     FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputGainChanged());
678   }
679 }
680
681 bool CrasAudioHandler::SetInputMuteInternal(bool mute_on) {
682   if (input_mute_locked_)
683     return false;
684
685   input_mute_on_ = mute_on;
686   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
687       SetInputMute(mute_on);
688   return true;
689 }
690
691 void CrasAudioHandler::GetNodes() {
692   chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes(
693       base::Bind(&CrasAudioHandler::HandleGetNodes,
694                  weak_ptr_factory_.GetWeakPtr()),
695       base::Bind(&CrasAudioHandler::HandleGetNodesError,
696                  weak_ptr_factory_.GetWeakPtr()));
697 }
698
699 bool CrasAudioHandler::ChangeActiveDevice(const AudioDevice& new_active_device,
700                                           uint64* current_active_node_id) {
701   // If the device we want to switch to is already the current active device,
702   // do nothing.
703   if (new_active_device.active &&
704       new_active_device.id == *current_active_node_id) {
705     return false;
706   }
707
708   // Reset all other input or output devices' active status. The active audio
709   // device from the previous user session can be remembered by cras, but not
710   // in chrome. see crbug.com/273271.
711   for (AudioDeviceMap::iterator it = audio_devices_.begin();
712        it != audio_devices_.end(); ++it) {
713     if (it->second.is_input == new_active_device.is_input &&
714         it->second.id != new_active_device.id)
715       it->second.active = false;
716   }
717
718   // Set the current active input/output device to the new_active_device.
719   *current_active_node_id = new_active_device.id;
720   audio_devices_[*current_active_node_id].active = true;
721   return true;
722 }
723
724 bool CrasAudioHandler::NonActiveDeviceUnplugged(
725     size_t old_devices_size,
726     size_t new_devices_size,
727     uint64 current_active_node) {
728   return (new_devices_size < old_devices_size &&
729           GetDeviceFromId(current_active_node));
730 }
731
732 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device, bool notify) {
733   if (device.is_input) {
734     if (!ChangeActiveDevice(device, &active_input_node_id_))
735       return;
736     SetupAudioInputState();
737     SetActiveInputNode(active_input_node_id_, notify);
738   } else {
739     if (!ChangeActiveDevice(device, &active_output_node_id_))
740       return;
741     SetupAudioOutputState();
742     SetActiveOutputNode(active_output_node_id_, notify);
743   }
744 }
745
746 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes,
747                                        bool is_input) {
748   size_t num_old_devices = 0;
749   size_t num_new_devices = 0;
750   for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
751        it != audio_devices_.end(); ++it) {
752     if (is_input == it->second.is_input)
753       ++num_old_devices;
754   }
755
756   for (AudioNodeList::const_iterator it = new_nodes.begin();
757        it != new_nodes.end(); ++it) {
758     if (is_input == it->is_input) {
759       ++num_new_devices;
760       // Look to see if the new device not in the old device list.
761       AudioDevice device(*it);
762       if (FoundNewOrChangedDevice(device))
763         return true;
764     }
765   }
766   return num_old_devices != num_new_devices;
767 }
768
769 bool CrasAudioHandler::FoundNewOrChangedDevice(const AudioDevice& device) {
770   const AudioDevice* device_found = GetDeviceFromId(device.id);
771   if (!device_found)
772     return true;
773
774   if (!IsSameAudioDevice(device, *device_found)) {
775     LOG(WARNING) << "Different Audio devices with same id:"
776         << " new device: " << device.ToString()
777         << " old device: " << device_found->ToString();
778     return true;
779   } else if (device.active != device_found->active) {
780     return true;
781   }
782
783   return false;
784 }
785
786 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) {
787   if (is_input)
788     FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged());
789   else
790     FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged());
791 }
792
793 void CrasAudioHandler::UpdateDevicesAndSwitchActive(
794     const AudioNodeList& nodes) {
795   size_t old_audio_devices_size = audio_devices_.size();
796   bool output_devices_changed = HasDeviceChange(nodes, false);
797   bool input_devices_changed = HasDeviceChange(nodes, true);
798   audio_devices_.clear();
799   has_alternative_input_ = false;
800   has_alternative_output_ = false;
801
802   while (!input_devices_pq_.empty())
803     input_devices_pq_.pop();
804   while (!output_devices_pq_.empty())
805     output_devices_pq_.pop();
806
807   for (size_t i = 0; i < nodes.size(); ++i) {
808     AudioDevice device(nodes[i]);
809     audio_devices_[device.id] = device;
810
811     if (!has_alternative_input_ &&
812         device.is_input &&
813         device.type != AUDIO_TYPE_INTERNAL_MIC &&
814         device.type != AUDIO_TYPE_KEYBOARD_MIC) {
815       has_alternative_input_ = true;
816     } else if (!has_alternative_output_ &&
817                !device.is_input &&
818                device.type != AUDIO_TYPE_INTERNAL_SPEAKER) {
819       has_alternative_output_ = true;
820     }
821
822     if (device.is_input)
823       input_devices_pq_.push(device);
824     else
825       output_devices_pq_.push(device);
826   }
827
828   // If audio nodes change is caused by unplugging some non-active audio
829   // devices, the previously set active audio device will stay active.
830   // Otherwise, switch to a new active audio device according to their priority.
831   if (input_devices_changed &&
832       !NonActiveDeviceUnplugged(old_audio_devices_size,
833                                 audio_devices_.size(),
834                                 active_input_node_id_) &&
835       !input_devices_pq_.empty())
836     SwitchToDevice(input_devices_pq_.top(), true);
837   if (output_devices_changed &&
838       !NonActiveDeviceUnplugged(old_audio_devices_size,
839                                 audio_devices_.size(),
840                                 active_output_node_id_) &&
841       !output_devices_pq_.empty()) {
842     SwitchToDevice(output_devices_pq_.top(), true);
843   }
844 }
845
846 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list,
847                                       bool success) {
848   if (!success) {
849     LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data";
850     return;
851   }
852
853   UpdateDevicesAndSwitchActive(node_list);
854   FOR_EACH_OBSERVER(AudioObserver, observers_, OnAudioNodesChanged());
855 }
856
857 void CrasAudioHandler::HandleGetNodesError(const std::string& error_name,
858                                            const std::string& error_msg) {
859   LOG_IF(ERROR, log_errors_) << "Failed to call GetNodes: "
860       << error_name  << ": " << error_msg;
861 }
862
863 void CrasAudioHandler::AddAdditionalActiveNode(uint64 node_id, bool notify) {
864   const AudioDevice* device = GetDeviceFromId(node_id);
865   if (!device) {
866     VLOG(1) << "AddActiveInputNode: Cannot find device id="
867             << "0x" << std::hex << node_id;
868     return;
869   }
870
871   audio_devices_[node_id].active = true;
872   SetupAdditionalActiveAudioNodeState(node_id);
873
874   if (device->is_input) {
875     DCHECK(node_id != active_input_node_id_);
876     chromeos::DBusThreadManager::Get()
877         ->GetCrasAudioClient()
878         ->AddActiveInputNode(node_id);
879     if (notify)
880       NotifyActiveNodeChanged(true);
881   } else {
882     DCHECK(node_id != active_output_node_id_);
883     chromeos::DBusThreadManager::Get()
884         ->GetCrasAudioClient()
885         ->AddActiveOutputNode(node_id);
886     if (notify)
887       NotifyActiveNodeChanged(false);
888   }
889 }
890
891 void CrasAudioHandler::RemoveActiveNodeInternal(uint64 node_id, bool notify) {
892   const AudioDevice* device = GetDeviceFromId(node_id);
893   if (!device) {
894     VLOG(1) << "RemoveActiveInputNode: Cannot find device id="
895             << "0x" << std::hex << node_id;
896     return;
897   }
898
899   audio_devices_[node_id].active = false;
900   if (device->is_input) {
901     if (node_id == active_input_node_id_)
902       active_input_node_id_ = 0;
903     chromeos::DBusThreadManager::Get()
904         ->GetCrasAudioClient()
905         ->RemoveActiveInputNode(node_id);
906     if (notify)
907       NotifyActiveNodeChanged(true);
908   } else {
909     if (node_id == active_output_node_id_)
910       active_output_node_id_ = 0;
911     chromeos::DBusThreadManager::Get()
912         ->GetCrasAudioClient()
913         ->RemoveActiveOutputNode(node_id);
914     if (notify)
915       NotifyActiveNodeChanged(false);
916   }
917 }
918
919 }  // namespace chromeos