source: roaraudio/libroarpulse/stream.c @ 3514:04b12826e5b8

Last change on this file since 3514:04b12826e5b8 was 3514:04b12826e5b8, checked in by phi, 14 years ago

wrote support to read data from stream

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