1 2/*** 3 This file is part of PulseAudio. 4 5 Copyright 2004-2006 Lennart Poettering 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <stdio.h> 26#include <string.h> 27#include <stdlib.h> 28 29#include <pulse/pulseaudio.h> 30#include <pulse/thread-mainloop.h> 31#include <pulse/xmalloc.h> 32 33#include <pulsecore/log.h> 34#include <pulsecore/macro.h> 35 36#include "simple.h" 37 38struct pa_simple { 39 pa_threaded_mainloop *mainloop; 40 pa_context *context; 41 pa_stream *stream; 42 pa_stream_direction_t direction; 43 44 const void *read_data; 45 size_t read_index, read_length; 46 47 int operation_success; 48}; 49 50#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) \ 51 do { \ 52 if (!(expression)) { \ 53 if (rerror) \ 54 *(rerror) = error; \ 55 return (ret); \ 56 } \ 57 } while(false); 58 59#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) \ 60 do { \ 61 if (!(expression)) { \ 62 if (rerror) \ 63 *(rerror) = pa_context_errno((p)->context); \ 64 goto label; \ 65 } \ 66 } while(false); 67 68#define CHECK_DEAD_GOTO(p, rerror, label) \ 69 do { \ 70 if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \ 71 !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \ 72 if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ 73 ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ 74 if (rerror) \ 75 *(rerror) = pa_context_errno((p)->context); \ 76 } else \ 77 if (rerror) \ 78 *(rerror) = PA_ERR_BADSTATE; \ 79 goto label; \ 80 } \ 81 } while(false); 82 83static void context_state_cb(pa_context *c, void *userdata) { 84 pa_simple *p = userdata; 85 pa_assert(c); 86 pa_assert(p); 87 88 switch (pa_context_get_state(c)) { 89 case PA_CONTEXT_READY: 90 case PA_CONTEXT_TERMINATED: 91 case PA_CONTEXT_FAILED: 92 pa_threaded_mainloop_signal(p->mainloop, 0); 93 break; 94 95 case PA_CONTEXT_UNCONNECTED: 96 case PA_CONTEXT_CONNECTING: 97 case PA_CONTEXT_AUTHORIZING: 98 case PA_CONTEXT_SETTING_NAME: 99 break; 100 } 101} 102 103static void stream_state_cb(pa_stream *s, void * userdata) { 104 pa_simple *p = userdata; 105 pa_assert(s); 106 pa_assert(p); 107 108 switch (pa_stream_get_state(s)) { 109 110 case PA_STREAM_READY: 111 case PA_STREAM_FAILED: 112 case PA_STREAM_TERMINATED: 113 pa_threaded_mainloop_signal(p->mainloop, 0); 114 break; 115 116 case PA_STREAM_UNCONNECTED: 117 case PA_STREAM_CREATING: 118 break; 119 } 120} 121 122static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { 123 pa_simple *p = userdata; 124 pa_assert(p); 125 126 pa_threaded_mainloop_signal(p->mainloop, 0); 127} 128 129static void stream_latency_update_cb(pa_stream *s, void *userdata) { 130 pa_simple *p = userdata; 131 132 pa_assert(p); 133 134 pa_threaded_mainloop_signal(p->mainloop, 0); 135} 136 137pa_simple* pa_simple_new( 138 const char *server, 139 const char *name, 140 pa_stream_direction_t dir, 141 const char *dev, 142 const char *stream_name, 143 const pa_sample_spec *ss, 144 const pa_channel_map *map, 145 const pa_buffer_attr *attr, 146 int *rerror) { 147 148 pa_simple *p; 149 int error = PA_ERR_INTERNAL, r; 150 151 CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); 152 CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); 153 CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); 154 CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); 155 CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) 156 157 p = pa_xnew0(pa_simple, 1); 158 p->direction = dir; 159 160 if (!(p->mainloop = pa_threaded_mainloop_new())) 161 goto fail; 162 163 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) 164 goto fail; 165 166 pa_context_set_state_callback(p->context, context_state_cb, p); 167 168 if (pa_context_connect(p->context, server, 0, NULL) < 0) { 169 error = pa_context_errno(p->context); 170 goto fail; 171 } 172 173 pa_threaded_mainloop_lock(p->mainloop); 174 175 if (pa_threaded_mainloop_start(p->mainloop) < 0) 176 goto unlock_and_fail; 177 178 for (;;) { 179 pa_context_state_t state; 180 181 state = pa_context_get_state(p->context); 182 183 if (state == PA_CONTEXT_READY) 184 break; 185 186 if (!PA_CONTEXT_IS_GOOD(state)) { 187 error = pa_context_errno(p->context); 188 goto unlock_and_fail; 189 } 190 191 /* Wait until the context is ready */ 192 pa_threaded_mainloop_wait(p->mainloop); 193 } 194 195 if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { 196 error = pa_context_errno(p->context); 197 goto unlock_and_fail; 198 } 199 200 pa_stream_set_state_callback(p->stream, stream_state_cb, p); 201 pa_stream_set_read_callback(p->stream, stream_request_cb, p); 202 pa_stream_set_write_callback(p->stream, stream_request_cb, p); 203 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); 204 205 if (dir == PA_STREAM_PLAYBACK) 206 r = pa_stream_connect_playback(p->stream, dev, attr, 207 PA_STREAM_INTERPOLATE_TIMING 208 |PA_STREAM_ADJUST_LATENCY 209 |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); 210 else 211 r = pa_stream_connect_record(p->stream, dev, attr, 212 PA_STREAM_INTERPOLATE_TIMING 213 |PA_STREAM_ADJUST_LATENCY 214 |PA_STREAM_AUTO_TIMING_UPDATE); 215 216 if (r < 0) { 217 error = pa_context_errno(p->context); 218 goto unlock_and_fail; 219 } 220 221 for (;;) { 222 pa_stream_state_t state; 223 224 state = pa_stream_get_state(p->stream); 225 226 if (state == PA_STREAM_READY) 227 break; 228 229 if (!PA_STREAM_IS_GOOD(state)) { 230 error = pa_context_errno(p->context); 231 goto unlock_and_fail; 232 } 233 234 /* Wait until the stream is ready */ 235 pa_threaded_mainloop_wait(p->mainloop); 236 } 237 238 pa_threaded_mainloop_unlock(p->mainloop); 239 240 return p; 241 242unlock_and_fail: 243 pa_threaded_mainloop_unlock(p->mainloop); 244 245fail: 246 if (rerror) 247 *rerror = error; 248 pa_simple_free(p); 249 return NULL; 250} 251 252void pa_simple_free(pa_simple *s) { 253 pa_assert(s); 254 255 if (s->mainloop) 256 pa_threaded_mainloop_stop(s->mainloop); 257 258 if (s->stream) 259 pa_stream_unref(s->stream); 260 261 if (s->context) { 262 pa_context_disconnect(s->context); 263 pa_context_unref(s->context); 264 } 265 266 if (s->mainloop) 267 pa_threaded_mainloop_free(s->mainloop); 268 269 pa_xfree(s); 270} 271 272int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { 273 pa_assert(p); 274 275 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); 276 CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); 277 CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); 278 279 pa_threaded_mainloop_lock(p->mainloop); 280 281 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 282 283 while (length > 0) { 284 size_t l; 285 int r; 286 287 while (!(l = pa_stream_writable_size(p->stream))) { 288 pa_threaded_mainloop_wait(p->mainloop); 289 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 290 } 291 292 CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); 293 294 if (l > length) 295 l = length; 296 297 r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); 298 CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); 299 300 data = (const uint8_t*) data + l; 301 length -= l; 302 } 303 304 pa_threaded_mainloop_unlock(p->mainloop); 305 return 0; 306 307unlock_and_fail: 308 pa_threaded_mainloop_unlock(p->mainloop); 309 return -1; 310} 311 312int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { 313 pa_assert(p); 314 315 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); 316 CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); 317 CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); 318 319 pa_threaded_mainloop_lock(p->mainloop); 320 321 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 322 323 while (length > 0) { 324 size_t l; 325 326 while (!p->read_data) { 327 int r; 328 329 r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); 330 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); 331 332 if (p->read_length <= 0) { 333 pa_threaded_mainloop_wait(p->mainloop); 334 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 335 } else if (!p->read_data) { 336 /* There's a hole in the stream, skip it. We could generate 337 * silence, but that wouldn't work for compressed streams. */ 338 r = pa_stream_drop(p->stream); 339 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); 340 } else 341 p->read_index = 0; 342 } 343 344 l = p->read_length < length ? p->read_length : length; 345 memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); 346 347 data = (uint8_t*) data + l; 348 length -= l; 349 350 p->read_index += l; 351 p->read_length -= l; 352 353 if (!p->read_length) { 354 int r; 355 356 r = pa_stream_drop(p->stream); 357 p->read_data = NULL; 358 p->read_length = 0; 359 p->read_index = 0; 360 361 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); 362 } 363 } 364 365 pa_threaded_mainloop_unlock(p->mainloop); 366 return 0; 367 368unlock_and_fail: 369 pa_threaded_mainloop_unlock(p->mainloop); 370 return -1; 371} 372 373static void success_cb(pa_stream *s, int success, void *userdata) { 374 pa_simple *p = userdata; 375 376 pa_assert(s); 377 pa_assert(p); 378 379 p->operation_success = success; 380 pa_threaded_mainloop_signal(p->mainloop, 0); 381} 382 383int pa_simple_drain(pa_simple *p, int *rerror) { 384 pa_operation *o = NULL; 385 386 pa_assert(p); 387 388 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); 389 390 pa_threaded_mainloop_lock(p->mainloop); 391 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 392 393 o = pa_stream_drain(p->stream, success_cb, p); 394 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); 395 396 p->operation_success = 0; 397 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { 398 pa_threaded_mainloop_wait(p->mainloop); 399 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 400 } 401 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); 402 403 pa_operation_unref(o); 404 pa_threaded_mainloop_unlock(p->mainloop); 405 406 return 0; 407 408unlock_and_fail: 409 410 if (o) { 411 pa_operation_cancel(o); 412 pa_operation_unref(o); 413 } 414 415 pa_threaded_mainloop_unlock(p->mainloop); 416 return -1; 417} 418 419int pa_simple_flush(pa_simple *p, int *rerror) { 420 pa_operation *o = NULL; 421 422 pa_assert(p); 423 424 pa_threaded_mainloop_lock(p->mainloop); 425 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 426 427 o = pa_stream_flush(p->stream, success_cb, p); 428 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); 429 430 p->operation_success = 0; 431 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { 432 pa_threaded_mainloop_wait(p->mainloop); 433 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 434 } 435 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); 436 437 pa_operation_unref(o); 438 pa_threaded_mainloop_unlock(p->mainloop); 439 440 return 0; 441 442unlock_and_fail: 443 444 if (o) { 445 pa_operation_cancel(o); 446 pa_operation_unref(o); 447 } 448 449 pa_threaded_mainloop_unlock(p->mainloop); 450 return -1; 451} 452 453pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { 454 pa_usec_t t; 455 456 pa_assert(p); 457 458 pa_threaded_mainloop_lock(p->mainloop); 459 460 for (;;) { 461 int negative; 462 463 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 464 465 if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) { 466 if (p->direction == PA_STREAM_RECORD) { 467 pa_usec_t already_read; 468 469 /* pa_simple_read() calls pa_stream_peek() to get the next 470 * chunk of audio. If the next chunk is larger than what the 471 * pa_simple_read() caller wanted, the leftover data is stored 472 * in p->read_data until pa_simple_read() is called again. 473 * pa_stream_drop() won't be called until the whole chunk has 474 * been consumed, which means that pa_stream_get_latency() will 475 * return too large values, because the whole size of the 476 * partially read chunk is included in the latency. Therefore, 477 * we need to subtract the already-read amount from the 478 * latency. */ 479 already_read = pa_bytes_to_usec(p->read_index, pa_stream_get_sample_spec(p->stream)); 480 481 if (!negative) { 482 if (t > already_read) 483 t -= already_read; 484 else 485 t = 0; 486 } 487 } 488 489 /* We don't have a way to report negative latencies from 490 * pa_simple_get_latency(). If the latency is negative, let's 491 * report zero. */ 492 if (negative) 493 t = 0; 494 495 break; 496 } 497 498 CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); 499 500 /* Wait until latency data is available again */ 501 pa_threaded_mainloop_wait(p->mainloop); 502 } 503 504 pa_threaded_mainloop_unlock(p->mainloop); 505 506 return t; 507 508unlock_and_fail: 509 510 pa_threaded_mainloop_unlock(p->mainloop); 511 return (pa_usec_t) -1; 512} 513