source: roaraudio/libroarpulse/stream.c @ 3434:6dd7040af0f3

Last change on this file since 3434:6dd7040af0f3 was 3434:6dd7040af0f3, checked in by phi, 14 years ago

implement most basic _roar_pa_stream_open()

File size: 17.5 KB
Line 
1//stream.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 libpulse*. They are mostly copyrighted by:
7 *  Lennart Poettering <poettering@users.sourceforge.net> and
8 *  Pierre Ossman <drzeus@drzeus.cx>
9 *
10 *  This file is part of libroarpulse a part of RoarAudio,
11 *  a cross-platform sound system for both, home and professional use.
12 *  See README for details.
13 *
14 *  This file is free software; you can redistribute it and/or modify
15 *  it under the terms of the GNU General Public License version 3
16 *  as published by the Free Software Foundation.
17 *
18 *  RoarAudio is distributed in the hope that it will be useful,
19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *  GNU General Public License for more details.
22 *
23 *  You should have received a copy of the GNU General Public License
24 *  along with this software; see the file COPYING.  If not, write to
25 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 *  NOTE for everyone want's to change something and send patches:
28 *  read README and HACKING! There a addition information on
29 *  the license of this document you need to read before you send
30 *  any patches.
31 *
32 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
33 *  or libpulse*:
34 *  The libs libroaresd, libroararts and libroarpulse link this libroar
35 *  and are therefore GPL. Because of this it may be illigal to use
36 *  them with any software that uses libesd, libartsc or libpulse*.
37 */
38
39#include <libroarpulse/libroarpulse.h>
40
41struct _roar_pa_stream_cb {
42 union {
43  pa_stream_notify_cb_t  ncb;
44  pa_stream_request_cb_t rcb;
45  pa_stream_success_cb_t scb;
46 } cb;
47 void * userdata;
48};
49
50struct pa_stream {
51 size_t refc;
52 pa_context * c;
53 struct roar_vio_calls vio;
54 struct roar_stream stream;
55 pa_stream_state_t state;
56 pa_sample_spec    sspec;
57 struct roar_buffer * iobuffer;
58 struct {
59  size_t size;
60  size_t num;
61 } fragments;
62 struct {
63  struct _roar_pa_stream_cb change_state;
64  struct _roar_pa_stream_cb write;
65  struct _roar_pa_stream_cb read;
66  struct _roar_pa_stream_cb overflow;
67  struct _roar_pa_stream_cb underflow;
68  struct _roar_pa_stream_cb latency;
69 } cb;
70};
71
72typedef void pa_proplist;
73void pa_stream_set_state(pa_stream *s, pa_stream_state_t st);
74
75pa_stream* pa_stream_new_with_proplist(
76        pa_context *c                     ,
77        const char *name                  ,
78        const pa_sample_spec *ss          ,
79        const pa_channel_map *map         ,
80        pa_proplist *p                    );
81
82/** Create a new, unconnected stream with the specified name and sample type */
83pa_stream* pa_stream_new(
84        pa_context *c                     /**< The context to create this stream in */,
85        const char *name                  /**< A name for this stream */,
86        const pa_sample_spec *ss          /**< The desired sample format */,
87        const pa_channel_map *map         /**< The desired channel map, or NULL for default */) {
88 return pa_stream_new_with_proplist(c, name, ss, map, NULL);
89}
90
91pa_stream* pa_stream_new_with_proplist(
92        pa_context *c                     ,
93        const char *name                  ,
94        const pa_sample_spec *ss          ,
95        const pa_channel_map *map         ,
96        pa_proplist *p                    ) {
97 pa_stream * s;
98
99 if ( p != NULL )
100  return NULL;
101
102 if ( (s = roar_mm_malloc(sizeof(pa_stream))) == NULL )
103  return NULL;
104
105 memset(s, 0, sizeof(pa_stream));
106
107 memcpy(&(s->sspec), ss, sizeof(pa_sample_spec));
108
109 if ( roar_pa_sspec2auinfo(&(s->stream.info), ss) == -1 ) {
110  roar_mm_free(s);
111  return NULL;
112 }
113
114 s->fragments.num  = 4;
115 s->fragments.size = 2048;
116
117 s->state = PA_STREAM_UNCONNECTED;
118 s->c     = c;
119 pa_context_ref(c);
120
121 return s;
122}
123
124static void _pa_stream_free(pa_stream * s) {
125 pa_stream_disconnect(s);
126 pa_context_unref(s->c);
127 roar_mm_free(s);
128}
129
130/** Decrease the reference counter by one */
131void pa_stream_unref(pa_stream *s) {
132 if ( s == NULL )
133  return;
134
135 s->refc--;
136
137 if (s->refc < 1 )
138  _pa_stream_free(s);
139}
140
141/** Increase the reference counter by one */
142pa_stream *pa_stream_ref(pa_stream *s) {
143 if ( s == NULL )
144  return NULL;
145
146 s->refc++;
147
148 return s;
149}
150
151/** Return the current state of the stream */
152pa_stream_state_t pa_stream_get_state(pa_stream *p) {
153 if ( p == NULL )
154  return PA_STREAM_FAILED;
155
156 return p->state;
157}
158
159/** Return the context this stream is attached to */
160pa_context* pa_stream_get_context(pa_stream *p) {
161 if ( p == NULL )
162  return NULL;
163
164 return p->c;
165}
166
167/** Return the device (sink input or source output) index this stream is connected to */
168uint32_t pa_stream_get_index(pa_stream *s) {
169 return 0;
170}
171
172static int _roar_pa_stream_open (pa_stream *s,
173                                 const char *dev,
174                                 const pa_buffer_attr *attr,
175                                 pa_stream_flags_t flags,
176                                 pa_cvolume *volume,
177                                 pa_stream *sync_stream,
178                                 pa_stream_direction_t dir) {
179 struct roar_connection * con;
180
181 if ( s == NULL )
182  return -1;
183
184 if ( attr != NULL || flags != 0 || volume != NULL || sync_stream != NULL ) {
185  pa_stream_set_state(s, PA_STREAM_FAILED);
186  return -1;
187 }
188
189 if ( (con = roar_pa_context_get_con(s->c)) == NULL ) {
190  pa_stream_set_state(s, PA_STREAM_FAILED);
191  return -1;
192 }
193
194 switch (dir) {
195  case PA_STREAM_PLAYBACK:
196    s->stream.dir = ROAR_DIR_PLAY;
197   break;
198  case PA_STREAM_RECORD:
199    s->stream.dir = ROAR_DIR_MONITOR;
200   break;
201  default:
202    pa_stream_set_state(s, PA_STREAM_FAILED);
203    return -1;
204   break;
205 }
206
207 if ( roar_vio_simple_new_stream_obj(&(s->vio), con, &(s->stream),
208                                     s->stream.info.rate, s->stream.info.channels,
209                                     s->stream.info.bits, s->stream.info.codec,
210                                     s->stream.dir) == -1 ) {
211  pa_stream_set_state(s, PA_STREAM_FAILED);
212  return -1;
213 }
214
215 pa_stream_set_state(s, PA_STREAM_READY);
216
217 return 0;
218}
219
220/** Connect the stream to a sink */
221int pa_stream_connect_playback(
222        pa_stream *s                  /**< The stream to connect to a sink */,
223        const char *dev               /**< Name of the sink to connect to, or NULL for default */ ,
224        const pa_buffer_attr *attr    /**< Buffering attributes, or NULL for default */,
225        pa_stream_flags_t flags       /**< Additional flags, or 0 for default */,
226        pa_cvolume *volume            /**< Initial volume, or NULL for default */,
227        pa_stream *sync_stream        /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/) {
228 return _roar_pa_stream_open(s, dev, attr, flags, volume, sync_stream, PA_STREAM_PLAYBACK);
229}
230
231/** Connect the stream to a source */
232int pa_stream_connect_record(
233        pa_stream *s                  /**< The stream to connect to a source */ ,
234        const char *dev               /**< Name of the source to connect to, or NULL for default */,
235        const pa_buffer_attr *attr    /**< Buffer attributes, or NULL for default */,
236        pa_stream_flags_t flags       /**< Additional flags, or 0 for default */) {
237 return _roar_pa_stream_open(s, dev, attr, flags, NULL, NULL, PA_STREAM_RECORD);
238}
239
240/** Disconnect a stream from a source/sink */
241int pa_stream_disconnect(pa_stream *s) {
242 if ( s == NULL )
243  return -1;
244
245 if ( s->state != PA_STREAM_READY )
246  return -1;
247
248 roar_vio_close(&(s->vio));
249
250 pa_stream_set_state(s, PA_STREAM_TERMINATED);
251
252 return 0;
253}
254
255/** Write some data to the server (for playback sinks), if free_cb is
256 * non-NULL this routine is called when all data has been written out
257 * and an internal reference to the specified data is kept, the data
258 * is not copied. If NULL, the data is copied into an internal
259 * buffer. The client my freely seek around in the output buffer. For
260 * most applications passing 0 and PA_SEEK_RELATIVE as arguments for
261 * offset and seek should be useful.*/
262int pa_stream_write(
263        pa_stream *p             /**< The stream to use */,
264        const void *data         /**< The data to write */,
265        size_t length            /**< The length of the data to write */,
266        pa_free_cb_t free_cb     /**< A cleanup routine for the data or NULL to request an internal copy */,
267        int64_t offset,          /**< Offset for seeking, must be 0 for upload streams */
268        pa_seek_mode_t seek      /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */) {
269 struct roar_buffer * buf;
270 void               * bufdata;
271
272 // TODO: implement seeking in output buffer
273
274 if ( p == NULL )
275  return -1;
276
277 if ( offset != 0 || seek != PA_SEEK_RELATIVE )
278  return -1;
279
280 if ( data == NULL ) {
281  if ( length == 0 ) {
282   if ( free_cb != NULL )
283    free_cb(NULL);
284
285   return 0;
286  } else {
287   return -1;
288  }
289 }
290
291 // seems we have a valid write from here.
292
293 if ( roar_buffer_new(&buf, length) == -1 ) {
294  if ( free_cb != NULL )
295   free_cb((void*)data);
296
297  return -1;
298 }
299
300 if ( roar_buffer_get_data(buf, &bufdata) == -1 ) {
301  if ( free_cb != NULL )
302   free_cb((void*)data);
303
304  return -1;
305 }
306
307 memcpy(bufdata, data, length);
308 if ( free_cb != NULL )
309  free_cb((void*)data);
310
311 if ( p->iobuffer == NULL ) {
312  p->iobuffer = buf;
313 } else {
314  if ( roar_buffer_add(p->iobuffer, buf) == -1 )
315   return -1;
316 }
317
318 return 0;
319}
320
321/** Read the next fragment from the buffer (for recording).
322 * data will point to the actual data and length will contain the size
323 * of the data in bytes (which can be less than a complete framgnet).
324 * Use pa_stream_drop() to actually remove the data from the
325 * buffer. If no data is available will return a NULL pointer  \since 0.8 */
326int pa_stream_peek(
327        pa_stream *p                 /**< The stream to use */,
328        const void **data            /**< Pointer to pointer that will point to data */,
329        size_t *length              /**< The length of the data read */) {
330 if ( data == NULL || length == NULL )
331  return -1;
332
333 *data   = NULL;
334 *length = 0;
335
336 if ( p == NULL )
337  return -1;
338
339 if ( p->iobuffer == NULL )
340  return 0;
341
342 if ( roar_buffer_get_len(p->iobuffer, length) == -1 ) {
343  *length = 0;
344  return -1;
345 }
346
347 if ( roar_buffer_get_data(p->iobuffer, (void**)data) == -1 ) {
348  *length = 0;
349  *data   = NULL;
350  return -1;
351 }
352
353 return 0;
354}
355
356/** Remove the current fragment on record streams. It is invalid to do this without first
357 * calling pa_stream_peek(). \since 0.8 */
358int pa_stream_drop(pa_stream *p) {
359 if ( p == NULL )
360  return -1;
361
362 if ( p->iobuffer == NULL )
363  return -1;
364
365 return roar_buffer_next(&(p->iobuffer));
366}
367
368/** Return the nember of bytes that may be written using pa_stream_write() */
369size_t pa_stream_writable_size(pa_stream *p) {
370 struct roar_buffer_stats stats;
371
372 if ( p == NULL )
373  return 0;
374
375 if ( p->iobuffer == NULL )
376  return 0;
377
378 if ( roar_buffer_ring_stats(p->iobuffer, &stats) == -1 )
379  return 0;
380
381 if ( stats.parts > p->fragments.num )
382  return 0;
383
384 return (p->fragments.num - stats.parts)*p->fragments.size;
385}
386
387/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */
388size_t pa_stream_readable_size(pa_stream *p) {
389 struct roar_buffer_stats stats;
390
391 if ( p == NULL )
392  return 0;
393
394 if ( p->iobuffer == NULL )
395  return 0;
396
397 if ( roar_buffer_ring_stats(p->iobuffer, &stats) == -1 )
398  return 0;
399
400 return stats.bytes;
401}
402
403/** Drain a playback stream. Use this for notification when the buffer is empty */
404pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
405
406/** Request a timing info structure update for a stream. Use
407 * pa_stream_get_timing_info() to get access to the raw timing data,
408 * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned
409 * up values. */
410pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata);
411
412/** Set the callback function that is called whenever the state of the stream changes */
413void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
414 if ( s == NULL )
415  return;
416
417 s->cb.change_state.cb.ncb    = cb;
418 s->cb.change_state.userdata  = userdata;
419}
420
421void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
422 if ( s == NULL )
423  return;
424
425 s->state = st;
426
427 if ( s->cb.change_state.cb.ncb == NULL ) {
428  s->cb.change_state.cb.ncb(s, s->cb.change_state.userdata);
429 }
430}
431
432/** Set the callback function that is called when new data may be
433 * written to the stream. */
434void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata) {
435 if ( p == NULL )
436  return;
437
438 p->cb.write.cb.rcb    = cb;
439 p->cb.write.userdata  = userdata;
440}
441
442/** Set the callback function that is called when new data is available from the stream.
443 * Return the number of bytes read. \since 0.8 */
444void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata) {
445 if ( p == NULL )
446  return;
447
448 p->cb.read.cb.rcb    = cb;
449 p->cb.read.userdata  = userdata;
450}
451
452/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */
453void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
454 if ( p == NULL )
455  return;
456
457 p->cb.overflow.cb.ncb    = cb;
458 p->cb.overflow.userdata  = userdata;
459}
460
461/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */
462void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
463 if ( p == NULL )
464  return;
465
466 p->cb.underflow.cb.ncb    = cb;
467 p->cb.underflow.userdata  = userdata;
468}
469
470/** Set the callback function that is called whenever a latency information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE streams only. (Only for playback streams) \since 0.8.2 */
471void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
472 if ( p == NULL )
473  return;
474
475 p->cb.latency.cb.ncb    = cb;
476 p->cb.latency.userdata  = userdata;
477}
478
479/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */
480pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata);
481
482/** Flush the playback buffer of this stream. Most of the time you're
483 * better off using the parameter delta of pa_stream_write() instead of this
484 * function. Available on both playback and recording streams. \since 0.3 */
485pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
486/** Reenable prebuffering as specified in the pa_buffer_attr
487 * structure. Available for playback streams only. \since 0.6 */
488pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
489
490/** Request immediate start of playback on this stream. This disables
491 * prebuffering as specified in the pa_buffer_attr
492 * structure, temporarily. Available for playback streams only. \since 0.3 */
493pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
494
495/** Rename the stream. \since 0.5 */
496pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata);
497
498/** Return the current playback/recording time. This is based on the
499 * data in the timing info structure returned by
500 * pa_stream_get_timing_info(). This function will usually only return
501 * new data if a timing info update has been recieved. Only if timing
502 * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING)
503 * the data from the last timing update is used for an estimation of
504 * the current playback/recording time based on the local time that
505 * passed since the timing info structure has been acquired. The time
506 * value returned by this function is guaranteed to increase
507 * monotonically. (that means: the returned value is always greater or
508 * equal to the value returned on the last call) This behaviour can
509 * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be
510 * desirable to deal better with bad estimations of transport
511 * latencies, but may have strange effects if the application is not
512 * able to deal with time going 'backwards'. \since 0.6 */
513int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec);
514
515/** Return the total stream latency. This function is based on
516 * pa_stream_get_time(). In case the stream is a monitoring stream the
517 * result can be negative, i.e. the captured samples are not yet
518 * played. In this case *negative is set to 1. \since 0.6 */
519int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative);
520
521/** Return the latest raw timing data structure. The returned pointer
522 * points to an internal read-only instance of the timing
523 * structure. The user should make a copy of this structure if he
524 * wants to modify it. An in-place update to this data structure may
525 * be requested using pa_stream_update_timing_info(). If no
526 * pa_stream_update_timing_info() call was issued before, this
527 * function will fail with PA_ERR_NODATA. Please note that the
528 * write_index member field (and only this field) is updated on each
529 * pa_stream_write() call, not just when a timing update has been
530 * recieved. \since 0.8 */
531const pa_timing_info* pa_stream_get_timing_info(pa_stream *s);
532
533/** Return a pointer to the stream's sample specification. \since 0.6 */
534const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) {
535 if ( s == NULL )
536  return NULL;
537
538 return &(s->sspec);
539}
540
541/** Return a pointer to the stream's channel map. \since 0.8 */
542const pa_channel_map* pa_stream_get_channel_map(pa_stream *s);
543
544/** Return the buffer metrics of the stream. Only valid after the
545 * stream has been connected successfuly and if the server is at least
546 * PulseAudio 0.9. \since 0.9.0 */
547const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s);
548
549//ll
Note: See TracBrowser for help on using the repository browser.