1 /*
2 Copyright (c) 2002 Malte Starostik <malte.starostik@t-online.de>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 */
19
20 #include <cstring>
21 #include <iostream>
22 #include <vector>
23
24 #include <alsa/mixer.h>
25
26 extern "C"
27 {
28 # include "grab-ng.h"
29 }
30
31 class alsa_mixer;
32
33 class attr_proxy : public ng_attribute
34 {
35 public:
36 typedef int ( alsa_mixer::*accessor )();
37 typedef void ( alsa_mixer::*mutator )( int );
38 attr_proxy() { std::memset( this, 0, sizeof( ng_attribute ) ); }
39 attr_proxy( int type, int id, const char* name, alsa_mixer* instance, accessor read, mutator write )
40 {
41 this->id = id;
42 this->name = name;
43 this->type = type;
44 this->read = &read_proxy;
45 this->write = &write_proxy;
46
47 handle_data* d = new handle_data;
48 d->instance = instance;
49 d->read = read;
50 d->write = write;
51 this->handle = d;
52 }
53 attr_proxy( const attr_proxy& other )
54 {
55 handle = 0;
56 *this = other;
57 }
58 attr_proxy& operator =( const attr_proxy& rhs )
59 {
60 if ( &rhs != this )
61 {
62 deref();
63 std::memcpy( this, &rhs, sizeof( ng_attribute ) );
64 ref();
65 }
66 return *this;
67 }
68 ~attr_proxy() { deref(); }
69
70 private:
71 struct handle_data
72 {
73 handle_data() : ref_count( 1 ) {}
74
75 alsa_mixer* instance;
76 accessor read;
77 mutator write;
78 int ref_count;
79 };
80
81 handle_data* data() const { return reinterpret_cast< handle_data* >( handle ); }
82 void ref() { if ( data() ) data()->ref_count++; }
83 void deref()
84 {
85 if ( data() && !--data()->ref_count )
86 {
87 delete data();
88 handle = 0;
89 }
90 }
91
92 static int read_proxy( ng_attribute* attr )
93 {
94 handle_data* d = reinterpret_cast< handle_data* >( attr->handle );
95 return ( d->instance->*d->read )();
96 }
97 static void write_proxy( ng_attribute* attr, int val )
98 {
99 handle_data* d = reinterpret_cast< handle_data* >( attr->handle );
100 ( d->instance->*d->write )( val );
101 }
102 };
103
104 class alsa_mixer
105 {
106 public:
107 alsa_mixer();
108 ~alsa_mixer();
109
110 bool init( const char* channel );
111
112 int mute();
113 void mute( int val );
114
115 int volume();
116 void volume( int val );
117
118 static void* open( char* );
119 static void close( void* inst );
120
121 static ng_devinfo* probe();
122 static ng_devinfo* channels( char* device );
123
124 static ng_attribute* volctl( void* inst, char* channel );
125
126 private:
127 std::vector< attr_proxy > attrs;
128 snd_mixer_t* handle;
129 snd_mixer_elem_t* elem;
130 bool muted;
131 };
132
133 alsa_mixer::alsa_mixer()
134 : attrs( 3 )
135 {
136 snd_mixer_open( &handle, 0 );
137 snd_mixer_attach( handle, "default" );
138 snd_mixer_selem_register( handle, 0, 0 );
139 snd_mixer_load( handle );
140
141 attrs[ 0 ] = attr_proxy( ATTR_TYPE_BOOL, ATTR_ID_MUTE, "mute",
142 this, &alsa_mixer::mute, &alsa_mixer::mute );
143 attrs[ 1 ] = attr_proxy( ATTR_TYPE_INTEGER, ATTR_ID_VOLUME, "volume",
144 this, &alsa_mixer::volume, &alsa_mixer::volume );
145 }
146
147 alsa_mixer::~alsa_mixer()
148 {
149 if ( handle ) snd_mixer_close( handle );
150 }
151
152 bool alsa_mixer::init( const char* channel )
153 {
154 for ( elem = snd_mixer_first_elem( handle ); elem; elem = snd_mixer_elem_next( elem ) )
155 if ( strcasecmp( channel, snd_mixer_selem_get_name( elem ) ) == 0 )
156 {
157 long min, max;
158 snd_mixer_selem_get_playback_volume_range( elem, &min, &max );
159 attrs[ 1 ].min = min;
160 attrs[ 1 ].max = max;
161 return true;
162 }
163 return false;
164 }
165
166 int alsa_mixer::mute()
167 {
168 int left, right;
169 snd_mixer_selem_get_playback_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, &left );
170 snd_mixer_selem_get_playback_switch( elem, SND_MIXER_SCHN_FRONT_RIGHT, &right );
171 return !left && !right;
172 }
173
174 void alsa_mixer::mute( int val )
175 {
176 snd_mixer_selem_set_playback_switch( elem, SND_MIXER_SCHN_FRONT_LEFT, !val );
177 snd_mixer_selem_set_playback_switch( elem, SND_MIXER_SCHN_FRONT_RIGHT, !val );
178 }
179
180 int alsa_mixer::volume()
181 {
182 long left, right;
183 snd_mixer_selem_get_playback_volume( elem, SND_MIXER_SCHN_FRONT_LEFT, &left );
184 snd_mixer_selem_get_playback_volume( elem, SND_MIXER_SCHN_FRONT_RIGHT, &right );
185 return ( left + right ) / 2;
186 }
187
188 void alsa_mixer::volume( int val )
189 {
190 snd_mixer_selem_set_playback_volume( elem, SND_MIXER_SCHN_FRONT_LEFT, val );
191 snd_mixer_selem_set_playback_volume( elem, SND_MIXER_SCHN_FRONT_RIGHT, val );
192 }
193
194 void* alsa_mixer::open( char* )
195 {
196 return new alsa_mixer();
197 }
198
199 void alsa_mixer::close( void* inst )
200 {
201 delete reinterpret_cast< alsa_mixer* >( inst );
202 }
203
204 ng_devinfo* alsa_mixer::probe()
205 {
206 std::cerr << "alsa_mixer::probe not implemented" << std::endl;
207 return 0;
208 }
209
210 ng_devinfo* alsa_mixer::channels( char* device )
211 {
212 std::cerr << "alsa_mixer::channels not implemented" << std::endl;
213 return 0;
214 }
215
216 ng_attribute* alsa_mixer::volctl( void* instance, char* channel )
217 {
218 alsa_mixer* mixer = reinterpret_cast< alsa_mixer* >( instance );
219 return mixer->init( channel ) ? &mixer->attrs[ 0 ] : 0;
220 }
221
222 extern "C" void ng_plugin_init( void )
223 {
224 static struct ng_mix_driver mixer_info =
225 {
226 /* name */ "alsa",
227 /* probe */ alsa_mixer::probe,
228 /* channels */ alsa_mixer::channels,
229 /* open */ alsa_mixer::open,
230 /* volctl */ alsa_mixer::volctl,
231 /* close */ alsa_mixer::close,
232 };
233
234 ng_mix_driver_register( NG_PLUGIN_MAGIC, __FILE__, &mixer_info );
235 }
236
237 // vim: ts=4 sw=4 noet
238
|
This page was automatically generated by the
LXR engine.
|