source: roaraudio/libroarpulse/stream.c @ 3439:83fb987c6017

Last change on this file since 3439:83fb987c6017 was 3439:83fb987c6017, checked in by phi, 14 years ago

registzer IO event, still need callback

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