source: roaraudio/plugins/alsavs/ctl_roar.c @ 5263:1f8769c1aff0

Last change on this file since 5263:1f8769c1aff0 was 5263:1f8769c1aff0, checked in by phi, 12 years ago

added very experimental control plugin

File size: 7.9 KB
Line 
1//ctl_roar.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36//#define DEBUG
37#include "roar.h"
38#include <string.h>
39
40static void roar_plugin_close(snd_ctl_ext_t * ext) {
41 struct roar_alsa_ctl * self = ext->private_data;
42
43 roar_disconnect(&(self->roar.con));
44 free(self);
45}
46
47static int roar_plugin_elem_count(snd_ctl_ext_t *ext) {
48 struct roar_alsa_ctl * self = ext->private_data;
49 int ret = 0;
50
51 for (; self->streams[ret].id != -1; ret++);
52
53 return ret;
54}
55
56static int roar_plugin_elem_list(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id) {
57 struct roar_alsa_ctl * self = ext->private_data;
58
59 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
60 snd_ctl_elem_id_set_name(id, self->streams[offset].name);
61
62 return 0;
63}
64
65static snd_ctl_ext_key_t roar_plugin_find_elem(snd_ctl_ext_t *ext,
66                                               const snd_ctl_elem_id_t *id) {
67 struct roar_alsa_ctl * self = ext->private_data;
68 int numid = snd_ctl_elem_id_get_numid(id);
69
70 return self->streams[numid].id;
71}
72
73static int roar_plugin_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
74                                     int *type, unsigned int *acc, unsigned int *count) {
75 struct roar_alsa_ctl * self = ext->private_data;
76 int i;
77
78 *type = SND_CTL_ELEM_TYPE_INTEGER;
79 *acc = SND_CTL_EXT_ACCESS_READWRITE;
80
81 for (i = 0; i < MAX_STREAMS && self->streams[i].id != (int)key; i++)
82
83 if ( i == MAX_STREAMS )
84  return -EIO;
85
86 *count = self->streams[i].channels;
87
88 return 0;
89}
90
91static int roar_plugin_get_integer_info(snd_ctl_ext_t *ext ATTRIBUTE_UNUSED,
92                                        snd_ctl_ext_key_t key ATTRIBUTE_UNUSED,
93                                        long *imin, long *imax, long *istep) {
94 *istep = 0;
95 *imin  = 0;
96 *imax  = 65535;
97 return 0;
98}
99
100static int roar_plugin_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value) {
101 struct roar_alsa_ctl * self = ext->private_data;
102 struct roar_mixer_settings mixer;
103 int channels;
104 int i;
105
106 for (i = 0; i < MAX_STREAMS && self->streams[i].id != (int)key; i++)
107
108 if ( i == MAX_STREAMS )
109  return -EIO;
110
111 roar_err_clear_all();
112 if ( roar_get_vol(&(self->roar.con), key, &mixer, &channels) == -1 ) {
113  roar_err_update();
114  return -errno;
115 }
116
117 if ( channels != (int)self->streams[i].channels )
118  return -EIO;
119
120 for (i = 0; i < channels; i++)
121  value[i] = ((unsigned long int)mixer.mixer[i] * 65535LU) / mixer.scale;
122
123 return 0;
124}
125
126static int roar_plugin_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value) {
127 struct roar_alsa_ctl * self = ext->private_data;
128 struct roar_mixer_settings mixer;
129 int sid;
130 int i;
131
132 for (sid = 0; i < MAX_STREAMS && self->streams[sid].id != (int)key; sid++)
133
134 if ( sid == MAX_STREAMS )
135  return -EIO;
136
137 mixer.scale = 65535;
138 mixer.rpg_mul = 1;
139 mixer.rpg_div = 1;
140
141 for (i = 0; i < (int)self->streams[i].channels; i++)
142  mixer.mixer[i] = value[i];
143
144 roar_err_clear_all();
145 if ( roar_set_vol(&(self->roar.con), key, &mixer, self->streams[sid].channels, ROAR_SET_VOL_ALL) == -1 ) {
146  roar_err_update();
147  return -errno;
148 }
149
150 return 0;
151}
152
153static int roar_plugin_read_event(snd_ctl_ext_t *ext ATTRIBUTE_UNUSED,
154                                  snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED,
155                                  unsigned int *event_mask ATTRIBUTE_UNUSED) {
156 return -EAGAIN;
157}
158
159static void roar_plugin__handle_stream(struct roar_alsa_ctl * self, int id) {
160 struct roar_mixerstream * cs = NULL;
161 struct roar_stream s;
162 char name[1024];
163 int i;
164
165 if ( roar_get_stream(&(self->roar.con), &s, id) == -1 )
166  return;
167
168 switch (s.dir) {
169  case ROAR_DIR_OUTPUT:
170  case ROAR_DIR_MIXING:
171  case ROAR_DIR_BRIDGE:
172    if ( roar_stream_get_name(&(self->roar.con), &s, name, sizeof(name)) != 0 )
173     snprintf(name, sizeof(name), "Stream %i", id);
174   break;
175  default:
176    return;
177   break;
178 }
179
180 for (i = 0; cs == NULL && i < (int)(sizeof(self->streams)/sizeof(*self->streams)); i++)
181  if (self->streams[i].id == -1 )
182   cs = &(self->streams[i]);
183
184 if ( cs == NULL )
185  return;
186
187 cs->id = id;
188 cs->channels = s.info.channels;
189 strncpy(cs->name, name, sizeof(cs->name) - 1);
190}
191
192static int roar_plugin__find_streams(struct roar_alsa_ctl * self) {
193 int id[ROAR_STREAMS_MAX];
194 int num;
195 int i;
196
197 for (i = 0; i < (int)(sizeof(self->streams)/sizeof(*self->streams)); i++)
198  self->streams[i].id = -1;
199
200 roar_err_clear_all();
201
202 if ( (num = roar_list_streams(&(self->roar.con), id, ROAR_STREAMS_MAX)) == -1 ) {
203  roar_err_update();
204  return -errno;
205 }
206
207 for (i = 0; i < num; i++)
208  roar_plugin__handle_stream(self, i);
209
210 return 0;
211}
212
213static snd_ctl_ext_callback_t roar_ext_callback = {
214 .close            = roar_plugin_close,
215 .elem_count       = roar_plugin_elem_count,
216 .elem_list        = roar_plugin_elem_list,
217 .find_elem        = roar_plugin_find_elem,
218 .get_attribute    = roar_plugin_get_attribute,
219 .get_integer_info = roar_plugin_get_integer_info,
220 .read_integer     = roar_plugin_read_integer,
221 .write_integer    = roar_plugin_write_integer,
222 .read_event       = roar_plugin_read_event
223};
224
225SND_CTL_PLUGIN_DEFINE_FUNC(roar) {
226 struct roar_alsa_ctl * self;
227 snd_config_iterator_t i, next;
228 snd_config_t * n;
229 const char   * para;
230 const char   * server = NULL;
231 int error;
232
233 const char   * ext_id   = "ROAR";
234 const char   * ext_name = "RoarAudio";
235
236 (void)root;
237
238 snd_config_for_each(i, next, conf) {
239  n = snd_config_iterator_entry(i);
240  if ( snd_config_get_id(n, &para) < 0 )
241   continue;
242
243  if ( !strcmp(para, "type") || !strcmp(para, "comment") || !strcmp(para, "hint") )
244   continue;
245
246  if ( !strcmp(para, "server") ) {
247   if (snd_config_get_string(n, &server) < 0) {
248    return -EINVAL;
249   }
250  } else {
251   return -EINVAL;
252  }
253 }
254
255 if ( (self = malloc(sizeof(struct roar_alsa_ctl))) == NULL )
256  return -errno;
257
258 memset(self, 0, sizeof(struct roar_alsa_ctl));
259
260 errno = ENOSYS;
261 if ( roar_simple_connect(&(self->roar.con), server, "ALSA Plugin") == -1 ) {
262  free(self);
263  return -errno;
264 }
265
266 if ( (error = roar_plugin__find_streams(self)) < 0 ) {
267  roar_disconnect(&(self->roar.con));
268  free(self);
269  return error;
270 }
271
272 self->ext.version = SND_CTL_EXT_VERSION;
273 self->ext.card_idx = 0; /* FIXME */
274 strncpy(self->ext.id, ext_id, sizeof(self->ext.id) - 1);
275 strcpy(self->ext.driver, "OSS-Emulation");
276 strncpy(self->ext.name, ext_name, sizeof(self->ext.name) - 1);
277 strncpy(self->ext.longname, ext_name, sizeof(self->ext.longname) - 1);
278 strncpy(self->ext.mixername, ext_name, sizeof(self->ext.mixername) - 1);
279 self->ext.poll_fd = -1;
280 self->ext.callback = &roar_ext_callback;
281 self->ext.private_data = self;
282
283 if ( (error = snd_ctl_ext_create(&(self->ext), name, mode)) < 0 ) {
284  roar_disconnect(&(self->roar.con));
285  free(self);
286  return error;
287 }
288
289 *handlep = self->ext.handle;
290 return 0;
291}
292
293SND_CTL_PLUGIN_SYMBOL(roar);
Note: See TracBrowser for help on using the repository browser.