source: roaraudio/libroarrsound/libroarrsound.c @ 4607:d00a1ae1f387

Last change on this file since 4607:d00a1ae1f387 was 4607:d00a1ae1f387, checked in by phi, 13 years ago

Added RSound's new 32 bit support to libroarrsound

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