|
| 1 | +unit alsa_volume; |
| 2 | + |
| 3 | +{$mode objfpc}{$H+} |
| 4 | + |
| 5 | +interface |
| 6 | + |
| 7 | +uses |
| 8 | + Classes, SysUtils, ctypes, dynlibs; |
| 9 | + |
| 10 | +function SetVolume(CardIndex: Integer; Percent: Integer): Boolean; |
| 11 | +function GetVolume(CardIndex: Integer; out Percent: Integer): Boolean; |
| 12 | + |
| 13 | +implementation |
| 14 | + |
| 15 | +type |
| 16 | + Psnd_mixer_t = Pointer; |
| 17 | + Psnd_mixer_elem_t = Pointer; |
| 18 | + Psnd_mixer_selem_id_t = Pointer; |
| 19 | + |
| 20 | +var |
| 21 | + asound: TLibHandle; |
| 22 | + |
| 23 | + snd_mixer_open: function(mixer: PPointer; mode: cint): cint; cdecl; |
| 24 | + snd_mixer_attach: function(mixer: Pointer; name: PChar): cint; cdecl; |
| 25 | + snd_mixer_selem_register: function(mixer: Pointer; options: Pointer; classp: PPointer): cint; cdecl; |
| 26 | + snd_mixer_load: function(mixer: Pointer): cint; cdecl; |
| 27 | + snd_mixer_first_elem: function(mixer: Pointer): Pointer; cdecl; |
| 28 | + snd_mixer_elem_next: function(elem: Pointer): Pointer; cdecl; |
| 29 | + snd_mixer_selem_is_active: function(elem: Pointer): cint; cdecl; |
| 30 | + snd_mixer_selem_get_name: function(elem: Pointer): PChar; cdecl; |
| 31 | + |
| 32 | + snd_mixer_selem_has_playback_volume: function(elem: Pointer): cint; cdecl; |
| 33 | + snd_mixer_selem_get_playback_volume_range: function(elem: Pointer; min, max: Plongint): cint; cdecl; |
| 34 | + snd_mixer_selem_set_playback_volume_all: function(elem: Pointer; value: clong): cint; cdecl; |
| 35 | + snd_mixer_selem_get_playback_volume: function(elem: Pointer; channel: cint; value: Plongint): cint; cdecl; |
| 36 | + |
| 37 | + snd_mixer_close: function(mixer: Pointer): cint; cdecl; |
| 38 | + |
| 39 | +const |
| 40 | + SND_MIXER_SCHN_FRONT_LEFT = 0; |
| 41 | + |
| 42 | +function LoadALSA: Boolean; |
| 43 | +begin |
| 44 | + if asound <> 0 then exit(True); |
| 45 | + |
| 46 | + asound := LoadLibrary('libasound.so'); |
| 47 | + if asound = 0 then exit(False); |
| 48 | + |
| 49 | + Pointer(snd_mixer_open) := GetProcAddress(asound, 'snd_mixer_open'); |
| 50 | + Pointer(snd_mixer_attach) := GetProcAddress(asound, 'snd_mixer_attach'); |
| 51 | + Pointer(snd_mixer_selem_register) := GetProcAddress(asound, 'snd_mixer_selem_register'); |
| 52 | + Pointer(snd_mixer_load) := GetProcAddress(asound, 'snd_mixer_load'); |
| 53 | + Pointer(snd_mixer_first_elem) := GetProcAddress(asound, 'snd_mixer_first_elem'); |
| 54 | + Pointer(snd_mixer_elem_next) := GetProcAddress(asound, 'snd_mixer_elem_next'); |
| 55 | + Pointer(snd_mixer_selem_is_active) := GetProcAddress(asound, 'snd_mixer_selem_is_active'); |
| 56 | + Pointer(snd_mixer_selem_get_name) := GetProcAddress(asound, 'snd_mixer_selem_get_name'); |
| 57 | + |
| 58 | + Pointer(snd_mixer_selem_has_playback_volume) := GetProcAddress(asound, 'snd_mixer_selem_has_playback_volume'); |
| 59 | + Pointer(snd_mixer_selem_get_playback_volume_range) := GetProcAddress(asound, 'snd_mixer_selem_get_playback_volume_range'); |
| 60 | + Pointer(snd_mixer_selem_set_playback_volume_all) := GetProcAddress(asound, 'snd_mixer_selem_set_playback_volume_all'); |
| 61 | + Pointer(snd_mixer_selem_get_playback_volume) := GetProcAddress(asound, 'snd_mixer_selem_get_playback_volume'); |
| 62 | + |
| 63 | + Pointer(snd_mixer_close) := GetProcAddress(asound, 'snd_mixer_close'); |
| 64 | + |
| 65 | + Result := True; |
| 66 | +end; |
| 67 | + |
| 68 | +function OpenMixer(CardIndex: Integer; out Mixer: Pointer): Boolean; |
| 69 | +var |
| 70 | + name: String; |
| 71 | +begin |
| 72 | + Result := False; |
| 73 | + |
| 74 | + if snd_mixer_open(@Mixer, 0) < 0 then exit; |
| 75 | + |
| 76 | + name := 'hw:' + IntToStr(CardIndex); |
| 77 | + |
| 78 | + if snd_mixer_attach(Mixer, PChar(name)) < 0 then exit; |
| 79 | + if snd_mixer_selem_register(Mixer, nil, nil) < 0 then exit; |
| 80 | + if snd_mixer_load(Mixer) < 0 then exit; |
| 81 | + |
| 82 | + Result := True; |
| 83 | +end; |
| 84 | + |
| 85 | +function FindVolumeElem(Mixer: Pointer): Pointer; |
| 86 | +var |
| 87 | + elem: Pointer; |
| 88 | +begin |
| 89 | + Result := nil; |
| 90 | + |
| 91 | + elem := snd_mixer_first_elem(Mixer); |
| 92 | + while elem <> nil do |
| 93 | + begin |
| 94 | + if (snd_mixer_selem_is_active(elem) <> 0) and |
| 95 | + (snd_mixer_selem_has_playback_volume(elem) <> 0) then |
| 96 | + begin |
| 97 | + Result := elem; |
| 98 | + exit; |
| 99 | + end; |
| 100 | + |
| 101 | + elem := snd_mixer_elem_next(elem); |
| 102 | + end; |
| 103 | +end; |
| 104 | + |
| 105 | +function SetVolume(CardIndex: Integer; Percent: Integer): Boolean; |
| 106 | +var |
| 107 | + mixer, elem: Pointer; |
| 108 | + minv, maxv: clong; |
| 109 | + value: clong; |
| 110 | +begin |
| 111 | + Result := False; |
| 112 | + |
| 113 | + if not LoadALSA then exit; |
| 114 | + if not OpenMixer(CardIndex, mixer) then exit; |
| 115 | + |
| 116 | + elem := FindVolumeElem(mixer); |
| 117 | + if elem = nil then |
| 118 | + begin |
| 119 | + snd_mixer_close(mixer); |
| 120 | + exit; |
| 121 | + end; |
| 122 | + |
| 123 | + snd_mixer_selem_get_playback_volume_range(elem, @minv, @maxv); |
| 124 | + |
| 125 | + value := minv + (Percent * (maxv - minv) div 100); |
| 126 | + |
| 127 | + snd_mixer_selem_set_playback_volume_all(elem, value); |
| 128 | + |
| 129 | + snd_mixer_close(mixer); |
| 130 | + Result := True; |
| 131 | +end; |
| 132 | + |
| 133 | +function GetVolume(CardIndex: Integer; out Percent: Integer): Boolean; |
| 134 | +var |
| 135 | + mixer, elem: Pointer; |
| 136 | + minv, maxv, value: clong; |
| 137 | +begin |
| 138 | + Result := False; |
| 139 | + Percent := 0; |
| 140 | + |
| 141 | + if not LoadALSA then exit; |
| 142 | + if not OpenMixer(CardIndex, mixer) then exit; |
| 143 | + |
| 144 | + elem := FindVolumeElem(mixer); |
| 145 | + if elem = nil then |
| 146 | + begin |
| 147 | + snd_mixer_close(mixer); |
| 148 | + exit; |
| 149 | + end; |
| 150 | + |
| 151 | + snd_mixer_selem_get_playback_volume_range(elem, @minv, @maxv); |
| 152 | + snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, @value); |
| 153 | + |
| 154 | + if maxv > minv then |
| 155 | + Percent := (value - minv) * 100 div (maxv - minv); |
| 156 | + |
| 157 | + snd_mixer_close(mixer); |
| 158 | + Result := True; |
| 159 | +end; |
| 160 | + |
| 161 | +initialization |
| 162 | + asound := 0; |
| 163 | + |
| 164 | +finalization |
| 165 | + if asound <> 0 then |
| 166 | + FreeLibrary(asound); |
| 167 | + |
| 168 | +end. |
0 commit comments