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