1// Copyright 2014 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 "ash/system/win/audio/tray_audio_delegate_win.h"
6
7#include <audiopolicy.h>
8#include <cmath>
9
10#include "media/audio/win/core_audio_util_win.h"
11
12using base::win::ScopedComPtr;
13
14namespace {
15
16// Volume value which should be considered as muted in range [0, 100].
17const int kMuteThresholdPercent = 1;
18
19// Lowest volume which is considered to be audible in the range [0, 100].
20const int kDefaultUnmuteVolumePercent = 4;
21
22}  // namespace
23
24namespace ash  {
25namespace system {
26
27void TrayAudioDelegateWin::AdjustOutputVolumeToAudibleLevel() {
28  if (GetOutputVolumeLevel() <= kMuteThresholdPercent)
29    SetOutputVolumeLevel(kDefaultUnmuteVolumePercent);
30}
31
32int TrayAudioDelegateWin::GetOutputDefaultVolumeMuteLevel() {
33  return kMuteThresholdPercent;
34}
35
36int TrayAudioDelegateWin::GetOutputVolumeLevel() {
37  ScopedComPtr<ISimpleAudioVolume> volume_control =
38      CreateDefaultVolumeControl();
39  if (!volume_control)
40    return 0;
41
42  float level = 0.0f;
43  if (FAILED(volume_control->GetMasterVolume(&level)))
44    return 0;
45
46  // MSVC prior to 2013 doesn't have a round function.  The below code is not
47  // conformant to C99 round(), but since we know that 0 <= level <= 100, it
48  // should be ok.
49  return static_cast<int>(level + 0.5);
50}
51
52int TrayAudioDelegateWin::GetActiveOutputDeviceIconId() {
53  return kNoAudioDeviceIcon;
54}
55
56bool TrayAudioDelegateWin::HasAlternativeSources() {
57  return false;
58}
59
60bool TrayAudioDelegateWin::IsOutputAudioMuted() {
61  ScopedComPtr<ISimpleAudioVolume> volume_control =
62      CreateDefaultVolumeControl();
63
64  if (!volume_control)
65    return false;
66
67  BOOL mute = FALSE;
68  if (FAILED(volume_control->GetMute(&mute)))
69    return false;
70
71  return !!mute;
72}
73
74void TrayAudioDelegateWin::SetOutputAudioIsMuted(bool is_muted) {
75  ScopedComPtr<ISimpleAudioVolume> volume_control =
76      CreateDefaultVolumeControl();
77
78  if (!volume_control)
79    return;
80
81  volume_control->SetMute(is_muted, NULL);
82}
83
84void TrayAudioDelegateWin::SetOutputVolumeLevel(int level) {
85  ScopedComPtr<ISimpleAudioVolume> volume_control =
86      CreateDefaultVolumeControl();
87
88  if (!volume_control)
89    return;
90
91  float volume_level = static_cast<float>(level) / 100.0f;
92  volume_control->SetMasterVolume(volume_level, NULL);
93}
94
95ScopedComPtr<ISimpleAudioVolume>
96TrayAudioDelegateWin::CreateDefaultVolumeControl() {
97  ScopedComPtr<ISimpleAudioVolume> volume_control;
98  ScopedComPtr<IAudioSessionManager> session_manager;
99
100  ScopedComPtr<IMMDevice> device =
101      media::CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
102  if (!device ||
103      FAILED(device->Activate(__uuidof(IAudioSessionManager), CLSCTX_ALL, NULL,
104             session_manager.ReceiveVoid()))) {
105    return volume_control;
106  }
107
108  session_manager->GetSimpleAudioVolume(NULL, FALSE,
109      volume_control.Receive());
110
111  return volume_control;
112}
113
114}  // namespace system
115}  // namespace ash
116