source: roaraudio/libroarrsound/libroarrsound.c @ 4221:a8c72bc698c6

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

fixed FTBFS with newer versions of RSound

File size: 12.4 KB
Line 
1//libroarrsound.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *  The code (may) include prototypes and comments (and maybe
6 *  other code fragements) from RSound.
7 *  They are copyrighted by Hans-Kristian 'maister' Arntzen.
8 *
9 *  This file is part of libroarrsound a part of RoarAudio,
10 *  a cross-platform sound system for both, home and professional use.
11 *  See README for details.
12 *
13 *  This file is free software; you can redistribute it and/or modify
14 *  it under the terms of the GNU General Public License version 3
15 *  as published by the Free Software Foundation.
16 *
17 *  RoarAudio is distributed in the hope that it will be useful,
18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 *  GNU General Public License for more details.
21 *
22 *  You should have received a copy of the GNU General Public License
23 *  along with this software; see the file COPYING.  If not, write to
24 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 *  NOTE for everyone want's to change something and send patches:
27 *  read README and HACKING! There a addition information on
28 *  the license of this document you need to read before you send
29 *  any patches.
30 */
31
32#define RSD_EXPOSE_STRUCT
33#include "libroarrsound.h"
34
35static size_t libroarrsound_fmt2fs (enum rsd_format format) {
36 switch (format) {
37  case RSD_S16_LE:
38  case RSD_S16_BE:
39  case RSD_S16_NE:
40  case RSD_U16_LE:
41  case RSD_U16_BE:
42  case RSD_U16_NE:
43    return 16;
44   break;
45  case RSD_U8:
46  case RSD_S8:
47  case RSD_ALAW:
48  case RSD_MULAW:
49    return 8;
50   break;
51  default:
52    return 0;
53   break;
54 }
55}
56
57int rsd_init (rsound_t **rd) {
58 struct libroarrsound * self;
59
60 ROAR_DBG("rsd_init(rd=%p) = ?", rd);
61
62 if ( rd == NULL )
63  return -1;
64
65 self = roar_mm_malloc(sizeof(struct libroarrsound));
66
67 if ( self == NULL )
68  return -1;
69
70 memset(self, 0, sizeof(struct libroarrsound));
71
72 *rd = (rsound_t*)self;
73
74 self->rsound.conn.socket     = -1;
75 self->rsound.conn.ctl_socket = -1;
76 self->rsound.channels        = ROAR_CHANNELS_DEFAULT;
77 self->rsound.rate            = ROAR_RATE_DEFAULT;
78 self->rsound.format          = RSD_S16_LE;
79
80 strncpy(self->rsound.identity, "libroarrsound client", sizeof(self->rsound.identity) - 1);
81 self->rsound.identity[sizeof(self->rsound.identity)-1] = 0;
82
83 return 0;
84}
85
86/* This is a simpler function that initializes an rsound struct, sets params as given,
87   and starts the stream. Should this function fail, the structure will stay uninitialized.
88   Should NULL be passed in either host, port or ident, defaults will be used. */
89
90int rsd_simple_start (rsound_t **rd, const char* host, const char* port, const char* ident,
91                           int rate, int channels, enum rsd_format format) {
92 rsound_t * rsound;
93
94 if ( rsd_init(rd) == -1 )
95  return -1;
96
97 if ( *rd == NULL )
98  return -1;
99
100 rsound = *rd;
101
102 if ( host != NULL ) {
103  if ( rsd_set_param(rsound, RSD_HOST, (void*)host) == -1 ) {
104   rsd_free(rsound);
105   return -1;
106  }
107 }
108
109 if ( port != NULL ) {
110  if ( rsd_set_param(rsound, RSD_PORT, (void*)port) == -1 ) {
111   rsd_free(rsound);
112   return -1;
113  }
114 }
115
116 if ( ident != NULL ) {
117  if ( rsd_set_param(rsound, RSD_IDENTITY, (void*)ident) == -1 ) {
118   rsd_free(rsound);
119   return -1;
120  }
121 }
122
123 if ( rsd_set_param(rsound, RSD_FORMAT, &format) == -1 ) {
124  rsd_free(rsound);
125  return -1;
126 }
127
128 if ( rsd_set_param(rsound, RSD_CHANNELS, &channels) == -1 ) {
129  rsd_free(rsound);
130  return -1;
131 }
132
133 if ( rsd_set_param(rsound, RSD_SAMPLERATE, &rate) == -1 ) {
134  rsd_free(rsound);
135  return -1;
136 }
137
138 if ( rsd_start(rsound) == -1 ) {
139  rsd_free(rsound);
140  return -1;
141 }
142
143 return 0;
144}
145
146
147/* Frees an rsound_t struct. */
148int rsd_free (rsound_t *rd) {
149 struct libroarrsound * self = (struct libroarrsound *)rd;
150 int ret = 0;
151
152 if ( self == NULL )
153  return -1;
154
155 if ( self->flags & LIBROARRSOUND_FLAGS_CONNECTED )
156  if ( roar_disconnect(&(self->con)) == -1 )
157   ret = -1;
158
159 if ( self->flags & LIBROARRSOUND_FLAGS_STREAMING )
160  if ( roar_vio_close(&(self->vio)) == -1 )
161   ret = -1;
162
163 if ( self->rsound.host != NULL )
164  roar_mm_free(self->rsound.host);
165
166 if ( self->rsound.port != NULL )
167  roar_mm_free(self->rsound.port);
168
169 roar_mm_free(self);
170
171 return ret;
172}
173
174int rsd_set_param (rsound_t *rd, enum rsd_settings option, void* param) {
175 struct libroarrsound * self = (struct libroarrsound *)rd;
176
177 ROAR_DBG("rsd_set_param(rd=%p, option=%i, param=%p) = ?", rd, option, param);
178
179 if ( self == NULL || param == NULL )
180  return -1;
181
182 switch (option) {
183  // connection settings:
184  case RSD_HOST:
185    if ( self->rsound.host != NULL )
186     roar_mm_free(self->rsound.host);
187
188    self->rsound.host = roar_mm_strdup(param);
189   break;
190  case RSD_PORT:
191    if ( self->rsound.port != NULL )
192     roar_mm_free(self->rsound.port);
193
194    self->rsound.port = roar_mm_strdup(param);
195   break;
196#ifdef RSD_IDENTITY
197  case RSD_IDENTITY:
198    strncpy(self->rsound.identity, param, sizeof(self->rsound.identity) - 1);
199    self->rsound.identity[sizeof(self->rsound.identity)-1] = 0;
200   break;
201#endif
202  // stream settings:
203  case RSD_SAMPLERATE:
204    self->rsound.rate = *(int*)param;
205   break;
206  case RSD_CHANNELS:
207    self->rsound.channels = *(int*)param;
208   break;
209  case RSD_FORMAT:
210    self->rsound.format = *(int*)param;
211#ifdef ROAR_HAVE_RSOUND_SAMPLESIZE
212    self->rsound.samplesize = libroarrsound_fmt2fs(self->rsound.format);
213#else
214    self->rsound.framesize = libroarrsound_fmt2fs(self->rsound.format);
215#endif
216   break;
217  default:
218/*
219   RSD_BUFSIZE,
220   RSD_LATENCY,
221*/
222     ROAR_DBG("rsd_set_param(rd=%p, option=%i, param=%p) = -1", rd, option, param);
223    return -1;
224   break;
225 }
226
227 ROAR_DBG("rsd_set_param(rd=%p, option=%i, param=%p) = 0", rd, option, param);
228 return 0;
229}
230
231static int libroarrsound_connect (struct libroarrsound * self) {
232 char * host;
233
234 if ( self->flags & LIBROARRSOUND_FLAGS_CONNECTED )
235  return 0;
236
237 host = self->rsound.host;
238
239 if ( host == NULL )
240  host = getenv("RSD_SERVER");
241
242 // FIXME: we currently ignore the port. :(
243
244 ROAR_DBG("libroarrsound_connect(self=%p): try to connect to: %s", self, host);
245
246 if ( roar_simple_connect(&(self->con), host, self->rsound.identity) == -1 ) {
247  ROAR_DBG("libroarrsound_connect(self=%p) = -1 // can not connect to server", self);
248  return -1;
249 }
250
251 self->flags |= LIBROARRSOUND_FLAGS_CONNECTED;
252
253 ROAR_DBG("libroarrsound_connect(self=%p) = 0", self);
254 return 0;
255}
256
257/* Establishes connection to server. Might fail if connection can't be established or that one of
258   the mandatory options isn't set in rsd_set_param(). This needs to be called after params have been set
259   with rsd_set_param(), and before rsd_write(). */
260int rsd_start (rsound_t *rd) {
261 struct libroarrsound * self = (struct libroarrsound *)rd;
262 int bits  = 16;
263 int codec;
264
265 ROAR_DBG("rsd_start(rd=%p) = ?", rd);
266
267 if ( self == NULL )
268  return -1;
269
270 if ( self->flags & LIBROARRSOUND_FLAGS_STREAMING )
271  return 0;
272
273 ROAR_DBG("rsd_start(rd=%p) = ?", rd);
274
275 if ( !(self->flags & LIBROARRSOUND_FLAGS_CONNECTED) ) {
276  if ( libroarrsound_connect(self) == -1 )
277   return -1;
278 }
279
280 ROAR_DBG("rsd_start(rd=%p) = ?", rd);
281
282 switch (self->rsound.format) {
283  case RSD_S16_LE:
284    codec = ROAR_CODEC_PCM_S_LE;
285   break;
286  case RSD_S16_BE:
287    codec = ROAR_CODEC_PCM_S_BE;
288   break;
289  case RSD_S16_NE:
290    codec = ROAR_CODEC_PCM_S;
291   break;
292  case RSD_U16_LE:
293    codec = ROAR_CODEC_PCM_U_LE;
294   break;
295  case RSD_U16_BE:
296    codec = ROAR_CODEC_PCM_U_BE;
297   break;
298  case RSD_U16_NE:
299    codec = ROAR_CODEC_PCM_U;
300   break;
301  case RSD_S8:
302    codec = ROAR_CODEC_PCM_S;
303    bits  = 8;
304   break;
305  case RSD_U8:
306    codec = ROAR_CODEC_PCM_U;
307    bits  = 8;
308   break;
309  case RSD_ALAW:
310    codec = ROAR_CODEC_ALAW;
311    bits  = 8;
312   break;
313  case RSD_MULAW:
314    codec = ROAR_CODEC_MULAW;
315    bits  = 8;
316   break;
317  default:
318    return -1;
319   break;
320 }
321
322 ROAR_DBG("rsd_start(rd=%p) = ?", rd);
323
324 if ( roar_vio_simple_new_stream_obj(&(self->vio), &(self->con), &(self->stream),
325                                     self->rsound.rate, self->rsound.channels, bits, codec, ROAR_DIR_PLAY) == -1 )
326  return -1;
327
328 ROAR_DBG("rsd_start(rd=%p) = ?", rd);
329
330 self->flags |= LIBROARRSOUND_FLAGS_STREAMING;
331
332 ROAR_DBG("rsd_start(rd=%p) = 0", rd);
333
334 return 0;
335}
336
337/* Shuts down the rsound data structures, but returns the file descriptor associated with the connection.
338   The control socket will be shut down. If this function returns a negative number, the exec failed,
339   but the data structures will not be teared down.
340   Should a valid file descriptor be returned, it will always be non-blocking.  <<-- FIXME? */
341int rsd_exec (rsound_t *rd) {
342 struct libroarrsound * self = (struct libroarrsound *)rd;
343 int fh;
344
345 ROAR_DBG("rsd_exec(rd=%p) = ?", rd);
346
347 if ( !(self->flags & LIBROARRSOUND_FLAGS_STREAMING) )
348  if ( rsd_start(rd) == -1 )
349   return -1;
350
351 ROAR_DBG("rsd_exec(rd=%p) = ?", rd);
352
353 if ( roar_vio_ctl(&(self->vio), ROAR_VIO_CTL_GET_FH, &fh) == -1 )
354  return -1;
355
356 ROAR_DBG("rsd_exec(rd=%p) = ?", rd);
357
358 if ( fh == -1 )
359  return -1;
360
361 ROAR_DBG("rsd_exec(rd=%p) = ?", rd);
362
363 if ( roar_stream_exec(&(self->con), &(self->stream)) == -1 )
364  return -1;
365
366 ROAR_DBG("rsd_exec(rd=%p) = ?", rd);
367
368 // reset flags:
369 if ( self->flags & LIBROARRSOUND_FLAGS_CONNECTED )
370  self->flags -= LIBROARRSOUND_FLAGS_CONNECTED;
371
372 if ( self->flags & LIBROARRSOUND_FLAGS_STREAMING )
373  self->flags -= LIBROARRSOUND_FLAGS_STREAMING;
374
375 ROAR_DBG("rsd_exec(rd=%p) = ?", rd);
376
377 // we hope nothing goes wrong here:
378 rsd_free(rd);
379
380 ROAR_DBG("rsd_exec(rd=%p) = %i", rd, fh);
381
382 return fh;
383}
384
385/* Disconnects from server. All audio data still in network buffer and other buffers will be dropped.
386   To continue playing, you will need to rsd_start() again. */
387int rsd_stop (rsound_t *rd) {
388 struct libroarrsound * self = (struct libroarrsound *)rd;
389 int ret;
390
391 if ( self == NULL )
392  return -1;
393
394 if ( !(self->flags & LIBROARRSOUND_FLAGS_STREAMING) )
395  return 0;
396
397 ret = roar_vio_close(&(self->vio));
398
399 self->flags -= LIBROARRSOUND_FLAGS_STREAMING;
400
401 return ret;
402}
403
404/* Writes from buf to the internal buffer. Might fail if no connection is established,
405   or there was an unexpected error. This function will block until all data has
406   been written to the buffer. This function will return the number of bytes written to the buffer,
407   or 0 should it fail (disconnection from server). You will have to restart the stream again should this occur. */
408size_t rsd_write (rsound_t *rd, const void * buf, size_t size) {
409 struct libroarrsound * self = (struct libroarrsound *)rd;
410 ssize_t ret;
411
412 if ( self == NULL )
413  return -1;
414
415 if ( !(self->flags & LIBROARRSOUND_FLAGS_STREAMING) )
416  return 0;
417
418 ret = roar_vio_write(&(self->vio), (void*)buf, size);
419
420 if ( ret == -1 )
421  return 0;
422
423 return ret;
424}
425
426/* Gets the position of the buffer pointer.
427   Not really interesting for normal applications.
428   Might be useful for implementing rsound on top of other blocking APIs. */
429size_t rsd_pointer (rsound_t *rd);
430
431/* Aquires how much data can be written to the buffer without blocking */
432size_t rsd_get_avail (rsound_t *rd);
433
434/* Aquires the latency at the moment for the audio stream. It is measured in bytes. Useful for syncing video and audio. */
435size_t rsd_delay (rsound_t *rd) {
436 (void)rd;
437 return 0; // TODO: FIXME: write some code to read pos from server.
438}
439
440/* Utility for returning latency in milliseconds. */
441size_t rsd_delay_ms (rsound_t *rd) {
442 if ( rd == NULL )
443  return -1;
444
445 if ( rd->rate <= 0 || rd->channels <= 0 )
446  return -1;
447
448#ifdef ROAR_HAVE_RSOUND_SAMPLESIZE
449 return (rsd_delay(rd) * 1000) / (rd->rate * rd->channels * rd->samplesize);
450#else
451 return (rsd_delay(rd) * 1000) / (rd->rate * rd->channels * rd->framesize);
452#endif
453}
454
455/* Returns bytes per sample */
456int rsd_samplesize( rsound_t *rd ) {
457 if ( rd == NULL )
458  return -1;
459
460#ifdef ROAR_HAVE_RSOUND_SAMPLESIZE
461 return rd->samplesize;
462#else
463 return rd->framesize;
464#endif
465}
466
467/* Will sleep until latency of stream reaches maximum allowed latency defined earlier by rsd_set_param - RSD_LATENCY
468   Useful for hard headed blocking I/O design where user defined latency is needed. If rsd_set_param hasn't been set
469   with RSD_LATENCY, this function will do nothing. */
470void rsd_delay_wait(rsound_t *rd);
471
472
473/* Pauses or unpauses a stream. pause -> enable = 1
474   This function essentially calls on start() and stop(). This behavior might be changed later. */
475int rsd_pause (rsound_t *rd, int enable) {
476 struct libroarrsound * self = (struct libroarrsound *)rd;
477
478 if ( self == NULL )
479  return -1;
480
481 if ( !(self->flags & LIBROARRSOUND_FLAGS_STREAMING) )
482  return -1;
483
484 return roar_stream_set_flags(&(self->con), &(self->stream), ROAR_FLAG_PAUSE, enable ? ROAR_SET_FLAG : ROAR_RESET_FLAG);
485}
486
487//ll
Note: See TracBrowser for help on using the repository browser.