1 /***************************************************************************
2 * Copyright (C) 2007, Gilles Casse <gcasse@oralux.org> *
3 * based on AudioIO.cc (Audacity-1.2.4b) and wavegen.cpp *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "speech.h"
22
23 #ifdef USE_ASYNC
24 // This source file is only used for asynchronious modes
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <assert.h>
31 #include <sys/time.h>
32 #include <time.h>
33
34 #include "portaudio.h"
35 #ifdef PLATFORM_WINDOWS
36 #include <windows.h>
37 #else
38 #include <unistd.h>
39 #endif
40 #include "wave.h"
41 #include "debug.h"
42
43 //<Definitions
44
45 #ifdef NEED_STRUCT_TIMESPEC
46 #define HAVE_STRUCT_TIMESPEC 1
47 struct timespec {
48 long tv_sec;
49 long tv_nsec;
50 };
51 #endif /* HAVE_STRUCT_TIMESPEC */
52
53
54 enum {ONE_BILLION=1000000000};
55
56 #ifdef USE_PORTAUDIO
57
58 #undef USE_PORTAUDIO
59 // determine portaudio version by looking for a #define which is not in V18
60 #ifdef paNeverDropInput
61 #define USE_PORTAUDIO 19
62 #else
63 #define USE_PORTAUDIO 18
64 #endif
65
66
67
68
69 #ifdef USE_PULSEAUDIO
70 // create some wrappers for runtime detection
71
72 // checked on wave_init
73 static int pulse_running;
74
75 // wave.cpp (this file)
76 int wave_port_init(int);
77 void* wave_port_open(const char* the_api);
78 size_t wave_port_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize);
79 int wave_port_close(void* theHandler);
80 int wave_port_is_busy(void* theHandler);
81 void wave_port_terminate();
82 uint32_t wave_port_get_read_position(void* theHandler);
83 uint32_t wave_port_get_write_position(void* theHandler);
84 void wave_port_flush(void* theHandler);
85 void wave_port_set_callback_is_output_enabled(t_wave_callback* cb);
86 void* wave_port_test_get_write_buffer();
87 int wave_port_get_remaining_time(uint32_t sample, uint32_t* time);
88
89 // wave_pulse.cpp
90 int is_pulse_running();
91 int wave_pulse_init(int);
92 void* wave_pulse_open(const char* the_api);
93 size_t wave_pulse_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize);
94 int wave_pulse_close(void* theHandler);
95 int wave_pulse_is_busy(void* theHandler);
96 void wave_pulse_terminate();
97 uint32_t wave_pulse_get_read_position(void* theHandler);
98 uint32_t wave_pulse_get_write_position(void* theHandler);
99 void wave_pulse_flush(void* theHandler);
100 void wave_pulse_set_callback_is_output_enabled(t_wave_callback* cb);
101 void* wave_pulse_test_get_write_buffer();
102 int wave_pulse_get_remaining_time(uint32_t sample, uint32_t* time);
103
104 // wrappers
wave_init(int srate)105 int wave_init(int srate) {
106 pulse_running = is_pulse_running();
107
108 if (pulse_running)
109 return wave_pulse_init(srate);
110 else
111 return wave_port_init(srate);
112 }
113
wave_open(const char * the_api)114 void* wave_open(const char* the_api) {
115 if (pulse_running)
116 return wave_pulse_open(the_api);
117 else
118 return wave_port_open(the_api);
119 }
120
wave_write(void * theHandler,char * theMono16BitsWaveBuffer,size_t theSize)121 size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {
122 if (pulse_running)
123 return wave_pulse_write(theHandler, theMono16BitsWaveBuffer, theSize);
124 else
125 return wave_port_write(theHandler, theMono16BitsWaveBuffer, theSize);
126 }
127
wave_close(void * theHandler)128 int wave_close(void* theHandler) {
129 if (pulse_running)
130 return wave_pulse_close(theHandler);
131 else
132 return wave_port_close(theHandler);
133 }
134
wave_is_busy(void * theHandler)135 int wave_is_busy(void* theHandler) {
136 if (pulse_running)
137 return wave_pulse_is_busy(theHandler);
138 else
139 return wave_port_is_busy(theHandler);
140 }
141
wave_terminate()142 void wave_terminate() {
143 if (pulse_running)
144 wave_pulse_terminate();
145 else
146 wave_port_terminate();
147 }
148
wave_get_read_position(void * theHandler)149 uint32_t wave_get_read_position(void* theHandler) {
150 if (pulse_running)
151 return wave_pulse_get_read_position(theHandler);
152 else
153 return wave_port_get_read_position(theHandler);
154 }
155
wave_get_write_position(void * theHandler)156 uint32_t wave_get_write_position(void* theHandler) {
157 if (pulse_running)
158 return wave_pulse_get_write_position(theHandler);
159 else
160 return wave_port_get_write_position(theHandler);
161 }
162
wave_flush(void * theHandler)163 void wave_flush(void* theHandler) {
164 if (pulse_running)
165 wave_pulse_flush(theHandler);
166 else
167 wave_port_flush(theHandler);
168 }
169
wave_set_callback_is_output_enabled(t_wave_callback * cb)170 void wave_set_callback_is_output_enabled(t_wave_callback* cb) {
171 if (pulse_running)
172 wave_pulse_set_callback_is_output_enabled(cb);
173 else
174 wave_port_set_callback_is_output_enabled(cb);
175 }
176
wave_test_get_write_buffer()177 void* wave_test_get_write_buffer() {
178 if (pulse_running)
179 return wave_pulse_test_get_write_buffer();
180 else
181 return wave_port_test_get_write_buffer();
182 }
183
wave_get_remaining_time(uint32_t sample,uint32_t * time)184 int wave_get_remaining_time(uint32_t sample, uint32_t* time)
185 {
186 if (pulse_running)
187 return wave_pulse_get_remaining_time(sample, time);
188 else
189 return wave_port_get_remaining_time(sample, time);
190 }
191
192 // rename functions to be wrapped
193 #define wave_init wave_port_init
194 #define wave_open wave_port_open
195 #define wave_write wave_port_write
196 #define wave_close wave_port_close
197 #define wave_is_busy wave_port_is_busy
198 #define wave_terminate wave_port_terminate
199 #define wave_get_read_position wave_port_get_read_position
200 #define wave_get_write_position wave_port_get_write_position
201 #define wave_flush wave_port_flush
202 #define wave_set_callback_is_output_enabled wave_port_set_callback_is_output_enabled
203 #define wave_test_get_write_buffer wave_port_test_get_write_buffer
204 #define wave_get_remaining_time wave_port_get_remaining_time
205
206 #endif // USE_PULSEAUDIO
207
208
209 static t_wave_callback* my_callback_is_output_enabled=NULL;
210
211 #define N_WAV_BUF 10
212 #define MAX_SAMPLE_RATE 22050
213 #define FRAMES_PER_BUFFER 512
214 #define BUFFER_LENGTH (MAX_SAMPLE_RATE*2*sizeof(uint16_t))
215 //#define THRESHOLD (BUFFER_LENGTH/5)
216 static char myBuffer[BUFFER_LENGTH];
217 static char* myRead=NULL;
218 static char* myWrite=NULL;
219 static int out_channels=1;
220 static int my_stream_could_start=0;
221 static int wave_samplerate;
222
223 static int mInCallbackFinishedState = false;
224 #if (USE_PORTAUDIO == 18)
225 static PortAudioStream *pa_stream=NULL;
226 #endif
227 #if (USE_PORTAUDIO == 19)
228 static struct PaStreamParameters myOutputParameters;
229 static PaStream *pa_stream=NULL;
230 #endif
231
232 static int userdata[4];
233 static PaError pa_init_err=0;
234
235 // time measurement
236 // The read and write position audio stream in the audio stream are measured in ms.
237 //
238 // * When the stream is opened, myReadPosition and myWritePosition are cleared.
239 // * myWritePosition is updated in wave_write.
240 // * myReadPosition is updated in pa_callback (+ sample delay).
241
242 static uint32_t myReadPosition = 0; // in ms
243 static uint32_t myWritePosition = 0;
244
245 //>
246 //<init_buffer, get_used_mem
247
init_buffer()248 static void init_buffer()
249 {
250 myWrite = myBuffer;
251 myRead = myBuffer;
252 memset(myBuffer,0,BUFFER_LENGTH);
253 myReadPosition = myWritePosition = 0;
254 SHOW("init_buffer > myRead=0x%x, myWrite=0x%x, BUFFER_LENGTH=0x%x, myReadPosition = myWritePosition = 0\n", (int)myRead, (int)myWrite, BUFFER_LENGTH);
255 }
256
get_used_mem()257 static unsigned int get_used_mem()
258 {
259 char* aRead = myRead;
260 char* aWrite = myWrite;
261 unsigned int used = 0;
262
263 assert ((aRead >= myBuffer)
264 && (aRead <= myBuffer + BUFFER_LENGTH)
265 && (aWrite >= myBuffer)
266 && (aWrite <= myBuffer + BUFFER_LENGTH));
267
268 if (aRead < aWrite)
269 {
270 used = aWrite - aRead;
271 }
272 else
273 {
274 used = aWrite + BUFFER_LENGTH - aRead;
275 }
276 SHOW("get_used_mem > %d\n", used);
277
278 return used;
279 }
280
281 //>
282 //<start stream
283
start_stream()284 static void start_stream()
285 {
286 PaError err;
287 SHOW_TIME("start_stream");
288
289 my_stream_could_start=0;
290 mInCallbackFinishedState = false;
291
292 err = Pa_StartStream(pa_stream);
293 SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));
294
295 #if USE_PORTAUDIO == 19
296 if(err == paStreamIsNotStopped)
297 {
298 SHOW_TIME("start_stream > restart stream (begin)");
299 // not sure why we need this, but PA v19 seems to need it
300 err = Pa_StopStream(pa_stream);
301 SHOW("start_stream > Pa_StopStream=%d (%s)\n", err, Pa_GetErrorText(err));
302 err = Pa_StartStream(pa_stream);
303 SHOW("start_stream > Pa_StartStream=%d (%s)\n", err, Pa_GetErrorText(err));
304 SHOW_TIME("start_stream > restart stream (end)");
305 }
306 #endif
307 }
308
309 //>
310 //<pa_callback
311
312 /* This routine will be called by the PortAudio engine when audio is needed.
313 ** It may called at interrupt level on some machines so don't do anything
314 ** that could mess up the system like calling malloc() or free().
315 */
316 #if USE_PORTAUDIO == 18
pa_callback(void * inputBuffer,void * outputBuffer,unsigned long framesPerBuffer,PaTimestamp outTime,void * userData)317 static int pa_callback(void *inputBuffer, void *outputBuffer,
318 unsigned long framesPerBuffer, PaTimestamp outTime, void *userData )
319 #else
320 static int pa_callback(const void *inputBuffer, void *outputBuffer,
321 long unsigned int framesPerBuffer, const PaStreamCallbackTimeInfo *outTime,
322 PaStreamCallbackFlags flags, void *userData )
323 #endif
324 {
325 int aResult=0; // paContinue
326 char* aWrite = myWrite;
327 size_t n = out_channels*sizeof(uint16_t)*framesPerBuffer;
328
329 myReadPosition += framesPerBuffer;
330 SHOW("pa_callback > myReadPosition=%u, framesPerBuffer=%lu (n=0x%x) \n",(int)myReadPosition, framesPerBuffer, n);
331
332 if (aWrite >= myRead)
333 {
334 if((size_t)(aWrite - myRead) >= n)
335 {
336 memcpy(outputBuffer, myRead, n);
337 myRead += n;
338 }
339 else
340 {
341 SHOW_TIME("pa_callback > underflow");
342 aResult=1; // paComplete;
343 mInCallbackFinishedState = true;
344 size_t aUsedMem=0;
345 aUsedMem = (size_t)(aWrite - myRead);
346 if (aUsedMem)
347 {
348 memcpy(outputBuffer, myRead, aUsedMem);
349 }
350 char* p = (char*)outputBuffer + aUsedMem;
351 memset(p, 0, n - aUsedMem);
352 // myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t));
353 myRead = aWrite;
354 }
355 }
356 else // myRead > aWrite
357 {
358 if ((size_t)(myBuffer + BUFFER_LENGTH - myRead) >= n)
359 {
360 memcpy(outputBuffer, myRead, n);
361 myRead += n;
362 }
363 else if ((size_t)(aWrite + BUFFER_LENGTH - myRead) >= n)
364 {
365 int aTopMem = myBuffer + BUFFER_LENGTH - myRead;
366 if (aTopMem)
367 {
368 SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem);
369 memcpy(outputBuffer, myRead, aTopMem);
370 }
371 int aRest = n - aTopMem;
372 if (aRest)
373 {
374 SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest);
375 char* p = (char*)outputBuffer + aTopMem;
376 memcpy(p, myBuffer, aRest);
377 }
378 myRead = myBuffer + aRest;
379 }
380 else
381 {
382 SHOW_TIME("pa_callback > underflow");
383 aResult=1; // paComplete;
384
385 int aTopMem = myBuffer + BUFFER_LENGTH - myRead;
386 if (aTopMem)
387 {
388 SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem);
389 memcpy(outputBuffer, myRead, aTopMem);
390 }
391 int aRest = aWrite - myBuffer;
392 if (aRest)
393 {
394 SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest);
395 char* p = (char*)outputBuffer + aTopMem;
396 memcpy(p, myBuffer, aRest);
397 }
398
399 size_t aUsedMem = aTopMem + aRest;
400 char* p = (char*)outputBuffer + aUsedMem;
401 memset(p, 0, n - aUsedMem);
402 // myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t));
403 myRead = aWrite;
404 }
405 }
406
407 SHOW("pa_callback > myRead=%x\n",(int)myRead);
408
409
410 // #if USE_PORTAUDIO == 18
411 // if(aBufferEmpty)
412 // {
413 // static int end_timer = 0;
414 // if(end_timer == 0)
415 // end_timer = 4;
416 // if(end_timer > 0)
417 // {
418 // end_timer--;
419 // if(end_timer == 0)
420 // return(1);
421 // }
422 // }
423 // return(0);
424 // #else
425
426 #ifdef ARCH_BIG
427 {
428 // BIG-ENDIAN, swap the order of bytes in each sound sample in the portaudio buffer
429 int c;
430 unsigned char *out_ptr;
431 unsigned char *out_end;
432 out_ptr = (unsigned char *)outputBuffer;
433 out_end = out_ptr + framesPerBuffer*2 * out_channels;
434 while(out_ptr < out_end)
435 {
436 c = out_ptr[0];
437 out_ptr[0] = out_ptr[1];
438 out_ptr[1] = c;
439 out_ptr += 2;
440 }
441 }
442 #endif
443
444
445 return(aResult);
446 //#endif
447
448 } // end of WaveCallBack
449
450 //>
451
452
wave_flush(void * theHandler)453 void wave_flush(void* theHandler)
454 {
455 ENTER("wave_flush");
456
457 if (my_stream_could_start)
458 {
459 // #define buf 1024
460 // static char a_buffer[buf*2];
461 // memset(a_buffer,0,buf*2);
462 // wave_write(theHandler, a_buffer, buf*2);
463 start_stream();
464 }
465 }
466
467 //<wave_open_sound
468
wave_open_sound()469 static int wave_open_sound()
470 {
471 ENTER("wave_open_sound");
472
473 PaError err=paNoError;
474 PaError active;
475
476 #if USE_PORTAUDIO == 18
477 active = Pa_StreamActive(pa_stream);
478 #else
479 active = Pa_IsStreamActive(pa_stream);
480 #endif
481
482 if(active == 1)
483 {
484 SHOW_TIME("wave_open_sound > already active");
485 return(0);
486 }
487 if(active < 0)
488 {
489 out_channels = 1;
490
491 #if USE_PORTAUDIO == 18
492 // err = Pa_OpenDefaultStream(&pa_stream,0,1,paInt16,wave_samplerate,FRAMES_PER_BUFFER,N_WAV_BUF,pa_callback,(void *)userdata);
493
494 PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID();
495
496 PaError err = Pa_OpenStream( &pa_stream,
497 /* capture parameters */
498 paNoDevice,
499 0,
500 paInt16,
501 NULL,
502 /* playback parameters */
503 playbackDevice,
504 out_channels,
505 paInt16,
506 NULL,
507 /* general parameters */
508 wave_samplerate, FRAMES_PER_BUFFER, 0,
509 //paClipOff | paDitherOff,
510 paNoFlag,
511 pa_callback, (void *)userdata);
512
513 SHOW("wave_open_sound > Pa_OpenDefaultStream(1): err=%d (%s)\n",err, Pa_GetErrorText(err));
514
515 if(err == paInvalidChannelCount)
516 {
517 SHOW_TIME("wave_open_sound > try stereo");
518 // failed to open with mono, try stereo
519 out_channels = 2;
520 // myOutputParameters.channelCount = out_channels;
521 PaError err = Pa_OpenStream( &pa_stream,
522 /* capture parameters */
523 paNoDevice,
524 0,
525 paInt16,
526 NULL,
527 /* playback parameters */
528 playbackDevice,
529 out_channels,
530 paInt16,
531 NULL,
532 /* general parameters */
533 wave_samplerate, FRAMES_PER_BUFFER, 0,
534 //paClipOff | paDitherOff,
535 paNoFlag,
536 pa_callback, (void *)userdata);
537 // err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,
538 // wave_samplerate,
539 // FRAMES_PER_BUFFER,
540 // N_WAV_BUF,pa_callback,(void *)userdata);
541 SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n",err, Pa_GetErrorText(err));
542 err=0; // avoid warning
543 }
544 mInCallbackFinishedState = false; // v18 only
545 #else
546 myOutputParameters.channelCount = out_channels;
547 unsigned long framesPerBuffer = paFramesPerBufferUnspecified;
548 err = Pa_OpenStream(
549 &pa_stream,
550 NULL, /* no input */
551 &myOutputParameters,
552 wave_samplerate,
553 framesPerBuffer,
554 paNoFlag,
555 // paClipOff | paDitherOff,
556 pa_callback,
557 (void *)userdata);
558 if ((err!=paNoError)
559 && (err!=paInvalidChannelCount)) //err==paUnanticipatedHostError
560 {
561 fprintf(stderr, "wave_open_sound > Pa_OpenStream : err=%d (%s)\n",err,Pa_GetErrorText(err));
562 framesPerBuffer = FRAMES_PER_BUFFER;
563 err = Pa_OpenStream(
564 &pa_stream,
565 NULL, /* no input */
566 &myOutputParameters,
567 wave_samplerate,
568 framesPerBuffer,
569 paNoFlag,
570 // paClipOff | paDitherOff,
571 pa_callback,
572 (void *)userdata);
573 }
574 if(err == paInvalidChannelCount)
575 {
576 SHOW_TIME("wave_open_sound > try stereo");
577 // failed to open with mono, try stereo
578 out_channels = 2;
579 myOutputParameters.channelCount = out_channels;
580 err = Pa_OpenStream(
581 &pa_stream,
582 NULL, /* no input */
583 &myOutputParameters,
584 wave_samplerate,
585 framesPerBuffer,
586 paNoFlag,
587 // paClipOff | paDitherOff,
588 pa_callback,
589 (void *)userdata);
590
591 // err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,(double)wave_samplerate,FRAMES_PER_BUFFER,pa_callback,(void *)userdata);
592 }
593 mInCallbackFinishedState = false;
594 #endif
595 }
596
597 SHOW("wave_open_sound > %s\n","LEAVE");
598
599 return (err != paNoError);
600 }
601
602 //>
603 //<select_device
604
605 #if (USE_PORTAUDIO == 19)
update_output_parameters(int selectedDevice,const PaDeviceInfo * deviceInfo)606 static void update_output_parameters(int selectedDevice, const PaDeviceInfo *deviceInfo)
607 {
608 // const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
609 myOutputParameters.device = selectedDevice;
610 // myOutputParameters.channelCount = pdi->maxOutputChannels;
611 myOutputParameters.channelCount = 1;
612 myOutputParameters.sampleFormat = paInt16;
613
614 // Latency greater than 100ms for avoiding glitches
615 // (e.g. when moving a window in a graphical desktop)
616 // deviceInfo = Pa_GetDeviceInfo(selectedDevice);
617 if (deviceInfo)
618 {
619 double aLatency = deviceInfo->defaultLowOutputLatency;
620 // double aCoeff = round(0.100 / aLatency);
621 // myOutputParameters.suggestedLatency = aCoeff * aLatency; // to avoid glitches ?
622 myOutputParameters.suggestedLatency = aLatency; // for faster response ?
623 SHOW("Device=%d, myOutputParameters.suggestedLatency=%f, aCoeff=%f\n",
624 selectedDevice,
625 myOutputParameters.suggestedLatency,
626 aCoeff);
627 }
628 else
629 {
630 myOutputParameters.suggestedLatency = (double)0.1; // 100ms
631 SHOW("Device=%d, myOutputParameters.suggestedLatency=%f (default)\n",
632 selectedDevice,
633 myOutputParameters.suggestedLatency);
634 }
635 //pdi->defaultLowOutputLatency;
636
637 myOutputParameters.hostApiSpecificStreamInfo = NULL;
638 }
639 #endif
640
select_device(const char * the_api)641 static void select_device(const char* the_api)
642 {
643 ENTER("select_device");
644
645 #if (USE_PORTAUDIO == 19)
646 int numDevices = Pa_GetDeviceCount();
647 if( numDevices < 0 )
648 {
649 SHOW( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
650 assert(0);
651 }
652
653 PaDeviceIndex i=0, selectedIndex=0, defaultAlsaIndex=numDevices;
654 const PaDeviceInfo *deviceInfo=NULL;
655 const PaDeviceInfo *selectedDeviceInfo=NULL;
656
657 if(option_device_number >= 0)
658 {
659 selectedIndex = option_device_number;
660 selectedDeviceInfo = Pa_GetDeviceInfo(selectedIndex);
661 }
662
663 if(selectedDeviceInfo == NULL)
664 {
665 for( i=0; i<numDevices; i++ )
666 {
667 deviceInfo = Pa_GetDeviceInfo( i );
668
669 if (deviceInfo == NULL)
670 {
671 break;
672 }
673 const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
674
675 if (hostInfo && hostInfo->type == paALSA)
676 {
677 // Check (once) the default output device
678 if (defaultAlsaIndex == numDevices)
679 {
680 defaultAlsaIndex = hostInfo->defaultOutputDevice;
681 const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( defaultAlsaIndex );
682 update_output_parameters(defaultAlsaIndex, deviceInfo);
683 if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0)
684 {
685 SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex);
686 selectedIndex = defaultAlsaIndex;
687 selectedDeviceInfo = deviceInfo;
688 break;
689 }
690 }
691
692 // if the default output device does not match,
693 // look for the device with the highest number of output channels
694 SHOW( "select_device > ALSA, i=%d (numDevices=%d)\n", i, numDevices);
695
696 update_output_parameters(i, deviceInfo);
697
698 if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0)
699 {
700 SHOW( "select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i);
701
702 if (!selectedDeviceInfo
703 || (selectedDeviceInfo->maxOutputChannels < deviceInfo->maxOutputChannels))
704 {
705 selectedIndex = i;
706 selectedDeviceInfo = deviceInfo;
707 }
708 }
709 }
710 }
711 }
712
713 if (selectedDeviceInfo)
714 {
715 update_output_parameters(selectedIndex, selectedDeviceInfo);
716 }
717 else
718 {
719 i = Pa_GetDefaultOutputDevice();
720 deviceInfo = Pa_GetDeviceInfo( i );
721 update_output_parameters(i, deviceInfo);
722 }
723
724 #endif
725 }
726
727 //>
728
729
730 // int wave_Close(void* theHandler)
731 // {
732 // SHOW_TIME("WaveCloseSound");
733
734 // // PaError active;
735
736 // // check whether speaking has finished, and close the stream
737 // if(pa_stream != NULL)
738 // {
739 // Pa_CloseStream(pa_stream);
740 // pa_stream = NULL;
741 // init_buffer();
742
743 // // #if USE_PORTAUDIO == 18
744 // // active = Pa_StreamActive(pa_stream);
745 // // #else
746 // // active = Pa_IsStreamActive(pa_stream);
747 // // #endif
748 // // if(active == 0)
749 // // {
750 // // SHOW_TIME("WaveCloseSound > ok, not active");
751 // // Pa_CloseStream(pa_stream);
752 // // pa_stream = NULL;
753 // // return(1);
754 // // }
755 // }
756 // return(0);
757 // }
758
759 //<wave_set_callback_is_output_enabled
760
wave_set_callback_is_output_enabled(t_wave_callback * cb)761 void wave_set_callback_is_output_enabled(t_wave_callback* cb)
762 {
763 my_callback_is_output_enabled = cb;
764 }
765
766 //>
767 //<wave_init
768
769 // TBD: the arg could be "alsa", "oss",...
wave_init(int srate)770 int wave_init(int srate)
771 {
772 ENTER("wave_init");
773 PaError err;
774
775 pa_stream = NULL;
776 wave_samplerate = srate;
777 mInCallbackFinishedState = false;
778 init_buffer();
779
780 // PortAudio sound output library
781 err = Pa_Initialize();
782 pa_init_err = err;
783 if(err != paNoError)
784 {
785 SHOW_TIME("wave_init > Failed to initialise the PortAudio sound");
786 }
787 return err == paNoError;
788 }
789
790 //>
791 //<wave_open
792
wave_open(const char * the_api)793 void* wave_open(const char* the_api)
794 {
795 ENTER("wave_open");
796 static int once=0;
797
798 // TBD: the_api (e.g. "alsa") is not used at the moment
799 // select_device is called once
800 if (!once)
801 {
802 select_device("alsa");
803 once=1;
804 }
805 return((void*)1);
806 }
807
808 //>
809 //<copyBuffer
810
811
copyBuffer(char * dest,char * src,const size_t theSizeInBytes)812 static size_t copyBuffer(char* dest, char* src, const size_t theSizeInBytes)
813 {
814 size_t bytes_written = 0;
815 unsigned int i = 0;
816 uint16_t* a_dest = NULL;
817 uint16_t* a_src = NULL;
818
819 if ((src != NULL) && dest != NULL)
820 {
821 // copy for one channel (mono)?
822 if(out_channels==1)
823 {
824 SHOW("copyBuffer > 1 channel > memcpy %x (%d bytes)\n", (int)myWrite, theSizeInBytes);
825 memcpy(dest, src, theSizeInBytes);
826 bytes_written = theSizeInBytes;
827 }
828 else // copy for 2 channels (stereo)
829 {
830 SHOW("copyBuffer > 2 channels > memcpy %x (%d bytes)\n", (int)myWrite, theSizeInBytes);
831 i = 0;
832 a_dest = (uint16_t* )dest;
833 a_src = (uint16_t* )src;
834
835 for(i=0; i<theSizeInBytes/2; i++)
836 {
837 a_dest[2*i] = a_src[i];
838 a_dest[2*i+1] = a_src[i];
839 }
840 bytes_written = 2*theSizeInBytes;
841 } // end if(out_channels==1)
842 } // end if ((src != NULL) && dest != NULL)
843
844 return bytes_written;
845 }
846
847 //>
848 //<wave_write
849
wave_write(void * theHandler,char * theMono16BitsWaveBuffer,size_t theSize)850 size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize)
851 {
852 ENTER("wave_write");
853 size_t bytes_written = 0;
854 // space in ringbuffer for the sample needed: 1x mono channel but 2x for 1 stereo channel
855 size_t bytes_to_write = (out_channels==1) ? theSize : theSize*2;
856 my_stream_could_start = 0;
857
858 if(pa_stream == NULL)
859 {
860 SHOW_TIME("wave_write > wave_open_sound\n");
861 if (0 != wave_open_sound())
862 {
863 SHOW_TIME("wave_write > wave_open_sound fails!");
864 return 0;
865 }
866 my_stream_could_start=1;
867 }
868 else if (!wave_is_busy(NULL))
869 {
870 my_stream_could_start = 1;
871 }
872 assert(BUFFER_LENGTH >= bytes_to_write);
873
874 if (myWrite >= myBuffer + BUFFER_LENGTH)
875 {
876 myWrite = myBuffer;
877 } // end if (myWrite >= myBuffer + BUFFER_LENGTH)
878
879 size_t aTotalFreeMem=0;
880 char* aRead = myRead;
881 SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
882
883 while (1)
884 {
885 if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled()))
886 {
887 SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
888 return 0;
889 }
890
891 aRead = myRead;
892
893 // write pointer is before read pointer?
894 if (myWrite >= aRead)
895 {
896 aTotalFreeMem = aRead + BUFFER_LENGTH - myWrite;
897 }
898 else // read pointer is before write pointer!
899 {
900 aTotalFreeMem = aRead - myWrite;
901 } // end if (myWrite >= aRead)
902
903 if (aTotalFreeMem>1)
904 {
905 // -1 because myWrite must be different of aRead
906 // otherwise buffer would be considered as empty
907 aTotalFreeMem -= 1;
908 } // end if (aTotalFreeMem>1)
909
910 if (aTotalFreeMem >= bytes_to_write)
911 {
912 break;
913 } // end if (aTotalFreeMem >= bytes_to_write)
914
915 //SHOW_TIME("wave_write > wait");
916 SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem);
917 SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
918 usleep(10000);
919 } // end while (1)
920
921 aRead = myRead;
922
923 // write pointer is ahead the read pointer?
924 if (myWrite >= aRead)
925 {
926 SHOW_TIME("wave_write > myWrite >= aRead");
927 // determine remaining free memory to the end of the ringbuffer
928 size_t aFreeMem = myBuffer + BUFFER_LENGTH - myWrite;
929 // is enough linear space available (regardless 1 or 2 channels)?
930 if (aFreeMem >= bytes_to_write)
931 {
932 // copy direct - no wrap around at end of ringbuffer needed
933 myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
934 }
935 else // not enough linear space available
936 {
937 // 2 channels (stereo)?
938 if (out_channels == 2)
939 {
940 // copy with wrap around at the end of ringbuffer
941 copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem/2);
942 myWrite = myBuffer;
943 myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem/2, theSize - aFreeMem/2);
944 }
945 else // 1 channel (mono)
946 {
947 // copy with wrap around at the end of ringbuffer
948 copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem);
949 myWrite = myBuffer;
950 myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, theSize - aFreeMem);
951 } // end if (out_channels == 2)
952 } // end if (aFreeMem >= bytes_to_write)
953 } // if (myWrite >= aRead)
954 else // read pointer is ahead the write pointer
955 {
956 SHOW_TIME("wave_write > myWrite <= aRead");
957 myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
958 } // end if (myWrite >= aRead)
959
960 bytes_written = bytes_to_write;
961 myWritePosition += theSize/sizeof(uint16_t); // add number of samples
962
963 if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
964 {
965 start_stream();
966 } // end if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
967
968 SHOW_TIME("wave_write > LEAVE");
969
970 return bytes_written;
971 }
972
973 //>
974 //<wave_close
975
wave_close(void * theHandler)976 int wave_close(void* theHandler)
977 {
978 SHOW_TIME("wave_close > ENTER");
979
980 static int aStopStreamCount = 0;
981
982 #if (USE_PORTAUDIO == 19)
983 if( pa_stream == NULL )
984 {
985 SHOW_TIME("wave_close > LEAVE (NULL stream)");
986 return 0;
987 }
988
989 if( Pa_IsStreamStopped( pa_stream ) )
990 {
991 SHOW_TIME("wave_close > LEAVE (stopped)");
992 return 0;
993 }
994 #else
995 if( pa_stream == NULL )
996 {
997 SHOW_TIME("wave_close > LEAVE (NULL stream)");
998 return 0;
999 }
1000
1001 if( Pa_StreamActive( pa_stream ) == false && mInCallbackFinishedState == false )
1002 {
1003 SHOW_TIME("wave_close > LEAVE (not active)");
1004 return 0;
1005 }
1006 #endif
1007
1008 // Avoid race condition by making sure this function only
1009 // gets called once at a time
1010 aStopStreamCount++;
1011 if (aStopStreamCount != 1)
1012 {
1013 SHOW_TIME("wave_close > LEAVE (stopStreamCount)");
1014 return 0;
1015 }
1016
1017 // Comment from Audacity-1.2.4b adapted to the eSpeak context.
1018 //
1019 // We got here in one of two ways:
1020 //
1021 // 1. The calling program calls the espeak_Cancel function and we
1022 // therefore want to stop as quickly as possible.
1023 // So we use AbortStream(). If this is
1024 // the case the portaudio stream is still in the Running state
1025 // (see PortAudio state machine docs).
1026 //
1027 // 2. The callback told PortAudio to stop the stream since it had
1028 // reached the end of the selection.
1029 // The event polling thread discovered this by noticing that
1030 // wave_is_busy() returned false.
1031 // wave_is_busy() (which calls Pa_GetStreamActive()) will not return
1032 // false until all buffers have finished playing, so we can call
1033 // AbortStream without losing any samples. If this is the case
1034 // we are in the "callback finished state" (see PortAudio state
1035 // machine docs).
1036 //
1037 // The moral of the story: We can call AbortStream safely, without
1038 // losing samples.
1039 //
1040 // DMM: This doesn't seem to be true; it seems to be necessary to
1041 // call StopStream if the callback brought us here, and AbortStream
1042 // if the user brought us here.
1043 //
1044
1045 #if (USE_PORTAUDIO == 19)
1046 if (pa_stream)
1047 {
1048 Pa_AbortStream( pa_stream );
1049 SHOW_TIME("wave_close > Pa_AbortStream (end)");
1050
1051 Pa_CloseStream( pa_stream );
1052 SHOW_TIME("wave_close > Pa_CloseStream (end)");
1053 pa_stream = NULL;
1054 mInCallbackFinishedState = false;
1055 }
1056 #else
1057 if (pa_stream)
1058 {
1059 if (mInCallbackFinishedState)
1060 {
1061 Pa_StopStream( pa_stream );
1062 SHOW_TIME("wave_close > Pa_StopStream (end)");
1063 }
1064 else
1065 {
1066 Pa_AbortStream( pa_stream );
1067 SHOW_TIME("wave_close > Pa_AbortStream (end)");
1068 }
1069 Pa_CloseStream( pa_stream );
1070 SHOW_TIME("wave_close > Pa_CloseStream (end)");
1071
1072 pa_stream = NULL;
1073 mInCallbackFinishedState = false;
1074 }
1075 #endif
1076 init_buffer();
1077
1078 aStopStreamCount = 0; // last action
1079 SHOW_TIME("wave_close > LEAVE");
1080 return 0;
1081 }
1082
1083 // int wave_close(void* theHandler)
1084 // {
1085 // ENTER("wave_close");
1086
1087 // if(pa_stream != NULL)
1088 // {
1089 // PaError err = Pa_AbortStream(pa_stream);
1090 // SHOW_TIME("wave_close > Pa_AbortStream (end)");
1091 // SHOW("wave_close Pa_AbortStream > err=%d\n",err);
1092 // while(1)
1093 // {
1094 // PaError active;
1095 // #if USE_PORTAUDIO == 18
1096 // active = Pa_StreamActive(pa_stream);
1097 // #else
1098 // active = Pa_IsStreamActive(pa_stream);
1099 // #endif
1100 // if (active != 1)
1101 // {
1102 // break;
1103 // }
1104 // SHOW("wave_close > active=%d\n",err);
1105 // usleep(10000); /* sleep until playback has finished */
1106 // }
1107 // err = Pa_CloseStream( pa_stream );
1108 // SHOW_TIME("wave_close > Pa_CloseStream (end)");
1109 // SHOW("wave_close Pa_CloseStream > err=%d\n",err);
1110 // pa_stream = NULL;
1111 // init_buffer();
1112 // }
1113 // return 0;
1114 // }
1115
1116 //>
1117 //<wave_is_busy
1118
wave_is_busy(void * theHandler)1119 int wave_is_busy(void* theHandler)
1120 {
1121 PaError active=0;
1122
1123 SHOW_TIME("wave_is_busy");
1124
1125 if (pa_stream)
1126 {
1127 #if USE_PORTAUDIO == 18
1128 active = Pa_StreamActive(pa_stream)
1129 && (mInCallbackFinishedState == false);
1130 #else
1131 active = Pa_IsStreamActive(pa_stream)
1132 && (mInCallbackFinishedState == false);
1133 #endif
1134 }
1135
1136 SHOW("wave_is_busy: %d\n",active);
1137
1138
1139 return (active==1);
1140 }
1141
1142 //>
1143 //<wave_terminate
1144
wave_terminate()1145 void wave_terminate()
1146 {
1147 ENTER("wave_terminate");
1148
1149 Pa_Terminate();
1150
1151 }
1152
1153 //>
1154 //<wave_get_read_position, wave_get_write_position, wave_get_remaining_time
1155
wave_get_read_position(void * theHandler)1156 uint32_t wave_get_read_position(void* theHandler)
1157 {
1158 SHOW("wave_get_read_position > myReadPosition=%u\n", myReadPosition);
1159 return myReadPosition;
1160 }
1161
wave_get_write_position(void * theHandler)1162 uint32_t wave_get_write_position(void* theHandler)
1163 {
1164 SHOW("wave_get_write_position > myWritePosition=%u\n", myWritePosition);
1165 return myWritePosition;
1166 }
1167
wave_get_remaining_time(uint32_t sample,uint32_t * time)1168 int wave_get_remaining_time(uint32_t sample, uint32_t* time)
1169 {
1170 double a_time=0;
1171
1172 if (!time || !pa_stream)
1173 {
1174 SHOW("event get_remaining_time> %s\n","audio device not available");
1175 return -1;
1176 }
1177
1178 if (sample > myReadPosition)
1179 {
1180 // TBD: take in account time suplied by portaudio V18 API
1181 a_time = sample - myReadPosition;
1182 a_time = 0.5 + (a_time * 1000.0) / wave_samplerate;
1183 }
1184 else
1185 {
1186 a_time = 0;
1187 }
1188
1189 SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time);
1190
1191 *time = (uint32_t)a_time;
1192
1193 return 0;
1194 }
1195
1196 //>
1197 //<wave_test_get_write_buffer
1198
wave_test_get_write_buffer()1199 void *wave_test_get_write_buffer()
1200 {
1201 return myWrite;
1202 }
1203
1204
1205 #else
1206 // notdef USE_PORTAUDIO
1207
1208
wave_init(int srate)1209 int wave_init(int srate) {return 1;}
wave_open(const char * the_api)1210 void* wave_open(const char* the_api) {return (void *)1;}
wave_write(void * theHandler,char * theMono16BitsWaveBuffer,size_t theSize)1211 size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;}
wave_close(void * theHandler)1212 int wave_close(void* theHandler) {return 0;}
wave_is_busy(void * theHandler)1213 int wave_is_busy(void* theHandler) {return 0;}
wave_terminate()1214 void wave_terminate() {}
wave_get_read_position(void * theHandler)1215 uint32_t wave_get_read_position(void* theHandler) {return 0;}
wave_get_write_position(void * theHandler)1216 uint32_t wave_get_write_position(void* theHandler) {return 0;}
wave_flush(void * theHandler)1217 void wave_flush(void* theHandler) {}
1218 typedef int (t_wave_callback)(void);
wave_set_callback_is_output_enabled(t_wave_callback * cb)1219 void wave_set_callback_is_output_enabled(t_wave_callback* cb) {}
wave_test_get_write_buffer()1220 extern void* wave_test_get_write_buffer() {return NULL;}
1221
wave_get_remaining_time(uint32_t sample,uint32_t * time)1222 int wave_get_remaining_time(uint32_t sample, uint32_t* time)
1223 {
1224 if (!time) return(-1);
1225 *time = (uint32_t)0;
1226 return 0;
1227 }
1228
1229 #endif // of USE_PORTAUDIO
1230
1231 //>
1232 //<clock_gettime2, add_time_in_ms
1233
clock_gettime2(struct timespec * ts)1234 void clock_gettime2(struct timespec *ts)
1235 {
1236 struct timeval tv;
1237
1238 if (!ts)
1239 {
1240 return;
1241 }
1242
1243 assert (gettimeofday(&tv, NULL) != -1);
1244 ts->tv_sec = tv.tv_sec;
1245 ts->tv_nsec = tv.tv_usec*1000;
1246 }
1247
add_time_in_ms(struct timespec * ts,int time_in_ms)1248 void add_time_in_ms(struct timespec *ts, int time_in_ms)
1249 {
1250 if (!ts)
1251 {
1252 return;
1253 }
1254
1255 uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
1256 while(t_ns >= ONE_BILLION)
1257 {
1258 SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
1259 ts->tv_sec += 1;
1260 t_ns -= ONE_BILLION;
1261 }
1262 ts->tv_nsec = (long int)t_ns;
1263 }
1264
1265
1266 #endif // USE_ASYNC
1267
1268 //>
1269