1 /*---------------------------------------------------------------------------*
2 * audioin.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20 /* -------------------------------------------------------------------------+
21 | ScanSoft Inc. |
22 + -------------------------------------------------------------------------*/
23
24
25
26 /* -------------------------------------------------------------------------+
27 | Project : ScanSoft AudioIn
28 | Module : audioin
29 | File name : audioin.c
30 | Description : This module contains the main implementation for the audioIn
31 | component.
32 | Reference(s) : wavein, audioout, audioin.chm, audioin.doc, audioin.hlp,
33 | SltGl00001_audioin_gl1.doc
34 | Status : Version 1.2
35 + -------------------------------------------------------------------------*/
36 /* Feb/25/2002: First QNX/SH4 "draft" version. Version 1.1 */
37 /* Nov/25/2004: clean up and minor changes like choice of the codec */
38 /* frame size which is now automatically selected */
39 /*--------------------------------------------------------------------------*/
40
41 #if !defined(ANDROID) || defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_4__)
42
43
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <pthread.h>
50 #include <sched.h>
51 #include <time.h>
52 #include <unistd.h>
53 #include <sys/select.h>
54 #include "plog.h"
55 #include "audioin.h"
56
57 #if defined(ANDROID)
58 #include "audioinwrapper.h"
59 #else
60 #include <alsa/asoundlib.h>
61 #endif
62
63 // #define SAVE_RAW_AUDIO 1
64
65 #ifdef SAVE_RAW_AUDIO
66 #include <sys/time.h>
67 #include <stdio.h>
68
69 static FILE *audio_data;
70 static struct timeval buffer_save_audio;
71 #endif
72
73 /*#define FILTER_ON*/
74
75 #ifdef FILTER_ON
76 #include "filter.h"
77 #endif
78
79 /* -------------------------------------------------------------------------+
80 | EXTERNAL DATA (+ meaning) |
81 + -------------------------------------------------------------------------*/
82
83 /* none */
84
85 /* -------------------------------------------------------------------------+
86 | MACROS |
87 + -------------------------------------------------------------------------*/
88
89 #define NR_OF_CHANNELS 1
90
91 #if defined(ANDROID)
92 /* size in samples */
93 /* We really no longer use this for ANDROID but more changes are needed to remove it. SteveR */
94 #define SAMPLES_BUFFER_SIZE (8*1024)
95 #define SAMPLES_BUFFER_HIGH_WATERMARK (6*1024)
96 #else
97 #define SAMPLES_BUFFER_SIZE (50*4410)
98 #define SAMPLES_BUFFER_HIGH_WATERMARK (40*4410)
99 #endif
100
101 /* IMPORTANT NOTE:
102 Here a "frame" is an ALSA term. A frame is comprised of 1 sample if mono,
103 and 2 samples if stereo. This should be distinguished from what the
104 ASR engine and lhs_audioin*() API functions refer to as a frame which is
105 a set of consecutive samples.
106 (see http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html) */
107 #if defined(ANDROID)
108 #define CODEC_FRAGMENT_SIZE_IN_FRAMES 1024
109 #else
110 //read the equivalent of 100 ms per buffer. Note: we are recording at 44 kHz
111 #define CODEC_FRAGMENT_SIZE_IN_FRAMES 4410
112 #endif
113
114 /* -------------------------------------------------------------------------+
115 | TYPE DEFINITIONS |
116 + -------------------------------------------------------------------------*/
117
118 /* -------------------------------------------------------------------------+
119 | GLOBAL CONSTANTS |
120 + -------------------------------------------------------------------------*/
121
122
123 /* -------------------------------------------------------------------------+
124 | GLOBAL VARIABLES |
125 + -------------------------------------------------------------------------*/
126
127 #if !defined(ANDROID)
128 static snd_pcm_t *ghPCM; /* handle to the PCM recording device */
129 #endif
130
131 static int gCodecFragmentSizeInFrames = CODEC_FRAGMENT_SIZE_IN_FRAMES; /* fragment size used by the codec driver */
132 static audioinSample gSamplesBufferCircularFifo[SAMPLES_BUFFER_SIZE]; /* circular buffer that buffers the incoming samples */
133
134 static int gWriteIndexPointer = 0; /* write pointer in the circular FIFO samples buffer */
135 static int gReadIndexPointer = 0; /* read pointer in the circular FIFO samples buffer */
136 static AUDIOIN_INFO gAudioInInfo; /* to store the info about the acquisition */
137 static pthread_mutex_t gAudioMutex; /* to prevent using the read/write pointers at the same time in both threads */
138
139 static pthread_cond_t gThreadRunning; /* synchronize when the AcquisitionThreadID is running*/
140 static int gThreadRunningSignaled = 0;
141
142 static pthread_cond_t gOpenExCalled; /* synchronize when the lhs_audioinOpenEx is called*/
143 static int gOpenExCalledSignaled = 0;
144
145 static pthread_cond_t gCloseCalled; /* synchronize when the lhs_audioinClose is called*/
146 static int gCloseCalledSignaled = 0;
147
148 static pthread_t AcquisitionThreadID; /* acquisition thread id */
149
150 static int gInitialized = 0; /* did we initialize some of the variables*/
151 static int gTerminateThread = 0;
152 static struct timeval timer; /* timer used by select to relinquish cpu times */
153
154 static int gRecordingVolume = -1; /* recording volume ; number between 0 and 15 */
155 static int bRecord = 0; /* recording state is off */
156 static int bClose = 1; /* audio pipe is closed */
157
158 #ifdef FILTER_ON
159 static FIR_struct *pFIR = NULL; /* pointer to FIR structure */
160 #endif
161
162 #ifdef AUDIOIN_SUPPORT_CALLBACK
163 static pCallbackFunc gpCallback = NULL;
164 static void *gpCallbackInstance = NULL;
165 static unsigned long gnCallbackSamples = 0;
166 #endif
167
168 /* -------------------------------------------------------------------------+
169 | LOCAL FUNCTION PROTOTYPES |
170 + -------------------------------------------------------------------------*/
171
172 static void *AcquisitionThread(void *data); /* Entry function for the acquisition thread */
173 static int OpenAndPrepareSound(unsigned long ulFrequency);
174
175 /**
176 * returns 0 if success
177 */
Initialize(AUDIOIN_H * phAudioIn)178 static int Initialize(AUDIOIN_H * phAudioIn)
179 {
180 int doneWaiting = 0;
181
182 if( gInitialized == 1 )
183 return 0;
184
185 /* creates the mutex that will be used to lock/unlock access to some variables/code */
186 if (pthread_mutex_init(&gAudioMutex, NULL) != 0)
187 {
188 return 1;
189 }
190
191 if(pthread_cond_init(&gThreadRunning, 0) != 0 )
192 {
193 return 1;
194 }
195
196 if(pthread_cond_init(&gOpenExCalled, 0) != 0 )
197 {
198 return 1;
199 }
200
201 if(pthread_cond_init(&gCloseCalled, 0) != 0 )
202 {
203 return 1;
204 }
205
206 pthread_mutex_lock(&gAudioMutex);
207
208 /* create a thread with very high priority that will do the acquisition */
209 if (pthread_create(&AcquisitionThreadID, NULL, AcquisitionThread, phAudioIn) != 0)
210 {
211 return 1;
212 }
213
214 //wait for the thread to run
215 while (!doneWaiting)
216 {
217 int rc = pthread_cond_wait(&gThreadRunning, &gAudioMutex);
218 switch (rc)
219 {
220 case 0:
221 if (!gThreadRunningSignaled)
222 {
223 // Avoid spurious wakeups
224 continue;
225 }
226 else
227 {
228 gThreadRunningSignaled = 0;
229 doneWaiting = 1;
230 break;
231 }
232 break;
233 default:
234 pthread_mutex_unlock(&gAudioMutex);
235 return 1;
236 }
237 }
238
239 pthread_mutex_unlock(&gAudioMutex);
240
241
242 //thread is now running.
243
244 gInitialized = 1;
245
246 return 0;
247 }
248
249 #if 0
250 /* disable this unused function for now until we decide what to do with this */
251
252 /**
253 * returns 0 if success
254 */
255 static int UnInitialize()
256 {
257 //signal the thread that it has to stop running.
258 pthread_mutex_lock ( &gAudioMutex );
259 gTerminateThread = 1;
260
261 //signal to tell that our thread is now running.
262 if ( pthread_cond_signal ( &gOpenExCalled ) != 0 )
263 {
264 pthread_mutex_unlock ( &gAudioMutex );
265 PLogError ( "Audio In Error pthread_cond_signal\n" );
266 return 1;
267 }
268 gOpenExCalledSignaled = 1;
269 pthread_mutex_unlock ( &gAudioMutex );
270
271 /* wait until thread exits */
272 if (pthread_join(AcquisitionThreadID, NULL) != 0)
273 {
274 return 1;
275 }
276
277 /* destroy the mutex */
278 if (pthread_mutex_destroy(&gAudioMutex) !=0 )
279 {
280 return 1;
281 }
282 if( pthread_cond_destroy(&gThreadRunning) != 0 )
283 {
284 return 1;
285 }
286 if( pthread_cond_destroy(&gOpenExCalled) != 0 )
287 {
288 return 1;
289 }
290 if( pthread_cond_destroy(&gCloseCalled) != 0 )
291 {
292 return 1;
293 }
294 gInitialized = 0;
295 return 0;
296 }
297 #endif
298
299 /* -------------------------------------------------------------------------+
300 | LOCAL FUNCTION (should be static) |
301 + -------------------------------------------------------------------------*/
302
setRecordOn(void)303 static void setRecordOn(void)
304 {
305 bRecord = 1;
306 }
307
setRecordOff(void)308 static void setRecordOff(void)
309 {
310 bRecord = 0;
311 }
312
getRecord(void)313 static int getRecord(void)
314 {
315 return bRecord;
316 }
317
setCloseOn(void)318 static void setCloseOn(void)
319 {
320 bClose = 1;
321 }
322
setCloseOff(void)323 static void setCloseOff(void)
324 {
325 bClose = 0;
326 }
327
getClose(void)328 static int getClose(void)
329 {
330 return bClose;
331 }
332
333
334 /**************************************************************
335 * AcquisitionThread *
336 * *
337 * This function is the entry function of a thread created by *
338 * lhs_audioinOpen and which is responsible of getting the *
339 * samples from the codec and store them in a big circular *
340 * FIFO buffer. *
341 * The priority of this thread has been set to high in order *
342 * to prevent codec buffer overrun. Since the FIFO is limited *
343 * in size (5 sec default ; see SAMPLES_BUFFER_SIZE *
344 * parameter), the application must still be fast enough to *
345 * prevent FIFO overflow/overrun *
346 **************************************************************/
347 #if defined(ANDROID)
348
AcquisitionThread(void * data)349 void *AcquisitionThread ( void *data )
350 {
351 int doneWaiting = 0;
352 audioinSample *CodecBuffer;
353 long x;
354 long y;
355 #ifdef AUDIOIN_SUPPORT_CALLBACK
356 AUDIOIN_H *phAudioIn = (AUDIOIN_H *)data;
357 AUDIOIN_WAVEHDR *pwhdr;
358 #endif
359
360
361 pthread_mutex_lock ( &gAudioMutex );
362
363 //signal to tell that our thread is now running.
364 if ( pthread_cond_signal ( &gThreadRunning ) != 0 )
365 {
366 pthread_mutex_unlock ( &gAudioMutex );
367 PLogError ( "Audio In Error pthread_cond_signal\n" );
368 exit ( 1 );
369 }
370 gThreadRunningSignaled = 1;
371
372 while( 1 )
373 {
374
375 while (!doneWaiting)
376 {
377 int rc = pthread_cond_wait(&gOpenExCalled, &gAudioMutex);
378 switch (rc)
379 {
380 case 0:
381 if (!gOpenExCalledSignaled)
382 {
383 // Avoid spurious wakeups
384 continue;
385 }
386 else
387 {
388 gOpenExCalledSignaled = 0;
389 doneWaiting = 1;
390 break;
391 }
392 break;
393 default:
394 PLogError ( "Audio In Error pthread_cond_signal\n" );
395 pthread_mutex_unlock(&gAudioMutex);
396 return ( (void *)NULL );
397 }
398 }
399 doneWaiting = 0;
400 pthread_mutex_unlock(&gAudioMutex);
401
402 if( gTerminateThread == 1 )
403 break;
404
405
406
407 /* buffer of 16 bits samples */
408 CodecBuffer = (audioinSample *)malloc ( gCodecFragmentSizeInFrames * sizeof ( audioinSample ) );
409
410 if ( CodecBuffer == NULL )
411 {
412 PLogError ( "Audio In Error malloc\n" );
413 exit ( 1 );
414 }
415 pwhdr = malloc ( sizeof ( AUDIOIN_WAVEHDR ) );
416
417 if ( pwhdr == NULL )
418 {
419 PLogError ( "Audio In Error malloc\n" );
420 exit ( 1 );
421 }
422
423 while ( !getClose ( ) )
424 {
425
426 int iReadFrames = 0; /* number of frames acquired by the codec */
427 /* NOTE: here a frame is comprised of 1 sample if mono, 2 samples if stereo, etc */
428 int iReadSamples = 0; /* number of samples acquired by the codec */
429 int frames_to_read; /* Actual number to read */
430 int frames_read; /* Frames read on one read */
431
432 iReadFrames = 0;
433
434 do
435 {
436 frames_to_read = gCodecFragmentSizeInFrames - iReadFrames;
437 /* AudioRead() - output: number of frames (mono: 1 sample, stereo: 2 samples)*/
438 frames_read = AudioRead ( CodecBuffer + iReadFrames, frames_to_read );
439
440 if ( frames_read > 0 )
441 iReadFrames += frames_read;
442 }
443 while ( ( iReadFrames < gCodecFragmentSizeInFrames ) && ( frames_read > 0 ) );
444 iReadSamples = iReadFrames;
445
446 if ( getRecord ( ) ) /* else continue to read from driver but discard samples */
447 {
448 if ( iReadSamples < 0 )
449 {
450 iReadSamples = 0;
451 gAudioInInfo.eStatusInfo = AUDIOIN_HWOVERRUN;
452 }
453 else
454 {
455 #ifdef FILTER_ON
456 /* x: index for start of input samples; y: index for output sample */
457 for ( x = 0, y = 0; x < iReadSamples; x += pFIR->factor_down )
458 {
459 FIR_downsample ( pFIR->factor_down, &( CodecBuffer[x] ), &( CodecBuffer[y++] ), pFIR );
460 }
461 /* update the number samples */
462 iReadSamples = y;
463 #endif
464 pthread_mutex_lock ( &gAudioMutex );
465
466 if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_SIZE )
467 {
468 gAudioInInfo.u32SamplesAvailable = SAMPLES_BUFFER_SIZE;
469 gAudioInInfo.eStatusInfo = AUDIOIN_FIFOOVERRUN;
470 }
471 else
472 {
473 if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_HIGH_WATERMARK )
474 {
475 gAudioInInfo.eStatusInfo = AUDIOIN_HIGHWATERMARK;
476 }
477 else if ( gAudioInInfo.eStatusInfo != AUDIOIN_FIFOOVERRUN )
478 {
479 gAudioInInfo.eStatusInfo = AUDIOIN_NORMAL;
480 }
481 gAudioInInfo.u32SamplesAvailable += iReadSamples;
482 }
483 if ( gWriteIndexPointer + iReadSamples <= SAMPLES_BUFFER_SIZE )
484 {
485 memcpy ( &( gSamplesBufferCircularFifo[gWriteIndexPointer] ), CodecBuffer,
486 iReadSamples * sizeof ( audioinSample ) );
487 gWriteIndexPointer += iReadSamples;
488
489 if ( gWriteIndexPointer >= SAMPLES_BUFFER_SIZE )
490 gWriteIndexPointer = 0;
491 }
492 else
493 {
494 int NbToCopy;
495
496 NbToCopy = SAMPLES_BUFFER_SIZE - gWriteIndexPointer;
497 memcpy ( &( gSamplesBufferCircularFifo [gWriteIndexPointer] ), CodecBuffer,
498 NbToCopy * sizeof ( audioinSample ) );
499 gWriteIndexPointer = 0;
500 memcpy ( gSamplesBufferCircularFifo, &( CodecBuffer [NbToCopy] ),
501 ( iReadSamples-NbToCopy ) * sizeof ( audioinSample ) );
502 gWriteIndexPointer = iReadSamples - NbToCopy;
503 }
504
505 #ifdef AUDIOIN_SUPPORT_CALLBACK
506 /* Callback notification. Ideally this audio acquisition thread should be very lean.
507 It should simply read from the low level driver, store the filtered samples in
508 the FIFO, then go back to reading from the driver. The additional data copy
509 for the callback function is ok despite the overhead incurred, but only because
510 there's some buffering done by the low level driver. This design should be
511 revisited to make it more general purpose.
512 */
513 if ( gpCallback != NULL )
514 {
515 pwhdr->nBufferLength = iReadSamples * sizeof ( audioinSample );
516 pwhdr->nBytesRecorded = pwhdr->nBufferLength;
517 pwhdr->status = AUDIOIN_NORMAL;
518 pwhdr->pData = CodecBuffer;
519 /* pass samples to callback function who should deallocate the buffer and structure */
520 gpCallback ( *phAudioIn, AUDIOIN_MSG_DATA, gpCallbackInstance, pwhdr, NULL );
521 }
522 #endif
523 /* samples are available to read */
524 pthread_mutex_unlock ( &gAudioMutex );
525 timer.tv_sec = 0;
526 timer.tv_usec = 200;
527 select ( 0, NULL, NULL, NULL, &timer );
528 }
529 } /* if (getRecord()) */
530
531 } /* while (!getClose()) */
532 if ( AudioClose ( ) !=0 )
533 {
534 PLogError ( "Audio In Error Closing Hardware\n" );
535 }
536 free ( CodecBuffer );
537
538 pthread_mutex_lock ( &gAudioMutex );
539 //signal to tell that our thread is now running.
540 if ( pthread_cond_signal ( &gCloseCalled ) != 0 )
541 {
542 pthread_mutex_unlock ( &gAudioMutex );
543 PLogError ( "Audio In Error pthread_cond_signal\n" );
544 exit ( 1 );
545 }
546 gCloseCalledSignaled = 1;
547 }
548
549 pthread_exit ( (void *)NULL );
550 return ( (void *)NULL );
551 }
552
553 #else
554 /* non-ANDROID version */
555
AcquisitionThread(void * data)556 void *AcquisitionThread ( void *data )
557 {
558 int doneWaiting = 0;
559 audioinSample *CodecBuffer;
560 #ifdef FILTER_ON
561 long x;
562 long y;
563 #endif
564 #ifdef AUDIOIN_SUPPORT_CALLBACK
565 AUDIOIN_H *phAudioIn = (AUDIOIN_H *)data;
566 #endif
567
568 pthread_mutex_lock ( &gAudioMutex );
569
570 //signal to tell that our thread is now running.
571 if ( pthread_cond_signal ( &gThreadRunning ) != 0 )
572 {
573 pthread_mutex_unlock ( &gAudioMutex );
574 PLogError ( "Audio In Error pthread_cond_signal\n" );
575 exit ( 1 );
576 }
577 gThreadRunningSignaled = 1;
578
579 while( 1 )
580 {
581 while (!doneWaiting)
582 {
583 int rc = pthread_cond_wait(&gOpenExCalled, &gAudioMutex);
584 switch (rc)
585 {
586 case 0:
587 if (!gOpenExCalledSignaled)
588 {
589 // Avoid spurious wakeups
590 continue;
591 }
592 else
593 {
594 gOpenExCalledSignaled = 0;
595 doneWaiting = 1;
596 break;
597 }
598 break;
599 default:
600 PLogError ( "Audio In Error pthread_cond_wait\n" );
601 pthread_mutex_unlock(&gAudioMutex);
602 return ( (void *)NULL );
603 }
604 }
605 doneWaiting = 0;
606 pthread_mutex_unlock(&gAudioMutex);
607
608 if( gTerminateThread == 1 )
609 break;
610
611 /* buffer of 16 bits samples */
612 CodecBuffer = (audioinSample *)malloc ( gCodecFragmentSizeInFrames * sizeof ( audioinSample ) );
613
614 if ( CodecBuffer == NULL )
615 {
616 PLogError ( "Audio In Error pthread_cond_signal\n" );
617 exit ( 1 );
618 }
619
620 while ( !getClose ( ) )
621 {
622 int iReadFrames = 0; /* number of frames acquired by the codec */
623 /* NOTE: here a frame is comprised of 1 sample if mono, 2 samples if stereo, etc */
624 int iReadSamples = 0; /* number of samples acquired by the codec */
625 if ( ( iReadFrames = snd_pcm_readi ( ghPCM, (void *)CodecBuffer, gCodecFragmentSizeInFrames ) ) < 0 )
626 {
627 if ( iReadFrames == -EBADFD )
628 {
629 PLogError ( "Audio In Error PCM Not In The Right State\n" );
630 }
631 else if ( iReadFrames == -EPIPE )
632 {
633 snd_pcm_prepare(ghPCM);
634 PLogError ( "Audio In Error Overrun\n" );
635 }
636 else if ( iReadFrames == -ESTRPIPE )
637 {
638 PLogError ( "Audio In Error Stream Suspended\n" );
639 }
640 }
641 iReadSamples = iReadFrames;
642
643 if ( getRecord ( ) ) /* else continue to read from driver but discard samples */
644 {
645 if ( iReadSamples < 0 )
646 {
647 iReadSamples = 0;
648 gAudioInInfo.eStatusInfo = AUDIOIN_HWOVERRUN;
649 }
650 else
651 {
652 #ifdef FILTER_ON
653 /* x: index for start of input samples; y: index for output sample */
654 for ( x = 0, y = 0; x < iReadSamples; x += pFIR->factor_down )
655 {
656 FIR_downsample ( pFIR->factor_down, &( CodecBuffer[x] ), &( CodecBuffer[y++] ), pFIR );
657 }
658 /* update the number samples */
659 iReadSamples = y;
660 #endif
661 #ifdef SAVE_RAW_AUDIO
662 if ( iReadSamples > 0 )
663 fwrite ( CodecBuffer, 2, iReadSamples, audio_data );
664 #endif
665
666 pthread_mutex_lock ( &gAudioMutex );
667
668 if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_SIZE )
669 {
670 gAudioInInfo.u32SamplesAvailable = SAMPLES_BUFFER_SIZE;
671 gAudioInInfo.eStatusInfo = AUDIOIN_FIFOOVERRUN;
672 }
673 else
674 {
675 if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_HIGH_WATERMARK )
676 {
677 gAudioInInfo.eStatusInfo = AUDIOIN_HIGHWATERMARK;
678 }
679 else if ( gAudioInInfo.eStatusInfo != AUDIOIN_FIFOOVERRUN )
680 {
681 gAudioInInfo.eStatusInfo = AUDIOIN_NORMAL;
682 }
683 gAudioInInfo.u32SamplesAvailable += iReadSamples;
684 }
685 if ( gWriteIndexPointer + iReadSamples <= SAMPLES_BUFFER_SIZE )
686 {
687 memcpy ( &( gSamplesBufferCircularFifo[gWriteIndexPointer] ), CodecBuffer,
688 iReadSamples * sizeof ( audioinSample ) );
689 gWriteIndexPointer += iReadSamples;
690
691 if ( gWriteIndexPointer >= SAMPLES_BUFFER_SIZE )
692 gWriteIndexPointer = 0;
693 }
694 else
695 {
696 int NbToCopy;
697
698 NbToCopy = SAMPLES_BUFFER_SIZE - gWriteIndexPointer;
699 memcpy ( &( gSamplesBufferCircularFifo [gWriteIndexPointer] ), CodecBuffer,
700 NbToCopy * sizeof ( audioinSample ) );
701 gWriteIndexPointer = 0;
702 memcpy ( gSamplesBufferCircularFifo, &( CodecBuffer [NbToCopy] ),
703 ( iReadSamples-NbToCopy ) * sizeof ( audioinSample ) );
704 gWriteIndexPointer = iReadSamples - NbToCopy;
705 }
706 #ifdef AUDIOIN_SUPPORT_CALLBACK
707 /* Callback notification. Ideally this audio acquisition thread should be very lean.
708 It should simply read from the low level driver, store the filtered samples in
709 the FIFO, then go back to reading from the driver. The additional data copy
710 for the callback function is ok despite the overhead incurred, but only because
711 there's some buffering done by the low level driver. This design should be
712 revisited to make it more general purpose.
713 */
714 while ( ( gpCallback != NULL ) && ( gAudioInInfo.u32SamplesAvailable >= gnCallbackSamples ) )
715 {
716 AUDIOIN_WAVEHDR *pwhdr;
717
718 pwhdr = malloc ( sizeof ( AUDIOIN_WAVEHDR ) );
719
720 if ( pwhdr != NULL )
721 {
722 pwhdr->nBufferLength = gnCallbackSamples * sizeof ( audioinSample );
723 pwhdr->nBytesRecorded = pwhdr->nBufferLength;
724 pwhdr->status = gAudioInInfo.eStatusInfo;
725 pwhdr->pData = malloc ( pwhdr->nBufferLength );
726
727 if ( pwhdr->pData != NULL )
728 {
729 if ( gReadIndexPointer + gnCallbackSamples <= SAMPLES_BUFFER_SIZE )
730 {
731 memcpy ( pwhdr->pData, &( gSamplesBufferCircularFifo [gReadIndexPointer] ),
732 pwhdr->nBufferLength );
733 gReadIndexPointer += gnCallbackSamples;
734
735 if ( gReadIndexPointer >= SAMPLES_BUFFER_SIZE )
736 gReadIndexPointer = 0;
737 }
738 else
739 {
740 size_t nSamplesPart1 = SAMPLES_BUFFER_SIZE - gReadIndexPointer;
741 size_t nSamplesPart2 = gnCallbackSamples - nSamplesPart1;
742
743 memcpy ( pwhdr->pData, &( gSamplesBufferCircularFifo [gReadIndexPointer] ),
744 nSamplesPart1*sizeof ( audioinSample ) );
745 gReadIndexPointer = 0;
746 memcpy ( pwhdr->pData + nSamplesPart1 * sizeof (audioinSample ),
747 gSamplesBufferCircularFifo, nSamplesPart2 * sizeof ( audioinSample ) );
748 gReadIndexPointer = nSamplesPart2;
749 }
750 gAudioInInfo.u32SamplesAvailable -= gnCallbackSamples;
751 /* pass samples to callback function who should deallocate the buffer and structure */
752 gpCallback ( *phAudioIn, AUDIOIN_MSG_DATA, gpCallbackInstance, pwhdr, NULL );
753 }
754 else
755 {
756 // error
757 }
758 }
759 else
760 {
761 // error
762 }
763 }
764 #endif
765 /* samples are available to read */
766 pthread_mutex_unlock ( &gAudioMutex );
767 timer.tv_sec = 0;
768 timer.tv_usec = 200;
769 select ( 0, NULL, NULL, NULL, &timer );
770 }
771 } /* if (getRecord()) */
772
773 } /* while (!getClose()) */
774
775 if ( snd_pcm_close ( ghPCM ) !=0 )
776 {
777 PLogError ( "Audio In Error Closing Hardware\n" );
778 }
779
780 free ( CodecBuffer );
781
782 pthread_mutex_lock ( &gAudioMutex );
783 //signal to tell that our thread is now running.
784 if ( pthread_cond_signal ( &gCloseCalled ) != 0 )
785 {
786 pthread_mutex_unlock ( &gAudioMutex );
787 PLogError ( "Audio In Error pthread_cond_signal\n" );
788 exit ( 1 );
789 }
790 gCloseCalledSignaled = 1;
791 }
792 pthread_exit ( (void *)NULL );
793 return ( (void *)NULL );
794 }
795 #endif
796
797 /**************************************************************
798 * OpenAndPrepareSound *
799 *************************************************************/
800
801
OpenAndPrepareSound(unsigned long ulFrequency)802 static int OpenAndPrepareSound(unsigned long ulFrequency)
803 {
804 #if defined(ANDROID)
805
806 /* Only support certain frequencies. Modify this to check frequency
807 against a structure of valid frequencies */
808 #ifdef FILTER_ON
809 if ( ulFrequency == 11025 )
810 {
811 if ( AudioSetInputFormat ( 44100, NR_OF_CHANNELS ) != 0 ) /* sample at 44100 then downsample */
812 {
813 PLogError ( "Audio In Error OpenAndPrepareSound - AudioSetInputFormat failed!\n");
814 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
815 }
816 }
817 else
818 {
819 PLogError ( "Audio In Error OpenAndPrepareSound - invalid frequency!");
820 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
821 }
822 #else
823 if ( ( ulFrequency == 11025 ) || ( ulFrequency == 8000 ) )
824 {
825 if ( AudioSetInputFormat ( ulFrequency, NR_OF_CHANNELS ) != 0 )
826 {
827 PLogError ( "Audio In Error OpenAndPrepareSound - AudioSetInputFormat failed!");
828 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
829 }
830 }
831 else
832 {
833 PLogError ( "Audio In Error OpenAndPrepareSound - invalid frequency!");
834 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
835 }
836 #endif
837
838 /* set some variables */
839 gAudioInInfo.u32SamplesAvailable = 0;
840
841 /* Open Audio driver */
842 if (AudioOpen() < 0)
843 {
844 PLogError ( "Audio In Error OpenAndPrepareSound - AudioOpen failed!");
845 return ~LHS_AUDIOIN_OK;
846 }
847
848 #else
849
850 snd_pcm_hw_params_t *hwparams;
851 unsigned int exact_rate;
852 int dir;
853 int rc;
854
855 /* step 1 : open the sound device */
856 /* ------------------------------ */
857 if ((rc = snd_pcm_open(&ghPCM, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0)
858 {
859 PLogError ( "Audio In Error snd_pcm_open() (rc = %d: %s)\n", rc, snd_strerror(rc));
860 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
861 }
862
863 if ((rc = snd_pcm_hw_params_malloc(&hwparams)) < 0)
864 {
865 PLogError ( "Audio In Error snd_pcm_hw_params_malloc() (rc = %d: %s)\n", rc, snd_strerror(rc));
866 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
867 }
868
869 /* step 2 : configuring the audio channel */
870 /* -------------------------------------- */
871
872 if ((rc = snd_pcm_hw_params_any(ghPCM, hwparams)) < 0)
873 {
874 PLogError ( "Audio In Error snd_pcm_hw_params_any() (rc = %d: %s)\n", rc, snd_strerror(rc));
875 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
876 }
877
878 if ((rc = snd_pcm_hw_params_set_access(ghPCM, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
879 {
880 PLogError ( "Audio In Error snd_pcm_hw_params_set_access() (rc = %d: %s)\n", rc, snd_strerror(rc));
881 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
882 }
883
884 if ((rc = snd_pcm_hw_params_set_format(ghPCM, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
885 {
886 PLogError ( "Audio In Error snd_pcm_hw_params_set_format() (rc = %d: %s)\n", rc, snd_strerror(rc));
887 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
888 }
889
890 #ifdef FILTER_ON
891 if (ulFrequency == 11025)
892 {
893 exact_rate = 44100;
894 }
895 else
896 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
897 #else
898 exact_rate = ulFrequency;
899 #endif
900
901 dir = 0;
902
903 #if 0
904 /* This version seems to have problems when the code is compiled into a shared library.
905 The subsequent call to snd_pcm_hw_params() fails. */
906 if ((rc = snd_pcm_hw_params_set_rate_near(ghPCM, hwparams, &exact_rate, &dir)) < 0)
907 {
908 PLogError ( "Audio In Error snd_pcm_hw_params_set_rate_near() (rc = %d: %s)\n", rc, snd_strerror(rc));
909 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
910 }
911 #else
912 /* This version works better and in fact makes more sense. */
913 if ((rc = snd_pcm_hw_params_set_rate(ghPCM, hwparams, exact_rate, dir)) < 0)
914 {
915 PLogError ( "Audio In Error snd_pcm_hw_params_set_rate() (rc = %d: %s)\n", rc, snd_strerror(rc));
916 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
917 }
918 #endif
919
920
921 if ((rc = snd_pcm_hw_params_set_channels(ghPCM, hwparams, NR_OF_CHANNELS)) < 0)
922 {
923 PLogError ( "Audio In Error snd_pcm_hw_params_set_channels() (rc = %d: %s)\n", rc, snd_strerror(rc));
924 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
925 }
926
927 if ((rc = snd_pcm_hw_params(ghPCM, hwparams)) < 0)
928 {
929 PLogError ( "Audio In Error snd_pcm_hw_params() (rc = %d: %s)\n", rc, snd_strerror(rc));
930 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
931 }
932
933 /* step 3 : preparing for read */
934 /* --------------------------- */
935
936 /*prepare the channel */
937
938 if ((rc = snd_pcm_prepare(ghPCM)) < 0)
939 {
940 PLogError ( "Audio In Error snd_pcm_prepare() (rc = %d: %s)\n", rc, snd_strerror(rc));
941 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
942 }
943
944 /* set some variables */
945 gAudioInInfo.u32SamplesAvailable = 0;
946
947
948 #endif
949
950 /* prepare to read samples */
951 setCloseOff();
952
953 return 0;
954 }
955
956
957 /* -------------------------------------------------------------------------+
958 | GLOBAL FUNCTIONS (prototypes in header file) |
959 + -------------------------------------------------------------------------*/
960
961 /**************************************************************
962 * lhs_audioinOpenEx *
963 * *
964 * notes : *
965 * -the input parameters are in fact not used but present *
966 * to ensure compatibility with Win32 implementations *
967 **************************************************************/
lhs_audioinOpenEx(unsigned long u32AudioInID,unsigned long u32Frequency,unsigned long u32NbrOfFrames,unsigned long u32SamplesPerFrame,AUDIOIN_H * phAudioIn)968 LHS_AUDIOIN_ERROR lhs_audioinOpenEx (
969 unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available
970 devices on the system). You can also use the following flag
971 instead of a device identifier.
972 <nl><nl><bold WAVE_MAPPER> = The function selects a
973 waveform-audio input device capable of recording in the
974 specified format. <bold Header:> Declared in Mmsystem.h from
975 the Windows Multimedia: Platform SDK.*/
976 unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */
977 unsigned long u32NbrOfFrames, /*@parm [in] Number of frames buffered internally. */
978 unsigned long u32SamplesPerFrame, /*@parm [in] Size, in samples, of each individual frame. */
979 AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */
980 )
981 {
982 //initialize some of the static variables.
983 if( Initialize(phAudioIn) )
984 return ~LHS_AUDIOIN_OK;
985
986
987 /* prepare sound */
988 if (OpenAndPrepareSound(u32Frequency) != 0)
989 {
990 return LHS_E_AUDIOIN_COULDNOTOPENDEVICE;
991 }
992
993 //signal the thread that it has to stop running.
994 pthread_mutex_lock ( &gAudioMutex );
995 //signal to tell that our thread is now running.
996 if ( pthread_cond_signal ( &gOpenExCalled ) != 0 )
997 {
998 pthread_mutex_unlock ( &gAudioMutex );
999 PLogError ( "Audio In Error pthread_cond_signal\n" );
1000 exit ( 1 );
1001 }
1002 gOpenExCalledSignaled = 1;
1003 pthread_mutex_unlock ( &gAudioMutex );
1004
1005 #ifdef FILTER_ON
1006 /* need to make this more generic to support different filters */
1007 pFIR = FIR_construct(filter_length, ps16FilterCoeff_up1_down4, u16ScaleFilterCoeff_up1_down4, FACTOR_UP, FACTOR_DOWN);
1008 if (pFIR == NULL)
1009 {
1010 // TO DO: HANDLE THIS (or modify for static allocation)
1011 }
1012 #endif
1013
1014 /* set the status to normal */
1015 gAudioInInfo.eStatusInfo = AUDIOIN_NORMAL;
1016
1017 /* do not care, but some applications are checking a NULL handle */
1018 *phAudioIn = (void *)10;
1019
1020 #ifdef AUDIOIN_SUPPORT_CALLBACK
1021 gpCallback = NULL;
1022 gpCallbackInstance = NULL;
1023 gnCallbackSamples = 0;
1024 #endif
1025
1026 return LHS_AUDIOIN_OK;
1027 }
1028
1029 /**************************************************************
1030 * lhs_audioinOpen *
1031 * *
1032 * notes : *
1033 * -the input parameters are in fact not used but present *
1034 * to ensure compatibility with Win32 implementation *
1035 **************************************************************/
lhs_audioinOpen(unsigned long u32AudioInID,unsigned long u32Frequency,AUDIOIN_H * phAudioIn)1036 LHS_AUDIOIN_ERROR lhs_audioinOpen (
1037 unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available
1038 devices on the system). You can also use the following flag
1039 instead of a device identifier.
1040 <nl><nl><bold WAVE_MAPPER> = The function selects a
1041 waveform-audio input device capable of recording in the
1042 specified format. <bold Header:> Declared in Mmsystem.h from
1043 the Windows Multimedia: Platform SDK.*/
1044 unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */
1045 AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */
1046 )
1047 {
1048 return lhs_audioinOpenEx(u32AudioInID, u32Frequency, 0, 0, phAudioIn);
1049 } /* lhs_audioinOpen */
1050
1051 #ifdef AUDIOIN_SUPPORT_CALLBACK
1052 /**************************************************************
1053 * lhs_audioinOpenCallback *
1054 * *
1055 * notes : *
1056 * -the input parameters are in fact not used but present *
1057 * to ensure compatibility with Win32 implementation *
1058 **************************************************************/
lhs_audioinOpenCallback(unsigned long u32AudioInID,unsigned long u32Frequency,unsigned long u32NbrOfSamples,pCallbackFunc pCallback,void * pCallbackInstance,AUDIOIN_H * phAudioIn)1059 LHS_AUDIOIN_ERROR lhs_audioinOpenCallback (
1060 unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available
1061 devices on the system). You can also use the following flag
1062 instead of a device identifier.
1063 <nl><nl><bold WAVE_MAPPER> = The function selects a
1064 waveform-audio input device capable of recording in the
1065 specified format. <bold Header:> Declared in Mmsystem.h from
1066 the Windows Multimedia: Platform SDK.*/
1067 unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */
1068 unsigned long u32NbrOfSamples, /*@parm [in] <nl><bold Input:> Number of samples requested per callback */
1069 pCallbackFunc pCallback, /*@parm [in] callback function */
1070 void *pCallbackInstance, /*@parm [in] callback instance */
1071 AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */
1072 )
1073 {
1074 LHS_AUDIOIN_ERROR lhsErr;
1075
1076 #ifdef FILTER_ON
1077 gCodecFragmentSizeInFrames = u32NbrOfSamples * 4;
1078 #else
1079 gCodecFragmentSizeInFrames = u32NbrOfSamples;
1080 #endif
1081
1082 if ((pCallback == NULL) || (u32NbrOfSamples == 0))
1083 {
1084 return LHS_E_AUDIOIN_INVALIDARG;
1085 }
1086 lhsErr = lhs_audioinOpenEx(u32AudioInID, u32Frequency, 0, 0, phAudioIn);
1087 if (lhsErr != LHS_AUDIOIN_OK)
1088 {
1089 return lhsErr;
1090 }
1091
1092 /* install callback */
1093 gpCallback = pCallback;
1094 gpCallbackInstance = pCallbackInstance;
1095 gnCallbackSamples = u32NbrOfSamples;
1096
1097 /* callback notification */
1098 gpCallback(*phAudioIn, AUDIOIN_MSG_OPEN, gpCallbackInstance, NULL, NULL);
1099
1100 return LHS_AUDIOIN_OK;
1101
1102 } /* lhs_audioinOpenCallback */
1103 #endif
1104
1105 /**************************************************************
1106 * lhs_audioinClose *
1107 * *
1108 * notes : *
1109 * -the input parameters are in fact not used but present *
1110 * to ensure compatibility with Win32 implementations *
1111 **************************************************************/
1112
lhs_audioinClose(AUDIOIN_H * phAudioIn)1113 LHS_AUDIOIN_ERROR lhs_audioinClose(AUDIOIN_H *phAudioIn)
1114 {
1115 int doneWaiting = 0;
1116
1117 /* Validate the handle */
1118 if ((phAudioIn == NULL) || (*phAudioIn == NULL))
1119 {
1120 return LHS_E_AUDIOIN_NULLPOINTER;
1121 }
1122
1123 /* stop recording audio samples */
1124 setRecordOff();
1125
1126 /* stop reading audio samples */
1127 setCloseOn();
1128
1129 //wait for the thread to stop reading samples.
1130 pthread_mutex_lock ( &gAudioMutex );
1131
1132 while (!doneWaiting)
1133 {
1134 int rc = pthread_cond_wait(&gCloseCalled, &gAudioMutex);
1135 switch (rc)
1136 {
1137 case 0:
1138 if (!gCloseCalledSignaled)
1139 {
1140 // Avoid spurious wakeups
1141 continue;
1142 }
1143 else
1144 {
1145 gCloseCalledSignaled = 0;
1146 doneWaiting = 1;
1147 break;
1148 }
1149 break;
1150 default:
1151 PLogError ( "Audio In Error pthread_cond_wait\n" );
1152 pthread_mutex_unlock(&gAudioMutex);
1153 return ~LHS_AUDIOIN_OK;
1154 }
1155 }
1156 pthread_mutex_unlock(&gAudioMutex);
1157
1158 #ifdef FILTER_ON
1159 FIR_deconstruct(pFIR);
1160 #endif
1161
1162 #ifdef AUDIOIN_SUPPORT_CALLBACK
1163 /* callback notification */
1164 if (gpCallback != NULL) gpCallback(*phAudioIn, AUDIOIN_MSG_CLOSE, gpCallbackInstance, NULL, NULL);
1165 #endif
1166
1167 return LHS_AUDIOIN_OK;
1168 }
1169
1170 /**************************************************************
1171 * lhs_audioinStart *
1172 * *
1173 * notes : *
1174 * -the input parameters are in fact not used but present *
1175 * to ensure compatibility with Win32 implementations *
1176 * -in fact the recording is never stopped or started, when *
1177 * non in 'start' status, the samples are just ignored *
1178 **************************************************************/
1179
lhs_audioinStart(AUDIOIN_H hAudioIn)1180 LHS_AUDIOIN_ERROR lhs_audioinStart(AUDIOIN_H hAudioIn)
1181 {
1182 #ifdef SAVE_RAW_AUDIO
1183 char file_name [256];
1184
1185 gettimeofday ( &buffer_save_audio, NULL );
1186 sprintf ( file_name, "data_%ld_%ld.raw", buffer_save_audio.tv_sec, buffer_save_audio.tv_usec );
1187 audio_data = fopen ( file_name, "w" );
1188 #endif
1189 if (hAudioIn == NULL)
1190 {
1191 return LHS_E_AUDIOIN_NULLPOINTER;
1192 }
1193
1194 pthread_mutex_lock ( &gAudioMutex );
1195
1196 #ifdef FILTER_ON
1197 FIR_reset(pFIR);
1198 #endif
1199
1200 gWriteIndexPointer = 0;
1201 gReadIndexPointer = 0;
1202 gAudioInInfo.u32SamplesAvailable = 0;
1203
1204 /* start recording */
1205 setRecordOn();
1206
1207 #ifdef AUDIOIN_SUPPORT_CALLBACK
1208 /* callback notification */
1209 if (gpCallback != NULL) gpCallback(hAudioIn, AUDIOIN_MSG_START, gpCallbackInstance, NULL, NULL);
1210 #endif
1211 pthread_mutex_unlock ( &gAudioMutex );
1212
1213 return LHS_AUDIOIN_OK;
1214 }
1215
1216 /**************************************************************
1217 * lhs_audioinStop *
1218 * *
1219 * notes : *
1220 * -the input parameters are in fact not used but present *
1221 * to ensure compatibility with Win32 implementations *
1222 * -in fact the recording is never stopped or started, when *
1223 * non in 'start' status, the samples are just ignored *
1224 **************************************************************/
1225
lhs_audioinStop(AUDIOIN_H hAudioIn)1226 LHS_AUDIOIN_ERROR lhs_audioinStop(AUDIOIN_H hAudioIn)
1227 {
1228 #ifdef SAVE_RAW_AUDIO
1229 fclose ( audio_data );
1230 #endif
1231 if (hAudioIn == NULL)
1232 {
1233 return LHS_E_AUDIOIN_NULLPOINTER;
1234 }
1235 pthread_mutex_lock ( &gAudioMutex );
1236
1237 /* stop recording (discard samples) */
1238 setRecordOff();
1239
1240 #ifdef AUDIOIN_SUPPORT_CALLBACK
1241 /* callback notification */
1242 if (gpCallback != NULL) gpCallback(hAudioIn, AUDIOIN_MSG_STOP, gpCallbackInstance, NULL, NULL);
1243 #endif
1244 pthread_mutex_unlock ( &gAudioMutex );
1245
1246 return LHS_AUDIOIN_OK;
1247 }
1248
1249 /**************************************************************
1250 * lhs_audioinGetSamples *
1251 * *
1252 * notes : *
1253 **************************************************************/
1254
lhs_audioinGetSamples(AUDIOIN_H hAudioIn,unsigned long * u32NbrOfSamples,void * pAudioBuffer,AUDIOIN_INFO * pgAudioInInfo)1255 LHS_AUDIOIN_ERROR lhs_audioinGetSamples(AUDIOIN_H hAudioIn, unsigned long * u32NbrOfSamples, void * pAudioBuffer, AUDIOIN_INFO * pgAudioInInfo)
1256 {
1257 unsigned long cSamples;
1258 //unsigned long nToCopy;
1259
1260 /* Check if the handle is valid */
1261 if (hAudioIn == NULL)
1262 {
1263 return LHS_E_AUDIOIN_NULLPOINTER;
1264 }
1265
1266 cSamples = 0;
1267
1268 while (1)
1269 {
1270 /* wait until we have enough samples */
1271 if (*u32NbrOfSamples <= gAudioInInfo.u32SamplesAvailable)
1272 {
1273 /* lock the code to prevent dual access to some variables */
1274 pthread_mutex_lock(&gAudioMutex);
1275
1276 /* TO DO: consider copying in chunks (like in AquisitionThread)
1277 rather than 1 sample at a time. */
1278
1279 /* copy all samples into the input buffer */
1280 while ((cSamples < *u32NbrOfSamples))
1281 {
1282 ((audioinSample *)pAudioBuffer)[cSamples++] = gSamplesBufferCircularFifo[gReadIndexPointer++];
1283
1284 /* adapt the parameters */
1285 gAudioInInfo.u32SamplesAvailable -= 1;
1286
1287 /* adapt circular buffer */
1288 if (gReadIndexPointer >= SAMPLES_BUFFER_SIZE)
1289 {
1290 gReadIndexPointer = 0;
1291 }
1292
1293 /* enough samples */
1294 if (cSamples == *u32NbrOfSamples)
1295 {
1296 /* return the audioin info structure */
1297 memcpy(pgAudioInInfo, &gAudioInInfo, sizeof(AUDIOIN_INFO));
1298 pthread_mutex_unlock(&gAudioMutex);
1299 return LHS_AUDIOIN_OK;
1300 }
1301 }
1302 }
1303 else
1304 {
1305 /* relinquish CPU. select() is more reliable than usleep(). */
1306 timer.tv_sec = 0;
1307 timer.tv_usec = 10000;
1308 select(0, NULL, NULL, NULL, &timer);
1309 }
1310 } /* while (1) */
1311 }
1312
1313 /**************************************************************
1314 * lhs_audioinGetVersion *
1315 * *
1316 * notes : not implemented *
1317 **************************************************************/
1318
lhs_audioinGetVersion(unsigned long * pu32Version)1319 LHS_AUDIOIN_ERROR lhs_audioinGetVersion(unsigned long *pu32Version)
1320 {
1321 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1322 }
1323
1324
1325 /**************************************************************
1326 * lhs_audioinGetVolume/lhs_audioinSetVolume *
1327 * *
1328 * notes : not implemented *
1329 **************************************************************/
1330
lhs_audioinGetVolume(AUDIOIN_H hAudioIn,unsigned long * pu32Volume)1331 LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume)
1332 {
1333 *pu32Volume = gRecordingVolume;
1334 return LHS_AUDIOIN_OK;
1335 }
1336
lhs_audioinSetVolume(AUDIOIN_H hAudioIn,unsigned long u32Volume)1337 LHS_AUDIOIN_ERROR lhs_audioinSetVolume(AUDIOIN_H hAudioIn, unsigned long u32Volume)
1338 {
1339 gRecordingVolume = u32Volume;
1340 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1341 }
1342
1343 /**************************************************************
1344 * lhs_audioinErrorGetString *
1345 * *
1346 * notes : not implemented *
1347 **************************************************************/
1348
lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error)1349 const char *lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error)
1350 {
1351 return ("unknown error");
1352 }
1353
1354
1355 #else
1356 /******************************************************************************/
1357 /* STUB FUNCTIONS FOR SIMULATOR BUILD (DOES NOT SUPPORT THREADS) */
1358 /* This code is enabled if both ANDROID and __ARM_ARCH_5__ are defined. */
1359 /******************************************************************************/
1360
1361 #include "audioin.h"
1362
lhs_audioinOpenEx(unsigned long u32AudioInID,unsigned long u32Frequency,unsigned long u32NbrOfFrames,unsigned long u32SamplesPerFrame,AUDIOIN_H * phAudioIn)1363 LHS_AUDIOIN_ERROR lhs_audioinOpenEx (
1364 unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available
1365 devices on the system). You can also use the following flag
1366 instead of a device identifier.
1367 <nl><nl><bold WAVE_MAPPER> = The function selects a
1368 waveform-audio input device capable of recording in the
1369 specified format. <bold Header:> Declared in Mmsystem.h from
1370 the Windows Multimedia: Platform SDK.*/
1371 unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */
1372 unsigned long u32NbrOfFrames, /*@parm [in] Number of frames buffered internally. */
1373 unsigned long u32SamplesPerFrame, /*@parm [in] Size, in samples, of each individual frame. */
1374 AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */
1375 )
1376 {
1377 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1378 }
1379
lhs_audioinOpen(unsigned long u32AudioInID,unsigned long u32Frequency,AUDIOIN_H * phAudioIn)1380 LHS_AUDIOIN_ERROR lhs_audioinOpen (
1381 unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available
1382 devices on the system). You can also use the following flag
1383 instead of a device identifier.
1384 <nl><nl><bold WAVE_MAPPER> = The function selects a
1385 waveform-audio input device capable of recording in the
1386 specified format. <bold Header:> Declared in Mmsystem.h from
1387 the Windows Multimedia: Platform SDK.*/
1388 unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */
1389 AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */
1390 )
1391 {
1392 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1393 }
1394
1395 #ifdef AUDIOIN_SUPPORT_CALLBACK
lhs_audioinOpenCallback(unsigned long u32AudioInID,unsigned long u32Frequency,unsigned long u32NbrOfSamples,pCallbackFunc pCallback,void * pCallbackInstance,AUDIOIN_H * phAudioIn)1396 LHS_AUDIOIN_ERROR lhs_audioinOpenCallback(unsigned long u32AudioInID, unsigned long u32Frequency, unsigned long u32NbrOfSamples, pCallbackFunc pCallback, void* pCallbackInstance, AUDIOIN_H * phAudioIn)
1397 {
1398 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1399 }
1400 #endif
1401
lhs_audioinClose(AUDIOIN_H * phAudioIn)1402 LHS_AUDIOIN_ERROR lhs_audioinClose(AUDIOIN_H *phAudioIn)
1403 {
1404 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1405 }
1406
lhs_audioinStart(AUDIOIN_H hAudioIn)1407 LHS_AUDIOIN_ERROR lhs_audioinStart(AUDIOIN_H hAudioIn)
1408 {
1409 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1410 }
1411
lhs_audioinStop(AUDIOIN_H hAudioIn)1412 LHS_AUDIOIN_ERROR lhs_audioinStop(AUDIOIN_H hAudioIn)
1413 {
1414 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1415 }
1416
lhs_audioinGetSamples(AUDIOIN_H hAudioIn,unsigned long * u32NbrOfSamples,void * pAudioBuffer,AUDIOIN_INFO * pgAudioInInfo)1417 LHS_AUDIOIN_ERROR lhs_audioinGetSamples(AUDIOIN_H hAudioIn, unsigned long * u32NbrOfSamples, void * pAudioBuffer, AUDIOIN_INFO * pgAudioInInfo)
1418 {
1419 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1420 }
1421
lhs_audioinGetVersion(unsigned long * pu32Version)1422 LHS_AUDIOIN_ERROR lhs_audioinGetVersion(unsigned long *pu32Version)
1423 {
1424 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1425 }
1426
lhs_audioinGetVolume(AUDIOIN_H hAudioIn,unsigned long * pu32Volume)1427 LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume)
1428 {
1429 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1430 }
1431
lhs_audioinSetVolume(AUDIOIN_H hAudioIn,unsigned long u32Volume)1432 LHS_AUDIOIN_ERROR lhs_audioinSetVolume(AUDIOIN_H hAudioIn, unsigned long u32Volume)
1433 {
1434 return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1435 }
1436
lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error)1437 const char *lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error)
1438 {
1439 return "LHS_E_AUDIOIN_NOTIMPLEMENTED";
1440 }
1441
1442 #endif
1443