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