Skip to content

Commit 0c94d16

Browse files
Work on audio control implementation
Permission denied!
1 parent eec21ba commit 0c94d16

11 files changed

+300
-33
lines changed

VBAudioRouter/App.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<Color x:Key="NodeTitleBarColor2">#8D802F</Color>
1515
<Color x:Key="PositiveColor">#89D185</Color>
1616
<Color x:Key="NegativeColor">#D97C6A</Color>
17+
<Color x:Key="NodeBackgroundColor">#3F3F3F</Color>
1718

1819
<!-- Segoe Fluent Icons - Font -->
1920
<FontFamily x:Key="SegoeFluentIcons">/Assets/Fonts/FluentIcons/Segoe Fluent Icons.ttf#Segoe Fluent Icons</FontFamily>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<UserControl
2+
x:Class="VBAudioRouter.Controls.AudioSessionControl"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:local="using:VBAudioRouter"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
mc:Ignorable="d"
9+
d:DesignHeight="300"
10+
d:DesignWidth="400"
11+
RequestedTheme="Dark"
12+
Background="{ThemeResource NodeBackgroundColor}">
13+
14+
<StackPanel Orientation="Vertical">
15+
<Grid>
16+
<Grid.ColumnDefinitions>
17+
<ColumnDefinition Width="auto" />
18+
<ColumnDefinition Width="*" />
19+
<ColumnDefinition Width="auto" />
20+
</Grid.ColumnDefinitions>
21+
<AppBarButton x:Name="MuteButton" Click="MuteButton_Click"
22+
Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Width="40" Margin="0,0,10,0"
23+
LabelPosition="Collapsed" ToolTipService.ToolTip="Mute" Icon="Volume" />
24+
<Slider x:Name="VolumeSlider"
25+
Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal"
26+
TickFrequency="10" TickPlacement="Outside"
27+
Minimum="0" Maximum="100" ValueChanged="VolumeSlider_ValueChanged" />
28+
<FontIcon Glyph="&#xe7f5;" Margin="20,10,10,10" VerticalAlignment="Center" Grid.Column="2" />
29+
</Grid>
30+
<StackPanel Orientation="Vertical">
31+
<Grid Background="CornflowerBlue" Height="3" RenderTransformOrigin="0,0" Margin="1">
32+
<Grid.RenderTransform>
33+
<ScaleTransform x:Name="LeftMeter" ScaleX="0.5" />
34+
</Grid.RenderTransform>
35+
</Grid>
36+
<Grid Background="CornflowerBlue" Height="3" RenderTransformOrigin="0,0" Margin="1">
37+
<Grid.RenderTransform>
38+
<ScaleTransform x:Name="RightMeter" ScaleX="0.3" />
39+
</Grid.RenderTransform>
40+
</Grid>
41+
</StackPanel>
42+
</StackPanel>
43+
</UserControl>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
2+
Imports System.Runtime.InteropServices
3+
Imports NAudio.CoreAudioApi.Interfaces
4+
Imports VBAudioRouter.Interop
5+
6+
Namespace Controls
7+
8+
Public NotInheritable Class AudioSessionControl
9+
Inherits UserControl
10+
Implements IAudioEndpointVolumeCallback, IAudioSessionEvents
11+
12+
Public ReadOnly Property VolumeManager As IAudioEndpointVolume
13+
Public ReadOnly Property MeterInformation As IAudioMeterInformation
14+
Public ReadOnly Property AudioSession As IAudioSessionControl
15+
16+
Public ReadOnly SpeakerControlPageInstance As SpeakerControlPage
17+
18+
Friend Sub New(parent As SpeakerControlPage, audioSession As IAudioSessionControl)
19+
InitializeComponent()
20+
21+
Me.SpeakerControlPageInstance = parent
22+
Me.AudioSession = audioSession
23+
24+
VolumeManager = DirectCast(audioSession, IAudioEndpointVolume)
25+
MeterInformation = DirectCast(audioSession, IAudioMeterInformation)
26+
27+
VolumeManager.RegisterControlChangeNotify(Me)
28+
OnNotify(IntPtr.Zero)
29+
30+
Dim timer As New Timers.Timer()
31+
timer.Interval = 30
32+
AddHandler timer.Elapsed, Sub()
33+
Dim unused = Dispatcher.RunIdleAsync(Sub()
34+
Dim meters As Single() = New Single(MeterInformation.GetMeteringChannelCount() - 1) {}
35+
Dim metersRef = GCHandle.Alloc(meters, GCHandleType.Pinned)
36+
MeterInformation.GetChannelsPeakValues(meters.Length, metersRef.AddrOfPinnedObject)
37+
metersRef.Free()
38+
LeftMeter.ScaleY = meters(0)
39+
RightMeter.ScaleY = meters(1)
40+
End Sub)
41+
End Sub
42+
timer.Enabled = True
43+
44+
audioSession.RegisterAudioSessionNotification(Me)
45+
End Sub
46+
47+
Private Sub AudioSessionControl_Unloaded(sender As Object, e As RoutedEventArgs) Handles Me.Unloaded
48+
VolumeManager?.UnregisterControlChangeNotify(Me)
49+
AudioSession?.UnregisterAudioSessionNotification(Me)
50+
End Sub
51+
52+
Dim oldValue As Double = -1
53+
Private Sub VolumeSlider_ValueChanged(sender As Object, e As RangeBaseValueChangedEventArgs)
54+
If VolumeManager Is Nothing Or oldValue = VolumeSlider.Value Then Exit Sub
55+
oldValue = VolumeSlider.Value
56+
VolumeManager.SetMasterVolumeLevelScalar(Convert.ToSingle(VolumeSlider.Value / 100), Guid.Empty)
57+
End Sub
58+
59+
Dim isMuted As Boolean = False
60+
Private Sub MuteButton_Click(sender As Object, e As RoutedEventArgs)
61+
If VolumeManager Is Nothing Then Exit Sub
62+
63+
If sender IsNot Nothing Then
64+
isMuted = Not isMuted
65+
VolumeManager.SetMute(isMuted, Guid.Empty)
66+
End If
67+
68+
If isMuted Then
69+
MuteButton.Icon = New SymbolIcon(Symbol.Mute)
70+
Else
71+
MuteButton.Icon = New SymbolIcon(Symbol.Volume)
72+
End If
73+
End Sub
74+
75+
Public Sub OnNotify(notifyData As IntPtr) Implements IAudioEndpointVolumeCallback.OnNotify
76+
Dim unused = Dispatcher.RunIdleAsync(Sub()
77+
VolumeSlider.Value = VolumeManager.GetMasterVolumeLevelScalar() * 100
78+
isMuted = VolumeManager.GetMute()
79+
MuteButton_Click(Nothing, Nothing)
80+
End Sub)
81+
End Sub
82+
83+
Public Function OnDisplayNameChanged(displayName As String, ByRef eventContext As Guid) As Integer Implements IAudioSessionEvents.OnDisplayNameChanged
84+
85+
End Function
86+
87+
Public Function OnIconPathChanged(iconPath As String, ByRef eventContext As Guid) As Integer Implements IAudioSessionEvents.OnIconPathChanged
88+
89+
End Function
90+
91+
Public Function OnSimpleVolumeChanged(volume As Single, isMuted As Boolean, ByRef eventContext As Guid) As Integer Implements IAudioSessionEvents.OnSimpleVolumeChanged
92+
93+
End Function
94+
95+
Public Function OnChannelVolumeChanged(channelCount As UInteger, newVolumes As IntPtr, channelIndex As UInteger, ByRef eventContext As Guid) As Integer Implements IAudioSessionEvents.OnChannelVolumeChanged
96+
97+
End Function
98+
99+
Public Function OnGroupingParamChanged(ByRef groupingId As Guid, ByRef eventContext As Guid) As Integer Implements IAudioSessionEvents.OnGroupingParamChanged
100+
101+
End Function
102+
103+
Public Function OnStateChanged(state As AudioSessionState) As Integer Implements IAudioSessionEvents.OnStateChanged
104+
105+
End Function
106+
107+
Public Function OnSessionDisconnected(disconnectReason As AudioSessionDisconnectReason) As Integer Implements IAudioSessionEvents.OnSessionDisconnected
108+
SpeakerControlPageInstance.AudioSessions.Remove(Me)
109+
End Function
110+
End Class
111+
112+
End Namespace

VBAudioRouter/Interop/IAudioEndpointVolume.vb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
Namespace Interop
44

55
''' <summary>
6-
''' <see href="https://github.com/naudio/NAudio/blob/master/NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioEndpointVolume.cs"/>
6+
''' <see href="https://docs.microsoft.com/en-us/windows/win32/api/endpointvolume/nn-endpointvolume-iaudioendpointvolume">Documentation</see> <br/>
7+
''' <see href="https://github.com/naudio/NAudio/blob/master/NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioEndpointVolume.cs">Implementation</see>
78
''' </summary>
89
<Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
910
Public Interface IAudioEndpointVolume
@@ -26,4 +27,5 @@ Namespace Interop
2627
Function QueryHardwareSupport(<Out> ByRef pdwHardwareSupportMask As UInteger) As Integer
2728
Function GetVolumeRange(<Out> ByRef pflVolumeMindB As Single, <Out> ByRef pflVolumeMaxdB As Single, <Out> ByRef pflVolumeIncrementdB As Single) As Integer
2829
End Interface
30+
2931
End Namespace

VBAudioRouter/Interop/IAudioMeterInformation.vb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
Namespace Interop
44

55
''' <summary>
6-
''' <see href="https://github.com/naudio/NAudio/blob/master/NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioMeterInformation.cs"/>
6+
''' <see href="https://docs.microsoft.com/en-us/windows/win32/api/endpointvolume/nn-endpointvolume-iaudiometerinformation">Documentation</see> <br/>
7+
''' <see href="https://github.com/naudio/NAudio/blob/master/NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioMeterInformation.cs">Implementation</see>
78
''' </summary>
89
<Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
910
Public Interface IAudioMeterInformation
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Imports System.Runtime.InteropServices
2+
Imports NAudio.CoreAudioApi.Interfaces
3+
4+
Namespace Interop
5+
6+
''' <summary>
7+
''' <see href="https://docs.microsoft.com/en-us/windows/win32/api/audiopolicy/nn-audiopolicy-iaudiosessionenumerator">Documentation</see> <br/>
8+
''' <see href="https://github.com/naudio/NAudio/blob/master/NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioSessionEnumerator.cs">Implementation</see>
9+
''' </summary>
10+
<Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
11+
Public Interface IAudioSessionEnumerator
12+
Function GetCount() As Integer
13+
Function GetSession(ByVal sessionCount As Integer) As IAudioSessionControl
14+
End Interface
15+
16+
End Namespace
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
Imports System.Runtime.InteropServices
3+
Imports NAudio.CoreAudioApi.Interfaces
4+
5+
Namespace Interop
6+
7+
''' <summary>
8+
''' <see href="https://github.com/naudio/NAudio/blob/master/NAudio.Wasapi/CoreAudioApi/Interfaces/IAudioSessionManager.cs"/>
9+
''' </summary>
10+
<Guid("BFA971F1-4D5E-40BB-935E-967039BFBEE4"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
11+
Public Interface IAudioSessionManager
12+
<PreserveSig>
13+
Function GetAudioSessionControl(
14+
<[In], [Optional]>
15+
<MarshalAs(UnmanagedType.LPStruct)> ByVal sessionId As Guid,
16+
<[In]>
17+
<MarshalAs(UnmanagedType.U4)> ByVal streamFlags As UInt32, <Out>
18+
<MarshalAs(UnmanagedType.[Interface])> ByRef sessionControl As IAudioSessionControl) As Integer
19+
<PreserveSig>
20+
Function GetSimpleAudioVolume(
21+
<[In], [Optional]>
22+
<MarshalAs(UnmanagedType.LPStruct)> ByVal sessionId As Guid,
23+
<[In]>
24+
<MarshalAs(UnmanagedType.U4)> ByVal streamFlags As UInt32, <Out>
25+
<MarshalAs(UnmanagedType.[Interface])> ByRef audioVolume As Object) As Integer 'ISimpleAudioVolume
26+
End Interface
27+
28+
<Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
29+
Public Interface IAudioSessionManager2
30+
Inherits IAudioSessionManager
31+
32+
<PreserveSig>
33+
Overloads Function GetAudioSessionControl(
34+
<[In], [Optional]>
35+
<MarshalAs(UnmanagedType.LPStruct)> ByVal sessionId As Guid,
36+
<[In]>
37+
<MarshalAs(UnmanagedType.U4)> ByVal streamFlags As UInt32, <Out>
38+
<MarshalAs(UnmanagedType.[Interface])> ByRef sessionControl As IAudioSessionControl) As Integer
39+
<PreserveSig>
40+
Overloads Function GetSimpleAudioVolume(
41+
<[In], [Optional]>
42+
<MarshalAs(UnmanagedType.LPStruct)> ByVal sessionId As Guid,
43+
<[In]>
44+
<MarshalAs(UnmanagedType.U4)> ByVal streamFlags As UInt32, <Out>
45+
<MarshalAs(UnmanagedType.[Interface])> ByRef audioVolume As Object) As Integer ' ISimpleAudioVolume
46+
47+
Function GetSessionEnumerator() As IAudioSessionEnumerator
48+
<PreserveSig>
49+
Function RegisterSessionNotification(ByVal sessionNotification As IAudioSessionNotification) As Integer
50+
<PreserveSig>
51+
Function UnregisterSessionNotification(ByVal sessionNotification As IAudioSessionNotification) As Integer
52+
<PreserveSig>
53+
Function RegisterDuckNotification(ByVal sessionId As String, ByVal audioVolumeDuckNotification As IAudioSessionNotification) As Integer
54+
<PreserveSig>
55+
Function UnregisterDuckNotification(ByVal audioVolumeDuckNotification As IntPtr) As Integer
56+
End Interface
57+
58+
59+
End Namespace

VBAudioRouter/Package.appxmanifest

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
88
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
99
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
10-
IgnorableNamespaces="uap mp uap3 rescap">
10+
xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
11+
IgnorableNamespaces="uap mp uap3 rescap iot">
1112

1213
<Identity
1314
Name="33942ShortDevelopment.VBAudioRouter"
@@ -74,6 +75,7 @@
7475
<rescap:Capability Name="confirmAppClose"/>
7576
<uap3:Capability Name="backgroundMediaPlayback"/>
7677
<Capability Name="internetClient" />
78+
<iot:Capability Name="systemManagement"/>
7779
<DeviceCapability Name="microphone"/>
7880
</Capabilities>
7981
</Package>

VBAudioRouter/SpeakerControlPage.xaml

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,36 @@
99
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
1010
RequestedTheme="Dark">
1111

12-
<StackPanel Padding="10" Orientation="Horizontal">
13-
<Grid>
14-
<Grid.RowDefinitions>
15-
<RowDefinition Height="auto" />
16-
<RowDefinition Height="*" />
17-
<RowDefinition Height="auto" />
18-
</Grid.RowDefinitions>
19-
<FontIcon Glyph="&#xe7f5;" Margin="10,10,10,20" />
20-
<Slider x:Name="GainSlider"
12+
<Grid>
13+
<StackPanel Padding="10" Orientation="Horizontal">
14+
<Grid>
15+
<Grid.RowDefinitions>
16+
<RowDefinition Height="auto" />
17+
<RowDefinition Height="*" />
18+
<RowDefinition Height="auto" />
19+
</Grid.RowDefinitions>
20+
<FontIcon Glyph="&#xe7f5;" Margin="10,10,10,20" />
21+
<Slider x:Name="GainSlider"
2122
Grid.Row="1" HorizontalAlignment="Center" Orientation="Vertical"
2223
TickFrequency="10" TickPlacement="Outside"
2324
Minimum="0" Maximum="100" ValueChanged="Slider_ValueChanged" />
24-
<AppBarButton x:Name="MuteButton" Click="MuteToggleButton_Click"
25+
<AppBarButton x:Name="MuteButton" Click="MuteToggleButton_Click"
2526
Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="40" Margin="0,10,0,0"
2627
LabelPosition="Collapsed" ToolTipService.ToolTip="Mute" Icon="Volume" />
27-
</Grid>
28-
<StackPanel Orientation="Horizontal">
29-
<Grid Background="CornflowerBlue" Width="3" RenderTransformOrigin="1,1" Margin="1">
30-
<Grid.RenderTransform>
31-
<ScaleTransform x:Name="LeftMeter" ScaleY="0.5" />
32-
</Grid.RenderTransform>
33-
</Grid>
34-
<Grid Background="CornflowerBlue" Width="3" RenderTransformOrigin="1,1" Margin="1">
35-
<Grid.RenderTransform>
36-
<ScaleTransform x:Name="RightMeter" ScaleY="0.3" />
37-
</Grid.RenderTransform>
3828
</Grid>
29+
<StackPanel Orientation="Horizontal">
30+
<Grid Background="CornflowerBlue" Width="3" RenderTransformOrigin="1,1" Margin="1">
31+
<Grid.RenderTransform>
32+
<ScaleTransform x:Name="LeftMeter" ScaleY="0.5" />
33+
</Grid.RenderTransform>
34+
</Grid>
35+
<Grid Background="CornflowerBlue" Width="3" RenderTransformOrigin="1,1" Margin="1">
36+
<Grid.RenderTransform>
37+
<ScaleTransform x:Name="RightMeter" ScaleY="0.3" />
38+
</Grid.RenderTransform>
39+
</Grid>
40+
</StackPanel>
3941
</StackPanel>
40-
</StackPanel>
42+
<ListView ItemsSource="{x:Bind AudioSessions}" />
43+
</Grid>
4144
</Page>

0 commit comments

Comments
 (0)