source: roaraudio/libroarrsound/libroarrsound.c @ 3945:0080e7adf205

Last change on this file since 3945:0080e7adf205 was 3945:0080e7adf205, checked in by phi, 14 years ago

new prototype

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