Skip to content

Instantly share code, notes, and snippets.

@danielcweber
Last active May 18, 2020 17:35
Show Gist options
  • Save danielcweber/b37df9e8eb4e65c81c23d31336d2ae42 to your computer and use it in GitHub Desktop.
Save danielcweber/b37df9e8eb4e65c81c23d31336d2ae42 to your computer and use it in GitHub Desktop.
Based on the answer at https://stackoverflow.com/questions/6787318/set-alsa-master-volume-from-c-code/6787957#6787957 and the native interop code from alsa-sharp (https://github.com/atsushieno/alsa-sharp/) by @atsushieno, the code in this gist presents a solution for "how to set the volume on Linux in C# through Alsa" that works for me.
using System;
using System.Runtime.InteropServices;
namespace Alsa
{
public sealed class VolumeControl : IDisposable
{
private readonly long _min;
private readonly long _max;
private readonly IntPtr _sid;
private readonly IntPtr _selem;
private readonly IntPtr _handle;
private const string LibraryName = "libasound";
public VolumeControl(string card = "default", string selemName = "PCM")
{
snd_mixer_open(ref _handle, 0);
snd_mixer_attach(_handle, card);
snd_mixer_selem_register(_handle, default, default);
snd_mixer_load(_handle);
snd_mixer_selem_id_malloc(ref _sid);
snd_mixer_selem_id_set_index(_sid, 0);
snd_mixer_selem_id_set_name(_sid, selemName);
_selem = snd_mixer_find_selem(_handle, _sid);
snd_mixer_selem_get_playback_volume_range(_selem, ref _min, ref _max);
}
public void SetVolumePercent(int volume)
{
snd_mixer_selem_set_playback_volume_all(_selem, (int)(volume * _max / 100));
}
public void Dispose()
{
ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
private void ReleaseUnmanagedResources()
{
snd_mixer_selem_id_free(_sid);
snd_mixer_close(_handle);
}
~AlsaSoundOutput()
{
ReleaseUnmanagedResources();
}
[DllImport(LibraryName)]
internal static extern int snd_mixer_open(ref IntPtr mixer, int mode);
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
internal static extern int snd_mixer_attach(IntPtr mixer, [MarshalAs(UnmanagedType.LPStr)] string name);
[DllImport(LibraryName)]
internal static extern int snd_mixer_selem_register(IntPtr mixer, IntPtr options, IntPtr classp);
[DllImport(LibraryName)]
internal static extern int snd_mixer_load(IntPtr mixer);
[DllImport(LibraryName)]
internal static extern int snd_mixer_selem_id_malloc(ref IntPtr selem);
[DllImport(LibraryName)]
internal static extern void snd_mixer_selem_id_set_index(IntPtr selem, uint val);
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
internal static extern void snd_mixer_selem_id_set_name(IntPtr selem, [MarshalAs(UnmanagedType.LPStr)] string value);
[DllImport(LibraryName)]
internal static extern IntPtr snd_mixer_find_selem(IntPtr mixer, IntPtr selem);
[DllImport(LibraryName)]
internal static extern int snd_mixer_selem_get_playback_volume_range(IntPtr selem, ref long min, ref long max);
[DllImport(LibraryName)]
internal static extern int snd_mixer_selem_set_playback_volume_all(IntPtr selem, int value);
[DllImport(LibraryName)]
internal static extern void snd_mixer_selem_id_free(IntPtr selem);
[DllImport(LibraryName)]
internal static extern int snd_mixer_close(IntPtr mixer);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment