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
69static FILE *audio_data;
70static 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)
128static snd_pcm_t       *ghPCM;                   /* handle to the PCM recording device */
129#endif
130
131static int              gCodecFragmentSizeInFrames = CODEC_FRAGMENT_SIZE_IN_FRAMES;    /* fragment size used by the codec driver */
132static audioinSample    gSamplesBufferCircularFifo[SAMPLES_BUFFER_SIZE]; /* circular buffer that buffers the incoming samples */
133
134static int              gWriteIndexPointer = 0;  /* write pointer in the circular FIFO samples buffer */
135static int              gReadIndexPointer  = 0;  /* read  pointer in the circular FIFO samples buffer */
136static AUDIOIN_INFO     gAudioInInfo;            /* to store the info about the acquisition */
137static pthread_mutex_t  gAudioMutex;             /* to prevent using the read/write pointers at the same time in both threads */
138
139static pthread_cond_t   gThreadRunning;          /* synchronize when the AcquisitionThreadID is running*/
140static int              gThreadRunningSignaled = 0;
141
142static pthread_cond_t   gOpenExCalled;          /* synchronize when the lhs_audioinOpenEx is called*/
143static int              gOpenExCalledSignaled = 0;
144
145static pthread_cond_t   gCloseCalled;          /* synchronize when the lhs_audioinClose is called*/
146static int              gCloseCalledSignaled = 0;
147
148static pthread_t        AcquisitionThreadID;     /* acquisition thread id */
149
150static int              gInitialized = 0; /* did we initialize some of the variables*/
151static int              gTerminateThread = 0;
152static struct timeval   timer;                   /* timer used by select to relinquish cpu times */
153
154static int              gRecordingVolume = -1;   /* recording volume ; number between 0 and 15 */
155static int              bRecord = 0;             /* recording state is off */
156static int              bClose  = 1;             /* audio pipe is closed */
157
158#ifdef FILTER_ON
159static FIR_struct      *pFIR = NULL;             /* pointer to FIR structure */
160#endif
161
162#ifdef AUDIOIN_SUPPORT_CALLBACK
163static pCallbackFunc    gpCallback         = NULL;
164static void            *gpCallbackInstance = NULL;
165static unsigned long    gnCallbackSamples  = 0;
166#endif
167
168/* -------------------------------------------------------------------------+
169   |   LOCAL FUNCTION PROTOTYPES                                              |
170   + -------------------------------------------------------------------------*/
171
172static void *AcquisitionThread(void *data);                /* Entry function for the acquisition thread */
173static int OpenAndPrepareSound(unsigned long ulFrequency);
174
175/**
176 * returns 0 if success
177 */
178static 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 */
255static 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
303static void setRecordOn(void)
304{
305  bRecord = 1;
306}
307
308static void setRecordOff(void)
309{
310  bRecord = 0;
311}
312
313static int getRecord(void)
314{
315  return bRecord;
316}
317
318static void setCloseOn(void)
319{
320  bClose = 1;
321}
322
323static void setCloseOff(void)
324{
325  bClose = 0;
326}
327
328static 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
349void *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
556void *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
802static 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 **************************************************************/
968LHS_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 **************************************************************/
1036LHS_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 **************************************************************/
1059LHS_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
1113LHS_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
1180LHS_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
1226LHS_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
1255LHS_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
1319LHS_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
1331LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume)
1332{
1333  *pu32Volume = gRecordingVolume;
1334  return LHS_AUDIOIN_OK;
1335}
1336
1337LHS_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
1349const 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
1363LHS_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
1380LHS_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
1396LHS_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
1402LHS_AUDIOIN_ERROR lhs_audioinClose(AUDIOIN_H *phAudioIn)
1403{
1404  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1405}
1406
1407LHS_AUDIOIN_ERROR lhs_audioinStart(AUDIOIN_H hAudioIn)
1408{
1409  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1410}
1411
1412LHS_AUDIOIN_ERROR lhs_audioinStop(AUDIOIN_H hAudioIn)
1413{
1414  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1415}
1416
1417LHS_AUDIOIN_ERROR lhs_audioinGetSamples(AUDIOIN_H hAudioIn, unsigned long * u32NbrOfSamples, void * pAudioBuffer, AUDIOIN_INFO * pgAudioInInfo)
1418{
1419  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1420}
1421
1422LHS_AUDIOIN_ERROR lhs_audioinGetVersion(unsigned long *pu32Version)
1423{
1424  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1425}
1426
1427LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume)
1428{
1429  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1430}
1431
1432LHS_AUDIOIN_ERROR lhs_audioinSetVolume(AUDIOIN_H hAudioIn, unsigned long u32Volume)
1433{
1434  return LHS_E_AUDIOIN_NOTIMPLEMENTED;
1435}
1436
1437const char *lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error)
1438{
1439  return "LHS_E_AUDIOIN_NOTIMPLEMENTED";
1440}
1441
1442#endif
1443