source: roaraudio/libroarpulse/stream.c @ 3449:ba42ab088e13

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

support pa_stream_drain()

File size: 19.6 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 pa_io_event           * io_event;
58 struct roar_buffer    * iobuffer;
59 struct {
60  size_t size;
61  size_t num;
62 } fragments;
63 struct {
64  struct _roar_pa_stream_cb change_state;
65  struct _roar_pa_stream_cb write;
66  struct _roar_pa_stream_cb read;
67  struct _roar_pa_stream_cb overflow;
68  struct _roar_pa_stream_cb underflow;
69  struct _roar_pa_stream_cb latency;
70  struct _roar_pa_stream_cb drain;
71 } cb;
72 struct {
73  pa_operation * drain;
74 } op;
75};
76
77typedef void pa_proplist;
78void pa_stream_set_state(pa_stream *s, pa_stream_state_t st);
79
80pa_stream* pa_stream_new_with_proplist(
81        pa_context *c                     ,
82        const char *name                  ,
83        const pa_sample_spec *ss          ,
84        const pa_channel_map *map         ,
85        pa_proplist *p                    );
86
87/** Create a new, unconnected stream with the specified name and sample type */
88pa_stream* pa_stream_new(
89        pa_context *c                     /**< The context to create this stream in */,
90        const char *name                  /**< A name for this stream */,
91        const pa_sample_spec *ss          /**< The desired sample format */,
92        const pa_channel_map *map         /**< The desired channel map, or NULL for default */) {
93 return pa_stream_new_with_proplist(c, name, ss, map, NULL);
94}
95
96pa_stream* pa_stream_new_with_proplist(
97        pa_context *c                     ,
98        const char *name                  ,
99        const pa_sample_spec *ss          ,
100        const pa_channel_map *map         ,
101        pa_proplist *p                    ) {
102 pa_stream * s;
103
104 ROAR_DBG("pa_stream_new_with_proplist(c=%p, name='%s', ss=%p, map=%p, p=%p) = ?", c, name, ss, map, p);
105
106 if ( p != NULL )
107  return NULL;
108
109 if ( (s = roar_mm_malloc(sizeof(pa_stream))) == NULL )
110  return NULL;
111
112 memset(s, 0, sizeof(pa_stream));
113
114 memcpy(&(s->sspec), ss, sizeof(pa_sample_spec));
115
116 ROAR_DBG("pa_stream_new_with_proplist(c=%p, name='%s', ss=%p, map=%p, p=%p) = ?", c, name, ss, map, p);
117
118 s->fragments.num  = 4;
119 s->fragments.size = 2048;
120
121 s->state = PA_STREAM_UNCONNECTED;
122 s->c     = c;
123 pa_context_ref(c);
124
125 ROAR_DBG("pa_stream_new_with_proplist(c=%p, name='%s', ss=%p, map=%p, p=%p) = ?", c, name, ss, map, p);
126
127 return s;
128}
129
130static void _pa_stream_free(pa_stream * s) {
131 pa_stream_disconnect(s);
132 pa_context_unref(s->c);
133 roar_mm_free(s);
134}
135
136/** Decrease the reference counter by one */
137void pa_stream_unref(pa_stream *s) {
138 if ( s == NULL )
139  return;
140
141 s->refc--;
142
143 if (s->refc < 1 )
144  _pa_stream_free(s);
145}
146
147/** Increase the reference counter by one */
148pa_stream *pa_stream_ref(pa_stream *s) {
149 if ( s == NULL )
150  return NULL;
151
152 s->refc++;
153
154 return s;
155}
156
157/** Return the current state of the stream */
158pa_stream_state_t pa_stream_get_state(pa_stream *p) {
159 if ( p == NULL )
160  return PA_STREAM_FAILED;
161
162 return p->state;
163}
164
165/** Return the context this stream is attached to */
166pa_context* pa_stream_get_context(pa_stream *p) {
167 if ( p == NULL )
168  return NULL;
169
170 return p->c;
171}
172
173/** Return the device (sink input or source output) index this stream is connected to */
174uint32_t pa_stream_get_index(pa_stream *s) {
175 return 0;
176}
177
178static void _roar_pa_stream_ioecb(pa_mainloop_api     * ea,
179                                  pa_io_event         * e,
180                                  int                   fd,
181                                  pa_io_event_flags_t   events,
182                                  void                * userdata) {
183 ROAR_DBG("_roar_pa_stream_ioecb(*) = (void)");
184}
185
186static int _roar_pa_stream_open (pa_stream *s,
187                                 const char *dev,
188                                 const pa_buffer_attr *attr,
189                                 pa_stream_flags_t flags,
190                                 pa_cvolume *volume,
191                                 pa_stream *sync_stream,
192                                 pa_stream_direction_t dir) {
193 struct roar_connection * con;
194 pa_mainloop_api * api;
195 pa_io_event_flags_t event_flags = PA_IO_EVENT_HANGUP;
196 int fh;
197 int ctl = -1;
198
199 if ( s == NULL )
200  return -1;
201
202 if ( attr != NULL || flags != 0 || volume != NULL || sync_stream != NULL ) {
203  pa_stream_set_state(s, PA_STREAM_FAILED);
204  return -1;
205 }
206
207 if ( (con = roar_pa_context_get_con(s->c)) == NULL ) {
208  pa_stream_set_state(s, PA_STREAM_FAILED);
209  return -1;
210 }
211
212 switch (dir) {
213  case PA_STREAM_PLAYBACK:
214    s->stream.dir = ROAR_DIR_PLAY;
215    ctl           = ROAR_VIO_CTL_GET_SELECT_WRITE_FH;
216    event_flags  |= PA_IO_EVENT_OUTPUT;
217   break;
218  case PA_STREAM_RECORD:
219    s->stream.dir = ROAR_DIR_MONITOR;
220    ctl           = ROAR_VIO_CTL_GET_SELECT_READ_FH;
221    event_flags  |= PA_IO_EVENT_INPUT;
222   break;
223  default:
224    pa_stream_set_state(s, PA_STREAM_FAILED);
225    return -1;
226   break;
227 }
228
229 if ( roar_pa_sspec2auinfo(&(s->stream.info), &(s->sspec)) == -1 ) {
230  pa_stream_set_state(s, PA_STREAM_FAILED);
231  return -1;
232 }
233
234 if ( roar_vio_simple_new_stream_obj(&(s->vio), con, &(s->stream),
235                                     s->stream.info.rate, s->stream.info.channels,
236                                     s->stream.info.bits, s->stream.info.codec,
237                                     s->stream.dir) == -1 ) {
238  pa_stream_set_state(s, PA_STREAM_FAILED);
239  return -1;
240 }
241
242 api = roar_pa_context_get_api(s->c);
243
244 if ( api != NULL && api->io_new != NULL ) {
245  if ( roar_vio_ctl(&(s->vio), ctl, &fh) != -1 ) {
246   s->io_event = api->io_new(api, fh, event_flags, _roar_pa_stream_ioecb, s);
247  }
248 }
249
250 pa_stream_set_state(s, PA_STREAM_READY);
251
252 return 0;
253}
254
255/** Connect the stream to a sink */
256int pa_stream_connect_playback(
257        pa_stream *s                  /**< The stream to connect to a sink */,
258        const char *dev               /**< Name of the sink to connect to, or NULL for default */ ,
259        const pa_buffer_attr *attr    /**< Buffering attributes, or NULL for default */,
260        pa_stream_flags_t flags       /**< Additional flags, or 0 for default */,
261        pa_cvolume *volume            /**< Initial volume, or NULL for default */,
262        pa_stream *sync_stream        /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/) {
263 return _roar_pa_stream_open(s, dev, attr, flags, volume, sync_stream, PA_STREAM_PLAYBACK);
264}
265
266/** Connect the stream to a source */
267int pa_stream_connect_record(
268        pa_stream *s                  /**< The stream to connect to a source */ ,
269        const char *dev               /**< Name of the source to connect to, or NULL for default */,
270        const pa_buffer_attr *attr    /**< Buffer attributes, or NULL for default */,
271        pa_stream_flags_t flags       /**< Additional flags, or 0 for default */) {
272 return _roar_pa_stream_open(s, dev, attr, flags, NULL, NULL, PA_STREAM_RECORD);
273}
274
275/** Disconnect a stream from a source/sink */
276int pa_stream_disconnect(pa_stream *s) {
277 pa_mainloop_api * api;
278
279 if ( s == NULL )
280  return -1;
281
282 if ( s->state != PA_STREAM_READY )
283  return -1;
284
285 if ( s->io_event != NULL ) {
286  api = roar_pa_context_get_api(s->c);
287
288  if ( api != NULL && api->io_free != NULL ) {
289   api->io_free(s->io_event);
290   s->io_event = NULL;
291  }
292 }
293
294 roar_vio_close(&(s->vio));
295
296 pa_stream_set_state(s, PA_STREAM_TERMINATED);
297
298 return 0;
299}
300
301/** Write some data to the server (for playback sinks), if free_cb is
302 * non-NULL this routine is called when all data has been written out
303 * and an internal reference to the specified data is kept, the data
304 * is not copied. If NULL, the data is copied into an internal
305 * buffer. The client my freely seek around in the output buffer. For
306 * most applications passing 0 and PA_SEEK_RELATIVE as arguments for
307 * offset and seek should be useful.*/
308int pa_stream_write(
309        pa_stream *p             /**< The stream to use */,
310        const void *data         /**< The data to write */,
311        size_t length            /**< The length of the data to write */,
312        pa_free_cb_t free_cb     /**< A cleanup routine for the data or NULL to request an internal copy */,
313        int64_t offset,          /**< Offset for seeking, must be 0 for upload streams */
314        pa_seek_mode_t seek      /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */) {
315 struct roar_buffer * buf;
316 void               * bufdata;
317
318 // TODO: implement seeking in output buffer
319
320 if ( p == NULL )
321  return -1;
322
323 if ( offset != 0 || seek != PA_SEEK_RELATIVE )
324  return -1;
325
326 if ( data == NULL ) {
327  if ( length == 0 ) {
328   if ( free_cb != NULL )
329    free_cb(NULL);
330
331   return 0;
332  } else {
333   return -1;
334  }
335 }
336
337 // seems we have a valid write from here.
338
339 if ( roar_buffer_new(&buf, length) == -1 ) {
340  if ( free_cb != NULL )
341   free_cb((void*)data);
342
343  return -1;
344 }
345
346 if ( roar_buffer_get_data(buf, &bufdata) == -1 ) {
347  if ( free_cb != NULL )
348   free_cb((void*)data);
349
350  return -1;
351 }
352
353 memcpy(bufdata, data, length);
354 if ( free_cb != NULL )
355  free_cb((void*)data);
356
357 if ( p->iobuffer == NULL ) {
358  p->iobuffer = buf;
359 } else {
360  if ( roar_buffer_add(p->iobuffer, buf) == -1 )
361   return -1;
362 }
363
364 return 0;
365}
366
367/** Read the next fragment from the buffer (for recording).
368 * data will point to the actual data and length will contain the size
369 * of the data in bytes (which can be less than a complete framgnet).
370 * Use pa_stream_drop() to actually remove the data from the
371 * buffer. If no data is available will return a NULL pointer  \since 0.8 */
372int pa_stream_peek(
373        pa_stream *p                 /**< The stream to use */,
374        const void **data            /**< Pointer to pointer that will point to data */,
375        size_t *length              /**< The length of the data read */) {
376 if ( data == NULL || length == NULL )
377  return -1;
378
379 *data   = NULL;
380 *length = 0;
381
382 if ( p == NULL )
383  return -1;
384
385 if ( p->iobuffer == NULL )
386  return 0;
387
388 if ( roar_buffer_get_len(p->iobuffer, length) == -1 ) {
389  *length = 0;
390  return -1;
391 }
392
393 if ( roar_buffer_get_data(p->iobuffer, (void**)data) == -1 ) {
394  *length = 0;
395  *data   = NULL;
396  return -1;
397 }
398
399 return 0;
400}
401
402/** Remove the current fragment on record streams. It is invalid to do this without first
403 * calling pa_stream_peek(). \since 0.8 */
404int pa_stream_drop(pa_stream *p) {
405 if ( p == NULL )
406  return -1;
407
408 if ( p->iobuffer == NULL )
409  return -1;
410
411 return roar_buffer_next(&(p->iobuffer));
412}
413
414/** Return the nember of bytes that may be written using pa_stream_write() */
415size_t pa_stream_writable_size(pa_stream *p) {
416 struct roar_buffer_stats stats;
417
418 if ( p == NULL )
419  return 0;
420
421 if ( p->iobuffer == NULL )
422  return 0;
423
424 if ( roar_buffer_ring_stats(p->iobuffer, &stats) == -1 )
425  return 0;
426
427 if ( stats.parts > p->fragments.num )
428  return 0;
429
430 return (p->fragments.num - stats.parts)*p->fragments.size;
431}
432
433/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */
434size_t pa_stream_readable_size(pa_stream *p) {
435 struct roar_buffer_stats stats;
436
437 if ( p == NULL )
438  return 0;
439
440 if ( p->iobuffer == NULL )
441  return 0;
442
443 if ( roar_buffer_ring_stats(p->iobuffer, &stats) == -1 )
444  return 0;
445
446 return stats.bytes;
447}
448
449/** Drain a playback stream. Use this for notification when the buffer is empty */
450pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
451 if ( s == NULL )
452  return NULL;
453
454 s->cb.drain.cb.scb   = cb;
455 s->cb.drain.userdata = userdata;
456
457 if ( s->op.drain == NULL ) {
458  s->op.drain = roar_pa_operation_new(PA_OPERATION_RUNNING);
459 }
460
461 pa_operation_ref(s->op.drain);
462
463 return s->op.drain;
464}
465
466/** Request a timing info structure update for a stream. Use
467 * pa_stream_get_timing_info() to get access to the raw timing data,
468 * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned
469 * up values. */
470pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata);
471
472/** Set the callback function that is called whenever the state of the stream changes */
473void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
474 ROAR_DBG("pa_stream_set_state_callback(s=%p, cb=%p, userdata=%p) = ?", s, cb, userdata);
475
476 if ( s == NULL )
477  return;
478
479 s->cb.change_state.cb.ncb    = cb;
480 s->cb.change_state.userdata  = userdata;
481}
482
483void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
484 if ( s == NULL )
485  return;
486
487 ROAR_DBG("pa_stream_set_state(s=%p, st=%i): State: %i->%i", s, st, s->state, st);
488
489 s->state = st;
490
491 if ( s->cb.change_state.cb.ncb != NULL ) {
492  ROAR_DBG("pa_stream_set_state(s=%p, st=%i): calling callback at %p", s, st, s->cb.change_state.cb.ncb);
493  s->cb.change_state.cb.ncb(s, s->cb.change_state.userdata);
494 }
495 ROAR_DBG("pa_stream_set_state(s=%p, st=%i) = (void)", s, st);
496}
497
498/** Set the callback function that is called when new data may be
499 * written to the stream. */
500void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata) {
501 if ( p == NULL )
502  return;
503
504 p->cb.write.cb.rcb    = cb;
505 p->cb.write.userdata  = userdata;
506}
507
508/** Set the callback function that is called when new data is available from the stream.
509 * Return the number of bytes read. \since 0.8 */
510void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata) {
511 if ( p == NULL )
512  return;
513
514 p->cb.read.cb.rcb    = cb;
515 p->cb.read.userdata  = userdata;
516}
517
518/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */
519void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
520 if ( p == NULL )
521  return;
522
523 p->cb.overflow.cb.ncb    = cb;
524 p->cb.overflow.userdata  = userdata;
525}
526
527/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */
528void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
529 if ( p == NULL )
530  return;
531
532 p->cb.underflow.cb.ncb    = cb;
533 p->cb.underflow.userdata  = userdata;
534}
535
536/** 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 */
537void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
538 if ( p == NULL )
539  return;
540
541 p->cb.latency.cb.ncb    = cb;
542 p->cb.latency.userdata  = userdata;
543}
544
545/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */
546pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata);
547
548/** Flush the playback buffer of this stream. Most of the time you're
549 * better off using the parameter delta of pa_stream_write() instead of this
550 * function. Available on both playback and recording streams. \since 0.3 */
551pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
552/** Reenable prebuffering as specified in the pa_buffer_attr
553 * structure. Available for playback streams only. \since 0.6 */
554pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
555
556/** Request immediate start of playback on this stream. This disables
557 * prebuffering as specified in the pa_buffer_attr
558 * structure, temporarily. Available for playback streams only. \since 0.3 */
559pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
560
561/** Rename the stream. \since 0.5 */
562pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata);
563
564/** Return the current playback/recording time. This is based on the
565 * data in the timing info structure returned by
566 * pa_stream_get_timing_info(). This function will usually only return
567 * new data if a timing info update has been recieved. Only if timing
568 * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING)
569 * the data from the last timing update is used for an estimation of
570 * the current playback/recording time based on the local time that
571 * passed since the timing info structure has been acquired. The time
572 * value returned by this function is guaranteed to increase
573 * monotonically. (that means: the returned value is always greater or
574 * equal to the value returned on the last call) This behaviour can
575 * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be
576 * desirable to deal better with bad estimations of transport
577 * latencies, but may have strange effects if the application is not
578 * able to deal with time going 'backwards'. \since 0.6 */
579int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec);
580
581/** Return the total stream latency. This function is based on
582 * pa_stream_get_time(). In case the stream is a monitoring stream the
583 * result can be negative, i.e. the captured samples are not yet
584 * played. In this case *negative is set to 1. \since 0.6 */
585int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative);
586
587/** Return the latest raw timing data structure. The returned pointer
588 * points to an internal read-only instance of the timing
589 * structure. The user should make a copy of this structure if he
590 * wants to modify it. An in-place update to this data structure may
591 * be requested using pa_stream_update_timing_info(). If no
592 * pa_stream_update_timing_info() call was issued before, this
593 * function will fail with PA_ERR_NODATA. Please note that the
594 * write_index member field (and only this field) is updated on each
595 * pa_stream_write() call, not just when a timing update has been
596 * recieved. \since 0.8 */
597const pa_timing_info* pa_stream_get_timing_info(pa_stream *s);
598
599/** Return a pointer to the stream's sample specification. \since 0.6 */
600const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) {
601 if ( s == NULL )
602  return NULL;
603
604 return &(s->sspec);
605}
606
607/** Return a pointer to the stream's channel map. \since 0.8 */
608const pa_channel_map* pa_stream_get_channel_map(pa_stream *s);
609
610/** Return the buffer metrics of the stream. Only valid after the
611 * stream has been connected successfuly and if the server is at least
612 * PulseAudio 0.9. \since 0.9.0 */
613const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s);
614
615//ll
Note: See TracBrowser for help on using the repository browser.