/native/external/espeak/src/wave_pulse.cpp
C++ | 935 lines | 586 code | 224 blank | 125 comment | 83 complexity | dc1eddd858e0db1caceb7bef36c35ce8 MD5 | raw file
1/*************************************************************************** 2 * Copyright (C) 2007, Gilles Casse <gcasse@oralux.org> * 3 * eSpeak driver for PulseAudio * 4 * based on the XMMS PulseAudio Plugin * 5 * * 6 * This program is free software; you can redistribute it and/or modify * 7 * it under the terms of the GNU General Public License as published by * 8 * the Free Software Foundation; either version 3 of the License, or * 9 * (at your option) any later version. * 10 * * 11 * This program is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 * GNU General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU General Public License * 17 * along with this program; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 20 ***************************************************************************/ 21// TBD: 22// * ARCH_BIG 23// * uint64? a_timing_info.read_index 24// * prebuf,... size? 25// * 0.9.6: pb pulse_free using tlength=8820 (max size never returned -> tlength=10000 ok, but higher drain). 26// 27#include "speech.h" 28 29#ifdef USE_ASYNC 30// This source file is only used for asynchronious modes 31 32#include <stdio.h> 33#include <string.h> 34#include <stdlib.h> 35#include <math.h> 36#include <assert.h> 37#include <sys/time.h> 38#include <time.h> 39#include <pulse/pulseaudio.h> 40#include <pthread.h> 41 42#ifndef PLATFORM_WINDOWS 43#include <unistd.h> 44#endif 45#include "wave.h" 46#include "debug.h" 47 48//<Definitions 49 50enum {ONE_BILLION=1000000000}; 51 52enum { 53// /* 100ms. 54// If a greater value is set (several seconds), 55// please update _pulse_timeout_start accordingly */ 56// PULSE_TIMEOUT_IN_USEC = 100000, 57 58 /* return value */ 59 PULSE_OK = 0, 60 PULSE_ERROR = -1, 61 PULSE_NO_CONNECTION = -2 62}; 63 64#ifdef USE_PULSEAUDIO 65 66static t_wave_callback* my_callback_is_output_enabled=NULL; 67 68#define SAMPLE_RATE 22050 69#define ESPEAK_FORMAT PA_SAMPLE_S16LE 70#define ESPEAK_CHANNEL 1 71 72#define MAXLENGTH 132300 73#define TLENGTH 4410 74#define PREBUF 2200 75#define MINREQ 880 76#define FRAGSIZE 0 77 78static pthread_mutex_t pulse_mutex; 79 80static pa_context *context = NULL; 81static pa_stream *stream = NULL; 82static pa_threaded_mainloop *mainloop = NULL; 83 84static pa_cvolume volume; 85static int volume_valid = 0; 86 87static int do_trigger = 0; 88static uint64_t written = 0; 89static int time_offset_msec = 0; 90static int just_flushed = 0; 91 92static int connected = 0; 93 94#define CHECK_DEAD_GOTO(label, warn) do { \ 95if (!mainloop || \ 96 !context || pa_context_get_state(context) != PA_CONTEXT_READY || \ 97 !stream || pa_stream_get_state(stream) != PA_STREAM_READY) { \ 98 if (warn) \ 99 SHOW("Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "NULL"); \ 100 goto label; \ 101 } \ 102} while(0); 103 104#define CHECK_CONNECTED(retval) \ 105do { \ 106 if (!connected) return retval; \ 107} while (0); 108 109#define CHECK_CONNECTED_NO_RETVAL(id) \ 110 do { \ 111 if (!connected){ SHOW("CHECK_CONNECTED_NO_RETVAL: !pulse_connected\n", ""); return; } \ 112 } while (0); 113 114//> 115 116 117// static void display_timing_info(const pa_timing_info* the_time) 118// { 119// const struct timeval *tv=&(the_time->timestamp); 120 121// SHOW_TIME("ti>"); 122// SHOW("ti> timestamp=%03d.%03dms\n",(int)(tv->tv_sec%1000), (int)(tv->tv_usec/1000)); 123// SHOW("ti> synchronized_clocks=%d\n",the_time->synchronized_clocks); 124// SHOW("ti> sink_usec=%ld\n",the_time->sink_usec); 125// SHOW("ti> source_usec=%ld\n",the_time->source_usec); 126// SHOW("ti> transport=%ld\n",the_time->transport_usec); 127// SHOW("ti> playing=%d\n",the_time->playing); 128// SHOW("ti> write_index_corrupt=%d\n",the_time->write_index_corrupt); 129// SHOW("ti> write_index=0x%lx\n",the_time->write_index); 130// SHOW("ti> read_index_corrupt=%d\n",the_time->read_index_corrupt); 131// SHOW("ti> read_index=0x%lx\n",the_time->read_index); 132// } 133 134 135static void info_cb(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { 136 ENTER(__FUNCTION__); 137 assert(c); 138 139 if (!i) 140 return; 141 142 volume = i->volume; 143 volume_valid = 1; 144} 145 146static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { 147 pa_operation *o; 148 ENTER(__FUNCTION__); 149 150 assert(c); 151 152 if (!stream || 153 index != pa_stream_get_index(stream) || 154 (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && 155 t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW))) 156 return; 157 158 if (!(o = pa_context_get_sink_input_info(c, index, info_cb, NULL))) { 159 SHOW("pa_context_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(c))); 160 return; 161 } 162 163 pa_operation_unref(o); 164} 165 166static void context_state_cb(pa_context *c, void *userdata) { 167 ENTER(__FUNCTION__); 168 assert(c); 169 170 switch (pa_context_get_state(c)) { 171 case PA_CONTEXT_READY: 172 case PA_CONTEXT_TERMINATED: 173 case PA_CONTEXT_FAILED: 174 pa_threaded_mainloop_signal(mainloop, 0); 175 break; 176 177 case PA_CONTEXT_UNCONNECTED: 178 case PA_CONTEXT_CONNECTING: 179 case PA_CONTEXT_AUTHORIZING: 180 case PA_CONTEXT_SETTING_NAME: 181 break; 182 } 183} 184 185static void stream_state_cb(pa_stream *s, void * userdata) { 186 ENTER(__FUNCTION__); 187 assert(s); 188 189 switch (pa_stream_get_state(s)) { 190 191 case PA_STREAM_READY: 192 case PA_STREAM_FAILED: 193 case PA_STREAM_TERMINATED: 194 pa_threaded_mainloop_signal(mainloop, 0); 195 break; 196 197 case PA_STREAM_UNCONNECTED: 198 case PA_STREAM_CREATING: 199 break; 200 } 201} 202 203static void stream_success_cb(pa_stream *s, int success, void *userdata) { 204 ENTER(__FUNCTION__); 205 assert(s); 206 207 if (userdata) 208 *(int*) userdata = success; 209 210 pa_threaded_mainloop_signal(mainloop, 0); 211} 212 213static void context_success_cb(pa_context *c, int success, void *userdata) { 214 ENTER(__FUNCTION__); 215 assert(c); 216 217 if (userdata) 218 *(int*) userdata = success; 219 220 pa_threaded_mainloop_signal(mainloop, 0); 221} 222 223static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { 224 ENTER(__FUNCTION__); 225 assert(s); 226 227 pa_threaded_mainloop_signal(mainloop, 0); 228} 229 230static void stream_latency_update_cb(pa_stream *s, void *userdata) { 231 // ENTER(__FUNCTION__); 232 assert(s); 233 234 pa_threaded_mainloop_signal(mainloop, 0); 235} 236 237static int pulse_free(void) { 238 ENTER(__FUNCTION__); 239 size_t l = 0; 240 pa_operation *o = NULL; 241 242 CHECK_CONNECTED(0); 243 244 SHOW("pulse_free: %s (call)\n", "pa_threaded_main_loop_lock"); 245 pa_threaded_mainloop_lock(mainloop); 246 CHECK_DEAD_GOTO(fail, 1); 247 248 if ((l = pa_stream_writable_size(stream)) == (size_t) -1) { 249 SHOW("pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(context))); 250 l = 0; 251 goto fail; 252 } 253 254 SHOW("pulse_free: %s (ret=%d)\n", "pa_stream_writable_size", l); 255 256 /* If this function is called twice with no pulse_write() call in 257 * between this means we should trigger the playback */ 258 if (do_trigger) { 259 int success = 0; 260 261 SHOW("pulse_free: %s (call)\n", "pa_stream_trigger"); 262 if (!(o = pa_stream_trigger(stream, stream_success_cb, &success))) { 263 SHOW("pa_stream_trigger() failed: %s", pa_strerror(pa_context_errno(context))); 264 goto fail; 265 } 266 267 SHOW("pulse_free: %s (call)\n", "pa_threaded_main_loop"); 268 while (pa_operation_get_state(o) != PA_OPERATION_DONE) { 269 CHECK_DEAD_GOTO(fail, 1); 270 pa_threaded_mainloop_wait(mainloop); 271 } 272 SHOW("pulse_free: %s (ret)\n", "pa_threaded_main_loop"); 273 274 if (!success) 275 SHOW("pa_stream_trigger() failed: %s", pa_strerror(pa_context_errno(context))); 276 } 277 278fail: 279 SHOW("pulse_free: %s (call)\n", "pa_operation_unref"); 280 if (o) 281 pa_operation_unref(o); 282 283 SHOW("pulse_free: %s (call)\n", "pa_threaded_main_loop_unlock"); 284 pa_threaded_mainloop_unlock(mainloop); 285 286 do_trigger = !!l; 287 SHOW("pulse_free: %d (ret)\n", (int)l); 288 return (int) l; 289} 290 291static int pulse_playing(const pa_timing_info *the_timing_info) { 292 ENTER(__FUNCTION__); 293 int r = 0; 294 const pa_timing_info *i; 295 296 assert(the_timing_info); 297 298 CHECK_CONNECTED(0); 299 300 pa_threaded_mainloop_lock(mainloop); 301 302 for (;;) { 303 CHECK_DEAD_GOTO(fail, 1); 304 305 if ((i = pa_stream_get_timing_info(stream))) 306 { 307 break; 308 } 309 if (pa_context_errno(context) != PA_ERR_NODATA) { 310 SHOW("pa_stream_get_timing_info() failed: %s", pa_strerror(pa_context_errno(context))); 311 goto fail; 312 } 313 314 pa_threaded_mainloop_wait(mainloop); 315 } 316 317 r = i->playing; 318 memcpy((void*)the_timing_info, (void*)i, sizeof(pa_timing_info)); 319 320 // display_timing_info(i); 321 322fail: 323 pa_threaded_mainloop_unlock(mainloop); 324 325 return r; 326} 327 328 329// static void pulse_flush(int time) { 330// ENTER(__FUNCTION__); 331// pa_operation *o = NULL; 332// int success = 0; 333 334// CHECK_CONNECTED(); 335 336// pa_threaded_mainloop_lock(mainloop); 337// CHECK_DEAD_GOTO(fail, 1); 338 339// if (!(o = pa_stream_flush(stream, stream_success_cb, &success))) { 340// SHOW("pa_stream_flush() failed: %s", pa_strerror(pa_context_errno(context))); 341// goto fail; 342// } 343 344// while (pa_operation_get_state(o) != PA_OPERATION_DONE) { 345// CHECK_DEAD_GOTO(fail, 1); 346// pa_threaded_mainloop_wait(mainloop); 347// } 348 349// if (!success) 350// SHOW("pa_stream_flush() failed: %s", pa_strerror(pa_context_errno(context))); 351 352// written = (uint64_t) (((double) time * pa_bytes_per_second(pa_stream_get_sample_spec(stream))) / 1000); 353// just_flushed = 1; 354// time_offset_msec = time; 355 356// fail: 357// if (o) 358// pa_operation_unref(o); 359 360// pa_threaded_mainloop_unlock(mainloop); 361// } 362 363 364static void pulse_write(void* ptr, int length) { 365 ENTER(__FUNCTION__); 366 367 368 SHOW("pulse_write > length=%d\n", length); 369 370 CHECK_CONNECTED(); 371 372 pa_threaded_mainloop_lock(mainloop); 373 CHECK_DEAD_GOTO(fail, 1); 374 375 if (pa_stream_write(stream, ptr, length, NULL, PA_SEEK_RELATIVE, (pa_seek_mode_t)0) < 0) { 376 SHOW("pa_stream_write() failed: %s", pa_strerror(pa_context_errno(context))); 377 goto fail; 378 } 379 380 do_trigger = 0; 381 written += length; 382 383fail: 384 385 pa_threaded_mainloop_unlock(mainloop); 386} 387 388static int drain(void) { 389 pa_operation *o = NULL; 390 int success = 0; 391 int ret = PULSE_ERROR; 392 393 ENTER(__FUNCTION__); 394 395 CHECK_CONNECTED(ret); 396 397 pa_threaded_mainloop_lock(mainloop); 398 CHECK_DEAD_GOTO(fail, 0); 399 400 SHOW_TIME("pa_stream_drain (call)"); 401 if (!(o = pa_stream_drain(stream, stream_success_cb, &success))) { 402 SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context))); 403 goto fail; 404 } 405 406 SHOW_TIME("pa_threaded_mainloop_wait (call)"); 407 while (pa_operation_get_state(o) != PA_OPERATION_DONE) { 408 CHECK_DEAD_GOTO(fail, 1); 409 pa_threaded_mainloop_wait(mainloop); 410 } 411 SHOW_TIME("pa_threaded_mainloop_wait (ret)"); 412 413 if (!success) { 414 SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context))); 415 } 416 else { 417 ret = PULSE_OK; 418 } 419 420fail: 421 SHOW_TIME("pa_operation_unref (call)"); 422 if (o) 423 pa_operation_unref(o); 424 425 pa_threaded_mainloop_unlock(mainloop); 426 SHOW_TIME("drain (ret)"); 427 428 return ret; 429} 430 431 432static void pulse_close(void) { 433 434 ENTER(__FUNCTION__); 435 436 drain(); 437 438 connected = 0; 439 440 if (mainloop) 441 pa_threaded_mainloop_stop(mainloop); 442 443 connected = 0; 444 445 if (context) { 446 SHOW_TIME("pa_context_disconnect (call)"); 447 pa_context_disconnect(context); 448 pa_context_unref(context); 449 context = NULL; 450 } 451 452 if (mainloop) { 453 SHOW_TIME("pa_threaded_mainloop_free (call)"); 454 pa_threaded_mainloop_free(mainloop); 455 mainloop = NULL; 456 } 457 SHOW_TIME("pulse_close (ret)"); 458 459} 460 461 462static int pulse_open() 463{ 464 ENTER(__FUNCTION__); 465 pa_sample_spec ss; 466 pa_operation *o = NULL; 467 int success; 468 int ret = PULSE_ERROR; 469 470 assert(!mainloop); 471 assert(!context); 472 assert(!stream); 473 assert(!connected); 474 475 pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL); 476 477 ss.format = ESPEAK_FORMAT; 478 ss.rate = SAMPLE_RATE; 479 ss.channels = ESPEAK_CHANNEL; 480 481 if (!pa_sample_spec_valid(&ss)) 482 return false; 483 484/* if (!volume_valid) { */ 485 pa_cvolume_reset(&volume, ss.channels); 486 volume_valid = 1; 487/* } else if (volume.channels != ss.channels) */ 488/* pa_cvolume_set(&volume, ss.channels, pa_cvolume_avg(&volume)); */ 489 490 SHOW_TIME("pa_threaded_mainloop_new (call)"); 491 if (!(mainloop = pa_threaded_mainloop_new())) { 492 SHOW("Failed to allocate main loop\n",""); 493 goto fail; 494 } 495 496 pa_threaded_mainloop_lock(mainloop); 497 498 SHOW_TIME("pa_context_new (call)"); 499 if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "eSpeak"))) { 500 SHOW("Failed to allocate context\n",""); 501 goto unlock_and_fail; 502 } 503 504 pa_context_set_state_callback(context, context_state_cb, NULL); 505 pa_context_set_subscribe_callback(context, subscribe_cb, NULL); 506 507 SHOW_TIME("pa_context_connect (call)"); 508 if (pa_context_connect(context, NULL, (pa_context_flags_t)0, NULL) < 0) { 509 SHOW("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); 510 ret = PULSE_NO_CONNECTION; 511 goto unlock_and_fail; 512 } 513 514 SHOW_TIME("pa_threaded_mainloop_start (call)"); 515 if (pa_threaded_mainloop_start(mainloop) < 0) { 516 SHOW("Failed to start main loop",""); 517 goto unlock_and_fail; 518 } 519 520 /* Wait until the context is ready */ 521 SHOW_TIME("pa_threaded_mainloop_wait"); 522 pa_threaded_mainloop_wait(mainloop); 523 524 if (pa_context_get_state(context) != PA_CONTEXT_READY) { 525 SHOW("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); 526 ret = PULSE_NO_CONNECTION; 527 if (mainloop) 528 pa_threaded_mainloop_stop(mainloop); 529 goto unlock_and_fail; 530 } 531 532 SHOW_TIME("pa_stream_new"); 533 if (!(stream = pa_stream_new(context, "unknown", &ss, NULL))) { 534 SHOW("Failed to create stream: %s", pa_strerror(pa_context_errno(context))); 535 goto unlock_and_fail; 536 } 537 538 pa_stream_set_state_callback(stream, stream_state_cb, NULL); 539 pa_stream_set_write_callback(stream, stream_request_cb, NULL); 540 pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); 541 542 543 544 pa_buffer_attr a_attr; 545 546 a_attr.maxlength = MAXLENGTH; 547 a_attr.tlength = TLENGTH; 548 a_attr.prebuf = PREBUF; 549 a_attr.minreq = MINREQ; 550 a_attr.fragsize = 0; 551 552 SHOW_TIME("pa_connect_playback"); 553 if (pa_stream_connect_playback(stream, NULL, &a_attr, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE), &volume, NULL) < 0) { 554 SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); 555 goto unlock_and_fail; 556 } 557 558 /* Wait until the stream is ready */ 559 SHOW_TIME("pa_threaded_mainloop_wait"); 560 pa_threaded_mainloop_wait(mainloop); 561 562 if (pa_stream_get_state(stream) != PA_STREAM_READY) { 563 SHOW("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); 564 goto unlock_and_fail; 565 } 566 567 /* Now subscribe to events */ 568 SHOW_TIME("pa_context_subscribe"); 569 if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) { 570 SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); 571 goto unlock_and_fail; 572 } 573 574 success = 0; 575 SHOW_TIME("pa_threaded_mainloop_wait"); 576 while (pa_operation_get_state(o) != PA_OPERATION_DONE) { 577 CHECK_DEAD_GOTO(fail, 1); 578 pa_threaded_mainloop_wait(mainloop); 579 } 580 581 if (!success) { 582 SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); 583 goto unlock_and_fail; 584 } 585 586 pa_operation_unref(o); 587 588 /* Now request the initial stream info */ 589 if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, NULL))) { 590 SHOW("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); 591 goto unlock_and_fail; 592 } 593 594 SHOW_TIME("pa_threaded_mainloop_wait 2"); 595 while (pa_operation_get_state(o) != PA_OPERATION_DONE) { 596 CHECK_DEAD_GOTO(fail, 1); 597 pa_threaded_mainloop_wait(mainloop); 598 } 599 600/* if (!volume_valid) { */ 601/* SHOW("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); */ 602/* goto unlock_and_fail; */ 603/* } */ 604 605 do_trigger = 0; 606 written = 0; 607 time_offset_msec = 0; 608 just_flushed = 0; 609 connected = 1; 610 // volume_time_event = NULL; 611 612 pa_threaded_mainloop_unlock(mainloop); 613 SHOW_TIME("pulse_open (ret true)"); 614 615 // return true; 616 return PULSE_OK; 617 618 619unlock_and_fail: 620 621 if (o) 622 pa_operation_unref(o); 623 624 pa_threaded_mainloop_unlock(mainloop); 625 626fail: 627 628 // pulse_close(); 629 630 if (ret == PULSE_NO_CONNECTION) { 631 if (context) { 632 SHOW_TIME("pa_context_disconnect (call)"); 633 pa_context_disconnect(context); 634 pa_context_unref(context); 635 context = NULL; 636 } 637 638 if (mainloop) { 639 SHOW_TIME("pa_threaded_mainloop_free (call)"); 640 pa_threaded_mainloop_free(mainloop); 641 mainloop = NULL; 642 } 643 } 644 else { 645 pulse_close(); 646 } 647 648 SHOW_TIME("pulse_open (ret false)"); 649 650 return ret; 651 652} 653 654void wave_flush(void* theHandler) 655{ 656 ENTER("wave_flush"); 657 658// if (my_stream_could_start) 659// { 660// // #define buf 1024 661// // static char a_buffer[buf*2]; 662// // memset(a_buffer,0,buf*2); 663// // wave_write(theHandler, a_buffer, buf*2); 664// start_stream(); 665// } 666} 667 668 669 670//<wave_set_callback_is_output_enabled 671 672void wave_set_callback_is_output_enabled(t_wave_callback* cb) 673{ 674 my_callback_is_output_enabled = cb; 675} 676 677//> 678//<wave_init 679 680void wave_init() 681{ 682 ENTER("wave_init"); 683 684 stream = NULL; 685 686 pulse_open(); 687} 688 689//> 690//<wave_open 691 692void* wave_open(const char* the_api) 693{ 694 ENTER("wave_open"); 695 return((void*)1); 696} 697 698//> 699//<wave_write 700 701size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) 702{ 703 ENTER("wave_write"); 704 size_t bytes_to_write = theSize; 705 char* aBuffer=theMono16BitsWaveBuffer; 706 707 assert(stream); 708 709 size_t aTotalFreeMem=0; 710 711 pthread_mutex_lock(&pulse_mutex); 712 713 while (1) 714 { 715 if (my_callback_is_output_enabled 716 && (0==my_callback_is_output_enabled())) 717 { 718 SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); 719 theSize=0; 720 goto terminate; 721 } 722 723 aTotalFreeMem = pulse_free(); 724 if (aTotalFreeMem >= bytes_to_write) 725 { 726 SHOW("wave_write > aTotalFreeMem(%d) >= bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); 727 break; 728 } 729 730 // TBD: check if really helpful 731 if (aTotalFreeMem >= MAXLENGTH*2) 732 { 733 aTotalFreeMem = MAXLENGTH*2; 734 } 735 736 SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); 737 738 // 500: threshold for avoiding too many calls to pulse_write 739 if (aTotalFreeMem>500) 740 { 741 pulse_write(aBuffer, aTotalFreeMem); 742 bytes_to_write -= aTotalFreeMem; 743 aBuffer += aTotalFreeMem; 744 } 745 746 usleep(10000); 747 } 748 749 pulse_write(aBuffer, bytes_to_write); 750 751 terminate: 752 pthread_mutex_unlock(&pulse_mutex); 753 SHOW("wave_write: theSize=%d", theSize); 754 SHOW_TIME("wave_write > LEAVE"); 755 return theSize; 756} 757 758//> 759//<wave_close 760 761int wave_close(void* theHandler) 762{ 763 SHOW_TIME("wave_close > ENTER"); 764 765 int a_status = pthread_mutex_lock(&pulse_mutex); 766 if (a_status) { 767 SHOW("Error: pulse_mutex lock=%d (%s)\n", a_status, __FUNCTION__); 768 return PULSE_ERROR; 769 } 770 771 drain(); 772 773 pthread_mutex_unlock(&pulse_mutex); 774 SHOW_TIME("wave_close (ret)"); 775 776 return PULSE_OK; 777} 778 779//> 780//<wave_is_busy 781 782int wave_is_busy(void* theHandler) 783{ 784 SHOW_TIME("wave_is_busy"); 785 786 pa_timing_info a_timing_info; 787 int active = pulse_playing(&a_timing_info); 788 SHOW("wave_is_busy: %d\n",active); 789 return active; 790} 791 792//> 793//<wave_terminate 794 795void wave_terminate() 796{ 797 ENTER("wave_terminate"); 798 799// Pa_Terminate(); 800 801 int a_status; 802 pthread_mutex_t* a_mutex = NULL; 803 a_mutex = &pulse_mutex; 804 a_status = pthread_mutex_lock(a_mutex); 805 806 pulse_close(); 807 808 SHOW_TIME("unlock mutex"); 809 a_status = pthread_mutex_unlock(a_mutex); 810 pthread_mutex_destroy(a_mutex); 811} 812 813//> 814//<wave_get_read_position, wave_get_write_position, wave_get_remaining_time 815 816uint32_t wave_get_read_position(void* theHandler) 817{ 818 pa_timing_info a_timing_info; 819 pulse_playing(&a_timing_info); 820 SHOW("wave_get_read_position > %lx\n", a_timing_info.read_index); 821 return a_timing_info.read_index; 822} 823 824uint32_t wave_get_write_position(void* theHandler) 825{ 826 pa_timing_info a_timing_info; 827 pulse_playing(&a_timing_info); 828 SHOW("wave_get_read_position > %lx\n", a_timing_info.write_index); 829 return a_timing_info.write_index; 830} 831 832int wave_get_remaining_time(uint32_t sample, uint32_t* time) 833{ 834 double a_time=0; 835 836 if (!time || !stream) 837 { 838 SHOW("event get_remaining_time> %s\n","audio device not available"); 839 return -1; 840 } 841 842 pa_timing_info a_timing_info; 843 pulse_playing(&a_timing_info); 844 845 if (sample > a_timing_info.read_index) 846 { 847 // TBD: take in account time suplied by portaudio V18 API 848 a_time = sample - a_timing_info.read_index; 849 a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE; 850 } 851 else 852 { 853 a_time = 0; 854 } 855 856 SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time); 857 858 *time = (uint32_t)a_time; 859 860 return 0; 861} 862 863//> 864//<wave_test_get_write_buffer 865 866void *wave_test_get_write_buffer() 867{ 868 return NULL; 869} 870 871 872#else 873// notdef USE_PULSEAUDIO 874 875 876void wave_init() {} 877void* wave_open(const char* the_api) {return (void *)1;} 878size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;} 879int wave_close(void* theHandler) {return 0;} 880int wave_is_busy(void* theHandler) {return 0;} 881void wave_terminate() {} 882uint32_t wave_get_read_position(void* theHandler) {return 0;} 883uint32_t wave_get_write_position(void* theHandler) {return 0;} 884void wave_flush(void* theHandler) {} 885typedef int (t_wave_callback)(void); 886void wave_set_callback_is_output_enabled(t_wave_callback* cb) {} 887extern void* wave_test_get_write_buffer() {return NULL;} 888 889int wave_get_remaining_time(uint32_t sample, uint32_t* time) 890{ 891 if (!time) return(-1); 892 *time = (uint32_t)0; 893 return 0; 894} 895 896#endif // of USE_PORTAUDIO 897 898//> 899//<clock_gettime2, add_time_in_ms 900 901void clock_gettime2(struct timespec *ts) 902{ 903 struct timeval tv; 904 905 if (!ts) 906 { 907 return; 908 } 909 910 assert (gettimeofday(&tv, NULL) != -1); 911 ts->tv_sec = tv.tv_sec; 912 ts->tv_nsec = tv.tv_usec*1000; 913} 914 915void add_time_in_ms(struct timespec *ts, int time_in_ms) 916{ 917 if (!ts) 918 { 919 return; 920 } 921 922 uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms; 923 while(t_ns >= ONE_BILLION) 924 { 925 SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns); 926 ts->tv_sec += 1; 927 t_ns -= ONE_BILLION; 928 } 929 ts->tv_nsec = (long int)t_ns; 930} 931 932 933#endif // USE_ASYNC 934 935//>