• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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__)
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