source: roaraudio/plugins/alsa/pcm.c @ 3658:d506b1a30a24

Last change on this file since 3658:d506b1a30a24 was 3658:d506b1a30a24, checked in by phi, 14 years ago

got it to work, at least in the cases you really, really know what you are doing

File size: 8.4 KB
Line 
1//pcm.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
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#include "roar.h"
37
38static int roar_hw_constraint(struct roar_alsa_pcm * self) {
39 snd_pcm_ioplug_t *io = &(self->io);
40 static const snd_pcm_access_t access_list[] = {
41  SND_PCM_ACCESS_RW_INTERLEAVED
42 };
43 static const unsigned int formats[] = {
44  // TODO: add list of additioal formats we support
45  SND_PCM_FORMAT_U8,
46  SND_PCM_FORMAT_A_LAW,
47  SND_PCM_FORMAT_MU_LAW,
48  SND_PCM_FORMAT_S16_LE,
49  SND_PCM_FORMAT_S16_BE,
50 };
51 int ret;
52
53 ROAR_DBG("roar_hw_constraint(*) = ?");
54
55 if ( (ret = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
56        _as(access_list), access_list)) < 0 )
57  return ret;
58
59 if ( (ret = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
60        _as(formats), formats)) < 0 )
61  return ret;
62
63 if ( (ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
64        1, ROAR_MAX_CHANNELS)) < 0 )
65  return ret;
66
67 if ( (ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 48000)) < 0 )
68  return ret;
69
70 if ( (ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 1, 4294967295U)) < 0 )
71  return ret;
72
73 if ( (ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 1, 4294967295U)) < 0 )
74  return ret;
75
76 if ( (ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_BUFFER_BYTES, 1, 4294967295U)) < 0 )
77  return ret;
78
79 ROAR_DBG("roar_hw_constraint(*) = 0");
80
81 return 0;
82}
83
84static int roar_pcm_dummy (snd_pcm_ioplug_t * io) {
85 ROAR_DBG("roar_pcm_dummy(*) = 0");
86 return 0;
87}
88
89static snd_pcm_sframes_t roar_pcm_pointer(snd_pcm_ioplug_t *io) {
90 struct roar_alsa_pcm * self = io->private_data;
91
92 ROAR_DBG("roar_pcm_pointer(*) = ?");
93
94 return snd_pcm_bytes_to_frames(io->pcm, self->writec);
95}
96
97// TODO: FIXME: add support for reading data!
98static snd_pcm_sframes_t roar_pcm_transfer(snd_pcm_ioplug_t *io,
99                                        const snd_pcm_channel_area_t *areas,
100                                        snd_pcm_uframes_t offset,
101                                        snd_pcm_uframes_t size) {
102 struct roar_alsa_pcm * self = io->private_data;
103 char * buf;
104 size_t len = size * self->info.channels * self->info.bits / 8;
105 ssize_t ret;
106
107 ROAR_DBG("roar_pcm_transfer(*) = ?");
108 ROAR_DBG("roar_pcm_transfer(*): len=%lu", (long unsigned int) len);
109
110 buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8;
111
112 ret = roar_vio_write(&(self->stream_vio), buf, len);
113
114 if ( ret != -1 )
115  self->writec += ret;
116
117 ROAR_DBG("roar_pcm_transfer(*) = %lli", (long long int)size);
118 return size;
119}
120
121static int roar_pcm_delay(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp) {
122 ROAR_DBG("roar_pcm_delay(*) = ?");
123 return 0;
124}
125
126static int roar_pcm_prepare(snd_pcm_ioplug_t *io) {
127 struct roar_alsa_pcm * self = io->private_data;
128
129 ROAR_DBG("roar_pcm_prepare(*) = ?");
130
131 if ( self->stream_opened ) {
132  roar_vio_close(&(self->stream_vio));
133  self->stream_opened = 0;
134 }
135
136#if 0
137 if ( roar_stream_new(&(self->stream), self->info.rate, self->info.channels, self->info.bits, self->info.codec) == -1 ) {
138  return -EINVAL;
139 }
140
141 if ( roar_stream_connect(&(self->roar.con), &(self->stream), io->stream == SND_PCM_STREAM_PLAYBACK ? ROAR_DIR_PLAY : ROAR_DIR_MONITOR) == -1 ) {
142  return -EINVAL;
143 }
144#endif
145 if ( roar_vio_simple_new_stream_obj(&(self->stream_vio), &(self->roar.con), &(self->stream),
146                                     self->info.rate, self->info.channels, self->info.bits, self->info.codec,
147                                     io->stream == SND_PCM_STREAM_PLAYBACK ? ROAR_DIR_PLAY : ROAR_DIR_MONITOR
148                                    ) == -1 ) {
149  return -EINVAL;
150 }
151
152 self->stream_opened = 1;
153
154 ROAR_DBG("roar_pcm_prepare(*) = 0");
155 return 0;
156}
157
158static int roar_pcm_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) {
159 struct roar_alsa_pcm * self = io->private_data;
160
161 ROAR_DBG("roar_pcm_hw_params(*) = ?");
162
163 self->info.channels = io->channels;
164 self->info.rate     = io->rate;
165
166 switch (io->format) {
167  case SND_PCM_FORMAT_U8:
168    self->info.codec = ROAR_CODEC_PCM_U_LE;
169    self->info.bits  = 8;
170   break;
171  case SND_PCM_FORMAT_A_LAW:
172    self->info.codec = ROAR_CODEC_ALAW;
173    self->info.bits  = 8;
174   break;
175  case SND_PCM_FORMAT_MU_LAW:
176    self->info.codec = ROAR_CODEC_MULAW;
177    self->info.bits  = 8;
178   break;
179  case SND_PCM_FORMAT_S16_LE:
180    self->info.codec = ROAR_CODEC_PCM_S_LE;
181    self->info.bits  = 16;
182   break;
183  case SND_PCM_FORMAT_S16_BE:
184    self->info.codec = ROAR_CODEC_PCM_S_BE;
185    self->info.bits  = 16;
186   break;
187  default:
188    return-EINVAL;
189 }
190
191 ROAR_DBG("roar_pcm_hw_params(*) = 0");
192 return 0;
193}
194
195static int roar_pcm_close (snd_pcm_ioplug_t * io) {
196 struct roar_alsa_pcm * self = io->private_data;
197
198 ROAR_DBG("roar_pcm_close(*) = ?");
199
200 roar_disconnect(&(self->roar.con));
201
202 free(self);
203
204 return 0;
205}
206
207static snd_pcm_ioplug_callback_t roar_pcm_callback = {
208    .start                  = roar_pcm_dummy,
209    .stop                   = roar_pcm_dummy,
210    .drain                  = roar_pcm_dummy,
211    .pointer                = roar_pcm_pointer,
212    .transfer               = roar_pcm_transfer,
213    .delay                  = roar_pcm_delay,
214    .poll_descriptors_count = NULL,
215    .poll_descriptors       = NULL,
216    .poll_revents           = NULL,
217    .prepare                = roar_pcm_prepare,
218    .hw_params              = roar_pcm_hw_params,
219    .hw_free                = NULL,
220    .sw_params              = NULL,
221    .pause                  = NULL,
222    .resume                 = NULL,
223    .dump                   = NULL,
224    .close                  = roar_pcm_close,
225};
226
227SND_PCM_PLUGIN_DEFINE_FUNC(roar) {
228 struct roar_alsa_pcm * self;
229 snd_config_iterator_t i, next;
230 snd_config_t * n;
231 const char   * para;
232 const char   * server = NULL;
233 int            ret;
234
235 ROAR_DBG("SND_PCM_PLUGIN_DEFINE_FUNC(roar) = ?");
236
237 snd_config_for_each(i, next, conf) {
238  n = snd_config_iterator_entry(i);
239  if ( snd_config_get_id(n, &para) < 0 )
240   continue;
241
242  if ( !strcmp(para, "type") || !strcmp(para, "comment") )
243   continue;
244
245  if ( !strcmp(para, "server") ) {
246   if (snd_config_get_string(n, &server) < 0) {
247    return -EINVAL;
248   }
249  } else {
250   return -EINVAL;
251  }
252 }
253
254 errno = ENOSYS;
255
256 if ( (self = malloc(sizeof(struct roar_alsa_pcm))) == NULL )
257  return -errno;
258
259 memset(self, 0, sizeof(struct roar_alsa_pcm));
260
261 errno = ENOSYS;
262 if ( roar_simple_connect(&(self->roar.con), (char*)server, "ALSA Plugin") == -1 ) {
263  free(self);
264  return -errno;
265 }
266
267 self->io.version      = SND_PCM_IOPLUG_VERSION;
268 self->io.name         = "RoarAudio Plugin";
269 self->io.poll_fd      = -1;
270 self->io.poll_events  =  0;
271 self->io.mmap_rw      =  0;
272 self->io.callback     = &roar_pcm_callback;
273 self->io.private_data =  self;
274
275 if ( (ret = snd_pcm_ioplug_create(&(self->io), name, stream, mode)) < 0 ) {
276  roar_disconnect(&(self->roar.con));
277  free(self);
278  return ret;
279 }
280
281 if ( (ret = roar_hw_constraint(self)) < 0 ) {
282  snd_pcm_ioplug_delete(&(self->io));
283  roar_disconnect(&(self->roar.con));
284  free(self);
285  return ret;
286 }
287
288 *pcmp = self->io.pcm;
289
290 ROAR_DBG("SND_PCM_PLUGIN_DEFINE_FUNC(roar) = 0");
291
292 return 0;
293}
294
295SND_PCM_PLUGIN_SYMBOL(roar);
296
297int __snd_pcm_roar_open_dlsym_pcm_001 (void) {
298 ROAR_DBG("__snd_pcm_roar_open_dlsym_pcm_001(void) = 0");
299 return 0;
300}
301
302//ll
Note: See TracBrowser for help on using the repository browser.