Home | History | Annotate | Download | only in src
      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  */
    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 
    303 static void setRecordOn(void)
    304 {
    305   bRecord = 1;
    306 }
    307 
    308 static void setRecordOff(void)
    309 {
    310   bRecord = 0;
    311 }
    312 
    313 static int getRecord(void)
    314 {
    315   return bRecord;
    316 }
    317 
    318 static void setCloseOn(void)
    319 {
    320   bClose = 1;
    321 }
    322 
    323 static void setCloseOff(void)
    324 {
    325   bClose = 0;
    326 }
    327 
    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 
    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 
    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 
    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  **************************************************************/
    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  **************************************************************/
   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  **************************************************************/
   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 
   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 
   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 
   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 
   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 
   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 
   1331 LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume)
   1332 {
   1333   *pu32Volume = gRecordingVolume;
   1334   return LHS_AUDIOIN_OK;
   1335 }
   1336 
   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 
   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 
   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 
   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
   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 
   1402 LHS_AUDIOIN_ERROR lhs_audioinClose(AUDIOIN_H *phAudioIn)
   1403 {
   1404   return LHS_E_AUDIOIN_NOTIMPLEMENTED;
   1405 }
   1406 
   1407 LHS_AUDIOIN_ERROR lhs_audioinStart(AUDIOIN_H hAudioIn)
   1408 {
   1409   return LHS_E_AUDIOIN_NOTIMPLEMENTED;
   1410 }
   1411 
   1412 LHS_AUDIOIN_ERROR lhs_audioinStop(AUDIOIN_H hAudioIn)
   1413 {
   1414   return LHS_E_AUDIOIN_NOTIMPLEMENTED;
   1415 }
   1416 
   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 
   1422 LHS_AUDIOIN_ERROR lhs_audioinGetVersion(unsigned long *pu32Version)
   1423 {
   1424   return LHS_E_AUDIOIN_NOTIMPLEMENTED;
   1425 }
   1426 
   1427 LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume)
   1428 {
   1429   return LHS_E_AUDIOIN_NOTIMPLEMENTED;
   1430 }
   1431 
   1432 LHS_AUDIOIN_ERROR lhs_audioinSetVolume(AUDIOIN_H hAudioIn, unsigned long u32Volume)
   1433 {
   1434   return LHS_E_AUDIOIN_NOTIMPLEMENTED;
   1435 }
   1436 
   1437 const char *lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error)
   1438 {
   1439   return "LHS_E_AUDIOIN_NOTIMPLEMENTED";
   1440 }
   1441 
   1442 #endif
   1443