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