source: roaraudio/libroarpulse/stream.c @ 5509:cd1927035f25

Last change on this file since 5509:cd1927035f25 was 5509:cd1927035f25, checked in by phi, 12 years ago

ported some more functions

File size: 25.7 KB
Line 
1//stream.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
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, 51 Franklin Street, Fifth Floor,
26 *  Boston, MA 02110-1301, USA.
27 *
28 *  NOTE for everyone want's to change something and send patches:
29 *  read README and HACKING! There a addition information on
30 *  the license of this document you need to read before you send
31 *  any patches.
32 *
33 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
34 *  or libpulse*:
35 *  The libs libroaresd, libroararts and libroarpulse link this libroar
36 *  and are therefore GPL. Because of this it may be illigal to use
37 *  them with any software that uses libesd, libartsc or libpulse*.
38 */
39
40#include <libroarpulse/libroarpulse.h>
41
42struct _roar_pa_stream_cb {
43 union {
44  pa_stream_notify_cb_t  ncb;
45  pa_stream_request_cb_t rcb;
46  pa_stream_success_cb_t scb;
47 } cb;
48 void * userdata;
49};
50
51struct pa_stream {
52 size_t                  refc;
53 pa_context            * c;
54 struct roar_vio_calls   vio;
55 struct roar_stream      stream;
56 pa_stream_state_t       state;
57 pa_sample_spec          sspec;
58 pa_io_event           * io_event;
59 pa_timing_info          timinginfo;
60 pa_buffer_attr          bufattr;
61 pa_stream_direction_t   dir;
62 struct roar_buffer    * iobuffer;
63 struct {
64  size_t size;
65  size_t num;
66 } fragments;
67 struct {
68  struct _roar_pa_stream_cb change_state;
69  struct _roar_pa_stream_cb write;
70  struct _roar_pa_stream_cb read;
71  struct _roar_pa_stream_cb overflow;
72  struct _roar_pa_stream_cb underflow;
73  struct _roar_pa_stream_cb latency;
74  struct _roar_pa_stream_cb drain;
75 } cb;
76 struct {
77  pa_operation * drain;
78 } op;
79};
80
81typedef struct pa_proplist pa_proplist;
82void pa_stream_set_state(pa_stream *s, pa_stream_state_t st);
83
84pa_stream* pa_stream_new_with_proplist(
85        pa_context *c                     ,
86        const char *name                  ,
87        const pa_sample_spec *ss          ,
88        const pa_channel_map *map         ,
89        pa_proplist *p                    );
90
91/** Create a new, unconnected stream with the specified name and sample type */
92pa_stream* pa_stream_new(
93        pa_context *c                     /**< The context to create this stream in */,
94        const char *name                  /**< A name for this stream */,
95        const pa_sample_spec *ss          /**< The desired sample format */,
96        const pa_channel_map *map         /**< The desired channel map, or NULL for default */) {
97 return pa_stream_new_with_proplist(c, name, ss, map, NULL);
98}
99
100pa_stream* pa_stream_new_with_proplist(
101        pa_context *c                     ,
102        const char *name                  ,
103        const pa_sample_spec *ss          ,
104        const pa_channel_map *map         ,
105        pa_proplist *p                    ) {
106 pa_stream * s;
107
108 ROAR_DBG("pa_stream_new_with_proplist(c=%p, name='%s', ss=%p, map=%p, p=%p) = ?", c, name, ss, map, p);
109
110 if ( p != NULL )
111  return NULL;
112
113 if ( (s = roar_mm_malloc(sizeof(pa_stream))) == NULL )
114  return NULL;
115
116 memset(s, 0, sizeof(pa_stream));
117
118 memcpy(&(s->sspec), ss, sizeof(pa_sample_spec));
119
120 ROAR_DBG("pa_stream_new_with_proplist(c=%p, name='%s', ss=%p, map=%p, p=%p) = ?", c, name, ss, map, p);
121
122 s->fragments.num  = 4;
123 s->fragments.size = 2048;
124
125 s->state = PA_STREAM_UNCONNECTED;
126 s->c     = c;
127 pa_context_ref(c);
128
129 ROAR_DBG("pa_stream_new_with_proplist(c=%p, name='%s', ss=%p, map=%p, p=%p) = ?", c, name, ss, map, p);
130
131 return s;
132}
133
134static void _pa_stream_free(pa_stream * s) {
135 pa_stream_disconnect(s);
136 pa_context_unref(s->c);
137 roar_mm_free(s);
138}
139
140/** Decrease the reference counter by one */
141void pa_stream_unref(pa_stream *s) {
142 if ( s == NULL )
143  return;
144
145 s->refc--;
146
147 if (s->refc < 1 )
148  _pa_stream_free(s);
149}
150
151/** Increase the reference counter by one */
152pa_stream *pa_stream_ref(pa_stream *s) {
153 if ( s == NULL )
154  return NULL;
155
156 s->refc++;
157
158 return s;
159}
160
161/** Return the current state of the stream */
162pa_stream_state_t pa_stream_get_state(pa_stream *p) {
163 if ( p == NULL )
164  return PA_STREAM_FAILED;
165
166 return p->state;
167}
168
169/** Return the context this stream is attached to */
170pa_context* pa_stream_get_context(pa_stream *p) {
171 if ( p == NULL )
172  return NULL;
173
174 return p->c;
175}
176
177/** Return the device (sink input or source output) index this stream is connected to */
178uint32_t pa_stream_get_index(pa_stream *s) {
179 struct roar_stream_info info;
180
181 if ( roar_stream_get_info(roar_pa_context_get_con(s->c), &(s->stream), &info) == -1 )
182  return 0;
183
184 if ( info.mixer == -1 )
185  return 0;
186
187 return info.mixer;
188}
189
190static void _roar_pa_stream_ioecb(pa_mainloop_api     * ea,
191                                  pa_io_event         * e,
192                                  int                   fd,
193                                  pa_io_event_flags_t   events,
194                                  void                * userdata) {
195 struct roar_buffer * buf;
196 pa_stream * s = userdata;
197 void * data;
198 size_t len;
199 ssize_t ret;
200 int bufret;
201
202 (void)fd, (void)events;
203
204 ROAR_DBG("_roar_pa_stream_ioecb(*) = ?");
205
206 switch (s->dir) {
207  case PA_STREAM_PLAYBACK:
208    if ( s->iobuffer != NULL ) {
209     if ( roar_buffer_get_data(s->iobuffer, &data) == -1 )
210      return;
211
212     if ( roar_buffer_get_len(s->iobuffer, &len) == -1 )
213      return;
214
215     if ( (ret = roar_vio_write(&(s->vio), data, len)) == -1 )
216      return;
217
218     ROAR_DBG("_roar_pa_stream_ioecb(*): vio write() = %lli", (long long int) ret);
219
220     // TODO: handle errors
221     if ( ret == (ssize_t)len ) {
222      bufret = roar_buffer_next(&(s->iobuffer));
223     } else {
224      bufret = roar_buffer_set_offset(s->iobuffer, ret);
225     }
226     if ( bufret == -1 ) {
227      ROAR_WARN("_roar_pa_stream_ioecb(*): Altering buffer after write failed. Bad.");
228      return;
229     }
230    }
231
232    if ( s->iobuffer == NULL ) {
233     ROAR_DBG("_roar_pa_stream_ioecb(*): disable IO events");
234     ea->io_enable(e, PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR);
235
236     if ( s->cb.write.cb.rcb != NULL )
237      s->cb.write.cb.rcb(s, pa_stream_writable_size(s), s->cb.write.userdata);
238
239     if ( s->cb.drain.cb.scb != NULL )
240      s->cb.drain.cb.scb(s, 1, s->cb.drain.userdata);
241    }
242   break;
243  case PA_STREAM_RECORD:
244    if ( roar_buffer_new_data(&buf, s->fragments.size, &data) == -1 )
245     return;
246
247    if ( (ret = roar_vio_read(&(s->vio), data, s->fragments.size)) < 1 ) {
248     roar_buffer_free(buf);
249     return;
250    }
251
252    if ( roar_buffer_set_len(buf, ret) == -1 ) { // bad error
253     roar_buffer_free(buf);
254     return;
255    }
256
257    if ( s->iobuffer == NULL ) {
258     s->iobuffer = buf;
259    } else {
260     if ( roar_buffer_moveinto(s->iobuffer, &buf) == -1 ) {
261      roar_buffer_free(buf);
262      return;
263     }
264    }
265
266    if ( s->cb.read.cb.rcb != NULL )
267     s->cb.read.cb.rcb(s, pa_stream_readable_size(s), s->cb.read.userdata);
268   break;
269  default:
270   return;
271 }
272
273 ROAR_DBG("_roar_pa_stream_ioecb(*) = (void)");
274}
275
276static int _roar_pa_stream_open (pa_stream *s,
277                                 const char *dev,
278                                 const pa_buffer_attr *attr,
279                                 pa_stream_flags_t flags,
280                                 pa_cvolume *volume,
281                                 pa_stream *sync_stream,
282                                 pa_stream_direction_t dir) {
283 struct roar_connection * con;
284 pa_mainloop_api * api;
285 pa_io_event_flags_t event_flags = PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR;
286 int fh;
287 int ctl = -1;
288
289 ROAR_DBG("_roar_pa_stream_open(s=%p, dev='%s', attr=%p, flags=%i, volume=%p, sync_stream=%p, dir=%i) = ?", s, dev, attr, flags, volume, sync_stream, dir);
290
291 if ( s == NULL )
292  return -1;
293
294 volume = NULL;
295
296 if ( dev != NULL || attr != NULL || flags != 0 || volume != NULL || sync_stream != NULL ) {
297  pa_stream_set_state(s, PA_STREAM_FAILED);
298  return -1;
299 }
300
301 if ( (con = roar_pa_context_get_con(s->c)) == NULL ) {
302  pa_stream_set_state(s, PA_STREAM_FAILED);
303  return -1;
304 }
305
306 s->dir = dir;
307
308 switch (dir) {
309  case PA_STREAM_PLAYBACK:
310    s->stream.dir = ROAR_DIR_PLAY;
311    ctl           = ROAR_VIO_CTL_GET_SELECT_WRITE_FH;
312    event_flags  |= PA_IO_EVENT_OUTPUT;
313   break;
314  case PA_STREAM_RECORD:
315    s->stream.dir = ROAR_DIR_RECORD;
316    ctl           = ROAR_VIO_CTL_GET_SELECT_READ_FH;
317    event_flags  |= PA_IO_EVENT_INPUT;
318   break;
319  default:
320    pa_stream_set_state(s, PA_STREAM_FAILED);
321    return -1;
322   break;
323 }
324
325 if ( roar_pa_sspec2auinfo(&(s->stream.info), &(s->sspec)) == -1 ) {
326  pa_stream_set_state(s, PA_STREAM_FAILED);
327  return -1;
328 }
329
330 if ( roar_vio_simple_new_stream_obj(&(s->vio), con, &(s->stream),
331                                     s->stream.info.rate, s->stream.info.channels,
332                                     s->stream.info.bits, s->stream.info.codec,
333                                     s->stream.dir, -1 /* TODO: FIXME: set to requested mixer */ ) == -1 ) {
334  pa_stream_set_state(s, PA_STREAM_FAILED);
335  return -1;
336 }
337
338 api = roar_pa_context_get_api(s->c);
339
340 if ( api != NULL && api->io_new != NULL ) {
341  if ( roar_vio_ctl(&(s->vio), ctl, &fh) != -1 ) {
342   s->io_event = api->io_new(api, fh, event_flags, _roar_pa_stream_ioecb, s);
343  }
344 }
345
346 // TODO: update s->fragments.
347
348 s->bufattr.maxlength = s->fragments.size * s->fragments.num;
349 s->bufattr.tlength   = s->fragments.size;
350 s->bufattr.prebuf    = 0;
351 s->bufattr.minreq    = 1;
352 s->bufattr.fragsize  = s->fragments.size;
353
354 pa_stream_set_state(s, PA_STREAM_READY);
355
356 return 0;
357}
358
359/** Connect the stream to a sink */
360int pa_stream_connect_playback(
361        pa_stream *s                  /**< The stream to connect to a sink */,
362        const char *dev               /**< Name of the sink to connect to, or NULL for default */ ,
363        const pa_buffer_attr *attr    /**< Buffering attributes, or NULL for default */,
364        pa_stream_flags_t flags       /**< Additional flags, or 0 for default */,
365        ROAR_HAVE_ARG_VOLUME_OF_PA_STREAM_CONNECT_PLAYBACK volume            /**< Initial volume, or NULL for default */,
366        pa_stream *sync_stream        /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/) {
367 return _roar_pa_stream_open(s, dev, attr, flags, (pa_cvolume*)volume, sync_stream, PA_STREAM_PLAYBACK);
368}
369
370/** Connect the stream to a source */
371int pa_stream_connect_record(
372        pa_stream *s                  /**< The stream to connect to a source */ ,
373        const char *dev               /**< Name of the source to connect to, or NULL for default */,
374        const pa_buffer_attr *attr    /**< Buffer attributes, or NULL for default */,
375        pa_stream_flags_t flags       /**< Additional flags, or 0 for default */) {
376 return _roar_pa_stream_open(s, dev, attr, flags, NULL, NULL, PA_STREAM_RECORD);
377}
378
379/** Disconnect a stream from a source/sink */
380int pa_stream_disconnect(pa_stream *s) {
381 pa_mainloop_api * api;
382
383 if ( s == NULL )
384  return -1;
385
386 if ( s->state != PA_STREAM_READY )
387  return -1;
388
389 if ( s->io_event != NULL ) {
390  api = roar_pa_context_get_api(s->c);
391
392  if ( api != NULL && api->io_free != NULL ) {
393   api->io_free(s->io_event);
394   s->io_event = NULL;
395  }
396 }
397
398 roar_vio_close(&(s->vio));
399
400 pa_stream_set_state(s, PA_STREAM_TERMINATED);
401
402 return 0;
403}
404
405/** Write some data to the server (for playback sinks), if free_cb is
406 * non-NULL this routine is called when all data has been written out
407 * and an internal reference to the specified data is kept, the data
408 * is not copied. If NULL, the data is copied into an internal
409 * buffer. The client my freely seek around in the output buffer. For
410 * most applications passing 0 and PA_SEEK_RELATIVE as arguments for
411 * offset and seek should be useful.*/
412int pa_stream_write(
413        pa_stream *p             /**< The stream to use */,
414        const void *data         /**< The data to write */,
415        size_t length            /**< The length of the data to write */,
416        pa_free_cb_t free_cb     /**< A cleanup routine for the data or NULL to request an internal copy */,
417        int64_t offset,          /**< Offset for seeking, must be 0 for upload streams */
418        pa_seek_mode_t seek      /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */) {
419 pa_mainloop_api    * api;
420 struct roar_buffer * buf;
421 void               * bufdata;
422
423 ROAR_DBG("pa_stream_write(p=%p, data=%p, length=%llu, free_cb=%p, offset=%lli, seek=%i) = ?", p, data, (long long unsigned int) length, free_cb, offset, seek);
424
425 // TODO: implement seeking in output buffer
426
427 if ( p == NULL )
428  return -1;
429
430 if ( offset != 0 || seek != PA_SEEK_RELATIVE )
431  return -1;
432
433 if ( data == NULL ) {
434  if ( length == 0 ) {
435   if ( free_cb != NULL )
436    free_cb(NULL);
437
438   return 0;
439  } else {
440   return -1;
441  }
442 }
443
444 // seems we have a valid write from here.
445
446 if ( roar_buffer_new_data(&buf, length, &bufdata) == -1 ) {
447  if ( free_cb != NULL )
448   free_cb((void*)data);
449
450  return -1;
451 }
452
453 memcpy(bufdata, data, length);
454 if ( free_cb != NULL )
455  free_cb((void*)data);
456
457 if ( p->iobuffer == NULL ) {
458  p->iobuffer = buf;
459 } else {
460  if ( roar_buffer_moveinto(p->iobuffer, &buf) == -1 ) {
461   roar_buffer_free(buf);
462   return -1;
463  }
464 }
465
466 if ( p->io_event != NULL ) {
467  api = roar_pa_context_get_api(p->c);
468  if ( api != NULL ) {
469   ROAR_DBG("pa_stream_write(*): enable IO events");
470   api->io_enable(p->io_event, PA_IO_EVENT_OUTPUT|PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR);
471  }
472 }
473
474 ROAR_DBG("pa_stream_write(p=%p, data=%p, length=%llu, free_cb=%p, offset=%lli, seek=%i) = 0", p, data, (long long unsigned int) length, free_cb, offset, seek);
475 return 0;
476}
477
478/** Read the next fragment from the buffer (for recording).
479 * data will point to the actual data and length will contain the size
480 * of the data in bytes (which can be less than a complete framgnet).
481 * Use pa_stream_drop() to actually remove the data from the
482 * buffer. If no data is available will return a NULL pointer  \since 0.8 */
483int pa_stream_peek(
484        pa_stream *p                 /**< The stream to use */,
485        const void **data            /**< Pointer to pointer that will point to data */,
486        size_t *length              /**< The length of the data read */) {
487 if ( data == NULL || length == NULL )
488  return -1;
489
490 *data   = NULL;
491 *length = 0;
492
493 if ( p == NULL )
494  return -1;
495
496 if ( p->iobuffer == NULL )
497  return 0;
498
499 if ( roar_buffer_get_len(p->iobuffer, length) == -1 ) {
500  *length = 0;
501  return -1;
502 }
503
504 if ( roar_buffer_get_data(p->iobuffer, (void**)data) == -1 ) {
505  *length = 0;
506  *data   = NULL;
507  return -1;
508 }
509
510 return 0;
511}
512
513/** Remove the current fragment on record streams. It is invalid to do this without first
514 * calling pa_stream_peek(). \since 0.8 */
515int pa_stream_drop(pa_stream *p) {
516 if ( p == NULL )
517  return -1;
518
519 if ( p->iobuffer == NULL )
520  return -1;
521
522 return roar_buffer_next(&(p->iobuffer));
523}
524
525/** Return the nember of bytes that may be written using pa_stream_write() */
526size_t pa_stream_writable_size(pa_stream *p) {
527 struct roar_buffer_stats stats;
528
529 ROAR_DBG("pa_stream_writable_size(p=%p) = ?", p);
530
531 if ( p == NULL ) {
532  ROAR_DBG("pa_stream_writable_size(p=%p) = 0", p);
533  return 0;
534 }
535
536 if ( p->iobuffer == NULL ) {
537  ROAR_DBG("pa_stream_writable_size(p=%p) = %llu", p, (long long unsigned)(p->fragments.num*p->fragments.size));
538  return p->fragments.num * p->fragments.size / 2;
539 }
540
541 if ( roar_buffer_ring_stats(p->iobuffer, &stats) == -1 ) {
542  ROAR_DBG("pa_stream_writable_size(p=%p) = 0", p);
543  return 0;
544 }
545
546 ROAR_DBG("pa_stream_writable_size(p=%p): stats={.parts=%i, .bytes=%i, ...}", p, stats.parts, stats.bytes);
547
548 if ( stats.parts > p->fragments.num ) {
549  ROAR_DBG("pa_stream_writable_size(p=%p) = 0", p);
550  return 0;
551 }
552
553 if ( stats.parts > (p->fragments.num/2) )
554  stats.parts = p->fragments.num / 2;
555
556 ROAR_DBG("pa_stream_writable_size(p=%p) = %llu", p, (long long unsigned)((p->fragments.num - stats.parts)*p->fragments.size));
557 return (p->fragments.num - stats.parts)*p->fragments.size;
558}
559
560/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */
561size_t pa_stream_readable_size(pa_stream *p) {
562 struct roar_buffer_stats stats;
563
564 if ( p == NULL )
565  return 0;
566
567 if ( p->iobuffer == NULL )
568  return 0;
569
570 if ( roar_buffer_ring_stats(p->iobuffer, &stats) == -1 )
571  return 0;
572
573 return stats.bytes;
574}
575
576/** Drain a playback stream. Use this for notification when the buffer is empty */
577pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
578 if ( s == NULL )
579  return NULL;
580
581 s->cb.drain.cb.scb   = cb;
582 s->cb.drain.userdata = userdata;
583
584 if ( s->op.drain == NULL ) {
585  s->op.drain = roar_pa_operation_new(PA_OPERATION_RUNNING);
586 }
587
588 pa_operation_ref(s->op.drain);
589
590 return s->op.drain;
591}
592
593/** Request a timing info structure update for a stream. Use
594 * pa_stream_get_timing_info() to get access to the raw timing data,
595 * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned
596 * up values. */
597pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata) {
598 int suc = 1;
599
600 if ( p == NULL )
601  return NULL;
602
603 if ( roar_get_stream(roar_pa_context_get_con(p->c), &(p->stream), p->stream.id) == -1 ) {
604  suc = 0;
605 }
606
607 // p->timinginfo
608 pa_gettimeofday(&(p->timinginfo.timestamp)); // we should interpolate between time before call and after
609
610 p->timinginfo.synchronized_clocks    = 0;
611 p->timinginfo.sink_usec              = 0;
612 p->timinginfo.source_usec            = 0;
613 p->timinginfo.transport_usec         = 0;
614 p->timinginfo.playing                = p->iobuffer != NULL;
615 p->timinginfo.write_index_corrupt    = 1;
616 p->timinginfo.write_index            = p->stream.pos * pa_frame_size(&(p->sspec));
617 p->timinginfo.read_index_corrupt     = 1;
618 p->timinginfo.read_index             = p->stream.pos * pa_frame_size(&(p->sspec));
619#if 0 /* newer versions */
620 p->timinginfo.configured_sink_usec   = p->timinginfo.sink_usec;
621 p->timinginfo.configured_source_usec = p->timinginfo.source_usec;
622 p->timinginfo.since_underrun         = 0;
623#endif
624
625 if ( cb != NULL ) {
626  cb(p, suc, userdata);
627 }
628
629 return roar_pa_op_new_done();
630}
631
632/** Set the callback function that is called whenever the state of the stream changes */
633void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
634 ROAR_DBG("pa_stream_set_state_callback(s=%p, cb=%p, userdata=%p) = ?", s, cb, userdata);
635
636 if ( s == NULL )
637  return;
638
639 s->cb.change_state.cb.ncb    = cb;
640 s->cb.change_state.userdata  = userdata;
641}
642
643void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
644 if ( s == NULL )
645  return;
646
647 ROAR_DBG("pa_stream_set_state(s=%p, st=%i): State: %i->%i", s, st, s->state, st);
648
649 s->state = st;
650
651 if ( s->cb.change_state.cb.ncb != NULL ) {
652  ROAR_DBG("pa_stream_set_state(s=%p, st=%i): calling callback at %p", s, st, s->cb.change_state.cb.ncb);
653  s->cb.change_state.cb.ncb(s, s->cb.change_state.userdata);
654 }
655 ROAR_DBG("pa_stream_set_state(s=%p, st=%i) = (void)", s, st);
656}
657
658/** Set the callback function that is called when new data may be
659 * written to the stream. */
660void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata) {
661 if ( p == NULL )
662  return;
663
664 p->cb.write.cb.rcb    = cb;
665 p->cb.write.userdata  = userdata;
666}
667
668/** Set the callback function that is called when new data is available from the stream.
669 * Return the number of bytes read. \since 0.8 */
670void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata) {
671 if ( p == NULL )
672  return;
673
674 p->cb.read.cb.rcb    = cb;
675 p->cb.read.userdata  = userdata;
676}
677
678/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */
679void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
680 if ( p == NULL )
681  return;
682
683 p->cb.overflow.cb.ncb    = cb;
684 p->cb.overflow.userdata  = userdata;
685}
686
687/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */
688void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
689 if ( p == NULL )
690  return;
691
692 p->cb.underflow.cb.ncb    = cb;
693 p->cb.underflow.userdata  = userdata;
694}
695
696/** 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 */
697void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata) {
698 if ( p == NULL )
699  return;
700
701 p->cb.latency.cb.ncb    = cb;
702 p->cb.latency.userdata  = userdata;
703}
704
705/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */
706pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) {
707 int action = b ? ROAR_SET_FLAG : ROAR_RESET_FLAG;
708
709 if ( roar_stream_set_flags(roar_pa_context_get_con(s->c), &(s->stream), ROAR_FLAG_PAUSE, action) == -1 ) {
710  cb(s, 0, userdata);
711 } else {
712  cb(s, 1, userdata);
713 }
714
715 return roar_pa_operation_new(PA_OPERATION_DONE);
716}
717
718/** Return 1 if the this stream has been corked. This will return 0 if
719 * not, and negative on error. \since 0.9.11 */
720int pa_stream_is_corked(pa_stream *s) {
721 struct roar_stream_info info;
722
723 if ( roar_stream_get_info(roar_pa_context_get_con(s->c), &(s->stream), &info) == -1 )
724  return -1;
725
726 return (info.flags & ROAR_FLAG_PAUSE) ? 1 : 0;
727}
728
729/** Flush the playback buffer of this stream. Most of the time you're
730 * better off using the parameter delta of pa_stream_write() instead of this
731 * function. Available on both playback and recording streams. \since 0.3 */
732pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
733 return pa_stream_drain(s, cb, userdata); // where is the differance to drain?
734}
735/** Reenable prebuffering as specified in the pa_buffer_attr
736 * structure. Available for playback streams only. \since 0.6 */
737pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
738
739/** Request immediate start of playback on this stream. This disables
740 * prebuffering as specified in the pa_buffer_attr
741 * structure, temporarily. Available for playback streams only. \since 0.3 */
742pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
743
744/** Rename the stream. \since 0.5 */
745pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata);
746
747/** Return the current playback/recording time. This is based on the
748 * data in the timing info structure returned by
749 * pa_stream_get_timing_info(). This function will usually only return
750 * new data if a timing info update has been recieved. Only if timing
751 * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING)
752 * the data from the last timing update is used for an estimation of
753 * the current playback/recording time based on the local time that
754 * passed since the timing info structure has been acquired. The time
755 * value returned by this function is guaranteed to increase
756 * monotonically. (that means: the returned value is always greater or
757 * equal to the value returned on the last call) This behaviour can
758 * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be
759 * desirable to deal better with bad estimations of transport
760 * latencies, but may have strange effects if the application is not
761 * able to deal with time going 'backwards'. \since 0.6 */
762int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) {
763 if ( s == NULL || r_usec == NULL )
764  return -1;
765
766 *r_usec = s->stream.pos * 1000000 / s->stream.info.rate / s->stream.info.channels;
767
768 return 0;
769}
770
771/** Return the total stream latency. This function is based on
772 * pa_stream_get_time(). In case the stream is a monitoring stream the
773 * result can be negative, i.e. the captured samples are not yet
774 * played. In this case *negative is set to 1. \since 0.6 */
775int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) {
776 // TODO: Fix this:
777 // sinks: lateny of stream, mixer, output...
778 // sources: mixer, output, negative
779
780 if ( r_usec != NULL )
781  *r_usec = 0;
782
783 if ( negative != NULL )
784  *negative = 0;
785
786 return 0;
787}
788
789/** Return the latest raw timing data structure. The returned pointer
790 * points to an internal read-only instance of the timing
791 * structure. The user should make a copy of this structure if he
792 * wants to modify it. An in-place update to this data structure may
793 * be requested using pa_stream_update_timing_info(). If no
794 * pa_stream_update_timing_info() call was issued before, this
795 * function will fail with PA_ERR_NODATA. Please note that the
796 * write_index member field (and only this field) is updated on each
797 * pa_stream_write() call, not just when a timing update has been
798 * recieved. \since 0.8 */
799const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) {
800 if ( s == NULL )
801  return NULL;
802
803 return &(s->timinginfo);
804}
805
806/** Return a pointer to the stream's sample specification. \since 0.6 */
807const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) {
808 if ( s == NULL )
809  return NULL;
810
811 return &(s->sspec);
812}
813
814/** Return a pointer to the stream's channel map. \since 0.8 */
815const pa_channel_map* pa_stream_get_channel_map(pa_stream *s);
816
817/** Return the buffer metrics of the stream. Only valid after the
818 * stream has been connected successfuly and if the server is at least
819 * PulseAudio 0.9. \since 0.9.0 */
820const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) {
821 if ( s == NULL )
822  return NULL;
823
824 return &(s->bufattr);
825}
826
827//ll
Note: See TracBrowser for help on using the repository browser.