From 8fc5a7f51e62cb4ae44a27bdf4176d04adc80ede Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 21 Oct 2008 07:00:00 -0700 Subject: Initial Contribution --- audio/Android.mk | 1 + audio/AudioIn/Android.mk | 1 + audio/AudioIn/UNIX/Android.mk | 1 + audio/AudioIn/UNIX/include/audioin.h | 262 ++++ audio/AudioIn/UNIX/include/audioinerr.h | 128 ++ audio/AudioIn/UNIX/include/audioinwrapper.h | 43 + audio/AudioIn/UNIX/include/filter.h | 61 + audio/AudioIn/UNIX/src/Android.mk | 26 + audio/AudioIn/UNIX/src/audioin.c | 1442 ++++++++++++++++++++ audio/AudioIn/UNIX/src/audioinwrapper.cpp | 276 ++++ audio/AudioIn/UNIX/src/filter.c | 376 +++++ audio/test/Android.mk | 1 + audio/test/AudioHardwareRecord/Android.mk | 29 + .../AudioHardwareRecord/src/AudioHardwareRecord.c | 99 ++ audio/test/AudioHardwareRecordLoop/Android.mk | 29 + .../src/AudioHardwareRecordLoop.c | 140 ++ audio/test/AudioInRecord/Android.mk | 29 + audio/test/AudioInRecord/src/AudioInRecord.c | 147 ++ 18 files changed, 3091 insertions(+) create mode 100644 audio/Android.mk create mode 100644 audio/AudioIn/Android.mk create mode 100644 audio/AudioIn/UNIX/Android.mk create mode 100644 audio/AudioIn/UNIX/include/audioin.h create mode 100644 audio/AudioIn/UNIX/include/audioinerr.h create mode 100644 audio/AudioIn/UNIX/include/audioinwrapper.h create mode 100644 audio/AudioIn/UNIX/include/filter.h create mode 100644 audio/AudioIn/UNIX/src/Android.mk create mode 100644 audio/AudioIn/UNIX/src/audioin.c create mode 100644 audio/AudioIn/UNIX/src/audioinwrapper.cpp create mode 100644 audio/AudioIn/UNIX/src/filter.c create mode 100644 audio/test/Android.mk create mode 100644 audio/test/AudioHardwareRecord/Android.mk create mode 100644 audio/test/AudioHardwareRecord/src/AudioHardwareRecord.c create mode 100644 audio/test/AudioHardwareRecordLoop/Android.mk create mode 100644 audio/test/AudioHardwareRecordLoop/src/AudioHardwareRecordLoop.c create mode 100644 audio/test/AudioInRecord/Android.mk create mode 100644 audio/test/AudioInRecord/src/AudioInRecord.c (limited to 'audio') diff --git a/audio/Android.mk b/audio/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/audio/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/audio/AudioIn/Android.mk b/audio/AudioIn/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/audio/AudioIn/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/audio/AudioIn/UNIX/Android.mk b/audio/AudioIn/UNIX/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/audio/AudioIn/UNIX/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/audio/AudioIn/UNIX/include/audioin.h b/audio/AudioIn/UNIX/include/audioin.h new file mode 100644 index 0000000..3475ceb --- /dev/null +++ b/audio/AudioIn/UNIX/include/audioin.h @@ -0,0 +1,262 @@ +/*---------------------------------------------------------------------------* + * audioin.h * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#ifndef __AUDIOIN_H__ +#define __AUDIOIN_H__ +/* -------------------------------------------------------------------------+ + | ScanSoft Inc. | + + -------------------------------------------------------------------------*/ + + + +/* -------------------------------------------------------------------------+ + | Project : ScanSoft AudioIn component + | Module : AUDIOIN + | File name : audioin.h + | Description : Interface definition for AUDIOIN + | Reference(s) : wavein, audioin.chm, audioin.doc, audioin.hlp + | SltGl00001_audioin_gl1.doc + | Status : Version 1.2 + + -------------------------------------------------------------------------*/ +/* Oct/8/2002: Fixes for Windows 2000, and memory leaks. Version 1.1 */ +/* PVP Jan/8/2004: Default audio format changed to 16kHz. Version 2.0 */ +/*--------------------------------------------------------------------------*/ + +/* @doc AUDIOININTERFACE */ + + +#include "audioinerr.h" + +#if defined( __cplusplus ) +extern "C" +{ +#endif + +/* -------------------------------------------------------------------------+ + | MACROS | + + -------------------------------------------------------------------------*/ + +/* none */ + +/* -------------------------------------------------------------------------+ + | TYPE DEFINITIONS | + + -------------------------------------------------------------------------*/ + +typedef short audioinSample; + + +/* Type Definitions for SCANSOFT-TYPES (re-definition)*/ + +/* @type AUDIOIN_H | Handle to an audio-in component. + * @comm Type is declared as a void *. The actual implementation is + * done by the implementation engineer. */ +typedef void * AUDIOIN_H; +#define WAVE_MAPPER 0 +/* @enum AUDIOIN_STATUSINFO | Enumerator for the Status Information of the AudioIn component. + * @comm The information contained in this definition concerns not only to the status of + * the FIFO but also the general status of the audio component. + * + * @xref (), AudioIn Diagram State */ +typedef enum _AUDIOIN_STATUSINFO { + AUDIOIN_NORMAL, /* @emem Normal state of the audio buffer. No problems detected while retrieving + samples.*/ + AUDIOIN_TIMEOUT, /* @emem The audio-in component timed out after no audio was received from the + audio device. The MMSystem is not providing any more samples, or the + lh_audioinGetSamples function may be called much faster than the actual + thread filling the buffer (Probable issue with the audio device). This could + be fixed by decreasing the number of samples that you want to retrieve or by + waiting till samples are available. A time out period is set internally on + the audioin implementation. Default of: + const DWORD GETSAMPLESTIMEOUT_PERIOD = 10000; (time in milliseconds)*/ + AUDIOIN_HIGHWATERMARK,/* @emem The buffer has been filled out with 75% or more. A high watermark on + the audio buffer has been detected and the buffer could be close to an OVERRUN + state.*/ + AUDIOIN_FIFOOVERRUN, /* @emem The buffer has been overfilled with audio samples. You can still retrieve + samples from the FIFO with the lhs_audioinGetSamples function, but the audio-in + component will not buffer any new audio into the FIFO. AudioinStop must be + called to reset the audio-in component.*/ + AUDIOIN_FLUSHED, /* @emem The buffer has been overfilled with audio samples. You can no longer retrieve + samples from the FIFO, since you already emptied it with lhs_audioinGetSamples. + The audio-in component will not buffer any new audio into the FIFO. + lhs_audioinStop must be called in the audio-in component since + lhs_audioinGetSamples will not longer work.*/ + AUDIOIN_HWOVERRUN, /* @emem The buffer has been overfilled with audio samples inside the device component + (audio device). lhs_audioinStop should be called to reset the contents of the + FIFO and the codec. This state is caused by an error in the MMSystem. It is + recommended to initialize the audio-in component before retrieving samples + again.*/ +} AUDIOIN_STATUSINFO; + + +/* @struct AUDIOIN_INFO | Structure for the AudioIn Information + * @comm The AUDIOIN_INFO contains information about several parts of the audio-in component. + * It gives information about the FIFO buffering audio and at the same time about the audio + * component. + * + * @xref (), AudioIn Diagram State */ +typedef struct _AUDIOIN_INFO{ + AUDIOIN_STATUSINFO eStatusInfo; /* @field The state in which the audio Buffer of the audio-in component + is. This is detailed in AUDIOIN_STATUSINFO. */ + unsigned long u32SamplesAvailable; /* @field The number of Samples still available in the audio Buffer after + lhs_audioinGetSamples is called. This value can help you to + detect over-runs in the audio buffer.*/ +} AUDIOIN_INFO; + +#ifdef AUDIOIN_SUPPORT_CALLBACK +typedef enum _AUDIOIN_MSG { + AUDIOIN_MSG_OPEN, // audio device was opened + AUDIOIN_MSG_START, // start audio acquisition + AUDIOIN_MSG_DATA, // audio samples are available + AUDIOIN_MSG_STOP, // stop audio acquisition + AUDIOIN_MSG_CLOSE, // audio device was closed + AUDIOIN_MSG_INVALID, // bogus +} AUDIOIN_MSG; + +/* callback function for "samples ready" notification */ +typedef void (*pCallbackFunc)(AUDIOIN_H hAudioIn, AUDIOIN_MSG uMsg, void* dwInstance, void* dwParam1, void* dwParam2); + +/* data structure passed to callback function; loosely based on Windows' WAVEHDR */ +typedef struct { + void *pData; + unsigned long nBufferLength; + unsigned long nBytesRecorded; + AUDIOIN_STATUSINFO status; +} AUDIOIN_WAVEHDR; +#endif + +/* -------------------------------------------------------------------------+ +| EXTERNAL DATA (+ meaning) | ++ -------------------------------------------------------------------------*/ + +/* none */ + +/* -------------------------------------------------------------------------+ +| GLOBAL FUNCTION PROTOTYPES | ++ -------------------------------------------------------------------------*/ +#if 0 + LHS_AUDIOIN_ERROR lhs_audioinOpenEx ( + unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available + devices on the system). You can also use the following flag + instead of a device identifier. + = The function selects a + waveform-audio input device capable of recording in the + specified format. Declared in Mmsystem.h from + the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */ + unsigned long u32NbrOfFrames, /*@parm [in] (not used) Number of frames buffered internally */ + unsigned long u32SamplesPerFrame, /*@parm [in] Size, in samples, of each individual frame. */ + AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */ + ); +#endif + +LHS_AUDIOIN_ERROR lhs_audioinOpen( + unsigned long u32AudioInID, /* [in] audio-in device ID (ranges from 0 to a number of available devices on the + system). You can also use the following flag instead of a device identifier. + = The function selects a waveform-audio input + device capable of recording in the specified format. + Declared in Mmsystem.h from the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /* [in] Frequency of the recognition engine in Hz. */ + AUDIOIN_H * phAudioIn /* [out] Handle to the audio-in device */ +); + +#ifdef AUDIOIN_SUPPORT_CALLBACK +LHS_AUDIOIN_ERROR lhs_audioinOpenCallback( + unsigned long u32AudioInID, /* [in] audio-in device ID (ranges from 0 to a number of available devices on the + system). You can also use the following flag instead of a device identifier. + = The function selects a waveform-audio input + device capable of recording in the specified format. + Declared in Mmsystem.h from the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /* [in] Frequency of the recognition engine in Hz. */ + unsigned long u32NbrOfSamples, /*[in] Number of samples requested per callback */ + + pCallbackFunc pCallback, /* [in] callback function */ + void *pCallbackInstance, /* [in] callback instance */ + AUDIOIN_H * phAudioIn /* [out] Handle to the audio-in device */ +); +#endif + +LHS_AUDIOIN_ERROR lhs_audioinClose( + AUDIOIN_H * phAudioIn /*[in] Pointer to the handle of the audio-in device to be closed.*/ +); + +LHS_AUDIOIN_ERROR lhs_audioinStart( + AUDIOIN_H hAudioIn /*[in] Handle of the audio-in device */ +); + +LHS_AUDIOIN_ERROR lhs_audioinStop( + AUDIOIN_H hAudioIn /*[in] Handle of the audio-in device*/ +); + +LHS_AUDIOIN_ERROR lhs_audioinGetSamples ( + AUDIOIN_H hAudioIn, /*[in] Handle of the audio-in device */ + unsigned long * u32NbrOfSamples, /*[in/out] The requested number of samples to be filled in + the pAudioBuffer. Note that the memory used for pBuffer should be large enough + to contain the requested number of samples, also note how the u32NbrOfSamples + is different than the Buffer size, since each frame has an specific size depending + on the audio format. + The actual number of recorded audio samples written in pBuffer. + If you pass 0 to this parameter then you may still retrieve the AUDIOIN_STATUSINFO + on the audio component. */ + void * pAudioBuffer, /*[out] Buffer that contains the recorded samples. The memory used for this + buffer is allocated by the client. So, it is the responsibility of the client to + make sure that this memory can contain the requested number of samples. The memory + for this buffer needs also to be freed by the client. */ + AUDIOIN_INFO * pAudioInInfo /*[out] Information about the audio internal buffer described in + AUDIOIN_INFO.*/ +); + + +LHS_AUDIOIN_ERROR lhs_audioinGetVersion( + unsigned long * pu32Version /*[out] The version number of the API implementation. */ +); + + +LHS_AUDIOIN_ERROR lhs_audioinGetVolume( + AUDIOIN_H hAudioIn, /*[in] Handle of the audio-in device.*/ + unsigned long * pu32Volume /*[out] Pointer to a variable that will be filled with the current volume + (normally range of 0 - 65535). Depending on the platform the volume + value may be set to in sizes of 16, 32 or other size, the range also + depends on the platform (Implementations of this interface may + change because of the compatibility of the internal function).*/ +); + +LHS_AUDIOIN_ERROR lhs_audioinSetVolume( + AUDIOIN_H hAudioIn, /*[in] Handle of the audio-in device.*/ + unsigned long u32Volume /*[in] The volume to be set (normal range 0-65535). Depending on the + platform the volume value may be set to in sizes of 16, 32 or other size, + the range also depends on the platform. (Implementations of this interface + may change because of the compatibility of the internal function)*/ +); + + +const TCHAR * lhs_audioinErrorGetString( + const LHS_AUDIOIN_ERROR Error /*[in] The Error code.*/ +); + + +/* -------------------------------------------------------------------------+ + | END | + + -------------------------------------------------------------------------*/ + +#if defined( __cplusplus ) +} +#endif + + +#endif /* #ifndef __AUDIOIN_H__ */ diff --git a/audio/AudioIn/UNIX/include/audioinerr.h b/audio/AudioIn/UNIX/include/audioinerr.h new file mode 100644 index 0000000..9cdefb9 --- /dev/null +++ b/audio/AudioIn/UNIX/include/audioinerr.h @@ -0,0 +1,128 @@ +/*---------------------------------------------------------------------------* + * audioinerr.h * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#ifndef _AUDIOINERRAPI_H +#define _AUDIOINERRAPI_H + +/* -------------------------------------------------------------------------+ + | ScanSoft Inc. | + + -------------------------------------------------------------------------*/ + + + +/* -------------------------------------------------------------------------+ + | Project : ScanSoft AudioIn component + | Module : AUDIOINERROR + | File name : audioinerr.h + | Description : Definition file for the error handling of the AUDIOIN + | Reference(s) : wavein, audioin.chm, audioin.doc, audioin.hlp + | SltGl00001_audioin_gl1.doc + | Status : Version 1.0 + + -------------------------------------------------------------------------*/ + +/* @doc AUDIOININTERFACE */ + + + + +#if defined( __cplusplus ) +extern "C" +{ +#endif + +/* -------------------------------------------------------------------------+ + | MACROS | + + -------------------------------------------------------------------------*/ + + /* none */ + +/* -------------------------------------------------------------------------+ + | TYPE DEFINITIONS | + + -------------------------------------------------------------------------*/ + +#define TCHAR char + +/* @type LHS_AUDIOIN_ERROR | LONG value for Error Code. (i386 win32 wince specific) + * @comm Type is declared as a LONG. + * @xref LHS_U32, LHS_U16, LHS_BOOL */ +typedef long LHS_AUDIOIN_ERROR; + + /* ERROR CODES */ + + /* general errors */ +#define LHS_AUDIOIN_OK 0 +#define LHS_E_AUDIOIN_BASE 1000 + /* AUDIOIN general errors */ +#define LHS_E_AUDIOIN_NOTIMPLEMENTED (LHS_E_AUDIOIN_BASE+0) +#define LHS_E_AUDIOIN_NULLPOINTER (LHS_E_AUDIOIN_BASE+1) +#define LHS_E_AUDIOIN_OUTOFMEMORY (LHS_E_AUDIOIN_BASE+2) +#define LHS_E_AUDIOIN_INVALIDARG (LHS_E_AUDIOIN_BASE+3) + /* AUDIOIN specific errors */ +#define LHS_E_AUDIOIN_INVALIDDEVICEID (LHS_E_AUDIOIN_BASE+4) +#define LHS_E_AUDIOIN_NOAUDIODRIVER (LHS_E_AUDIOIN_BASE+5) +#define LHS_E_AUDIOIN_COULDNOTOPENDEVICE (LHS_E_AUDIOIN_BASE+6) +#define LHS_E_AUDIOIN_BADFORMAT (LHS_E_AUDIOIN_BASE+7) +#define LHS_E_AUDIOIN_WRONGSTATE (LHS_E_AUDIOIN_BASE+8) +#define LHS_E_AUDIOIN_OVERRUN (LHS_E_AUDIOIN_BASE+9) +#define LHS_E_AUDIOIN_NOSAMPLES (LHS_E_AUDIOIN_BASE+10) +#define LHS_E_AUDIOIN_GETSETVOLUME (LHS_E_AUDIOIN_BASE+11) +#define LHS_E_AUDIOIN_AUDIOINOPENTIMEDOUT (LHS_E_AUDIOIN_BASE+12) +#define LHS_E_AUDIOIN_AUDIOINBUSY (LHS_E_AUDIOIN_BASE+13) +#define LHS_E_AUDIOIN_CREATEEVENTERROR (LHS_E_AUDIOIN_BASE+14) +#define LHS_E_AUDIOIN_CANNOTRESETAUDIODEV (LHS_E_AUDIOIN_BASE+15) +#define LHS_E_AUDIOIN_CANNOTCLOSEAUDIODEV (LHS_E_AUDIOIN_BASE+16) +#define LHS_E_AUDIOIN_CANNOTSTARTAUDIODEV (LHS_E_AUDIOIN_BASE+17) +#define LHS_E_AUDIOIN_CANNOTSTOPAUDIODEV (LHS_E_AUDIOIN_BASE+18) + +// ******************* Error Type Definitions ********************* +typedef struct _AUDIOIN_ERRORINFO +{ + long u32ErrorCode; + + const TCHAR *szExplanation; + + +}AUDIOIN_ERRORINFO; + + +/* -------------------------------------------------------------------------+ +| EXTERNAL DATA (+ meaning) | ++ -------------------------------------------------------------------------*/ + + /* none */ + +/* -------------------------------------------------------------------------+ + | GLOBAL FUNCTION PROTOTYPES | + + -------------------------------------------------------------------------*/ + +#if ( !defined(_MSC_VER) && !defined(WINAPI) ) +#define WINAPI +#endif + +/* -------------------------------------------------------------------------+ + | END | + + -------------------------------------------------------------------------*/ + + +#if defined( __cplusplus ) +} +#endif + +#endif /* _AUDIOINERRAPI_H*/ + diff --git a/audio/AudioIn/UNIX/include/audioinwrapper.h b/audio/AudioIn/UNIX/include/audioinwrapper.h new file mode 100644 index 0000000..b638c78 --- /dev/null +++ b/audio/AudioIn/UNIX/include/audioinwrapper.h @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------* + * audioinwrapper.h * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#ifndef __AUDIOINWRAPPER_H__ +#define __AUDIOINWRAPPER_H__ + +#if defined( __cplusplus ) +extern "C" +{ +#endif + +/* -------------------------------------------------------------------------+ + | C++ FUNCTION WRAPPER | + + -------------------------------------------------------------------------*/ + +int AudioOpen(void); +int AudioClose(void); +int AudioSetInputFormat(int sample_rate, int channel_count); +int AudioRead(short *buffer, int frame_count); +int AudioSetVolume(int stream_type, int volume); +int AudioGetVolume(int stream_type); + +#if defined( __cplusplus ) +} +#endif + +#endif diff --git a/audio/AudioIn/UNIX/include/filter.h b/audio/AudioIn/UNIX/include/filter.h new file mode 100644 index 0000000..41d5ff5 --- /dev/null +++ b/audio/AudioIn/UNIX/include/filter.h @@ -0,0 +1,61 @@ +/*---------------------------------------------------------------------------* + * filter.h * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#ifndef __FILTER_H__ +#define __FILTER_H__ + +// Define new data types + +typedef short typeSample; // for input and output samples +typedef short typeCoeff; // FIR filter coefficients +typedef long typeAccum; // FIR filter accumulator + +#define FACTOR_UP 1 // upsampling factor +#define FACTOR_DOWN 4 // downsampling factor + +#define u16ScaleFilterCoeff_up1_down4 15 + +typedef struct fir_struct +{ + int state; // state of FIR delay line (index of next slot to fill) + typeSample *z; // pointer to delay line + + unsigned int factor_up; + unsigned int factor_down; + + unsigned int nTaps; // length of FIR filter + unsigned int scale; // fixed-point filter scale factor + const typeCoeff *h; // pointer to FIR filter coefficients + typeAccum round; // used for roundoff +} FIR_struct; + +extern const typeCoeff ps16FilterCoeff_up1_down4[]; + +extern unsigned int filter_length; + +extern void FIR_downsample(unsigned int nInput, typeSample *pInput, + typeSample *pOutput, FIR_struct *pFIR); + +extern FIR_struct* FIR_construct(unsigned int nTaps, const typeCoeff *pCoeffs, int scale, int factor_up, int factor_down); + +extern int FIR_deconstruct(FIR_struct *pFIR); + +extern void FIR_reset(FIR_struct *pFIR); + +#endif diff --git a/audio/AudioIn/UNIX/src/Android.mk b/audio/AudioIn/UNIX/src/Android.mk new file mode 100644 index 0000000..2b80e76 --- /dev/null +++ b/audio/AudioIn/UNIX/src/Android.mk @@ -0,0 +1,26 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# common settings for all ASR builds, exports some variables for sub-makes +include $(ASR_MAKE_DIR)/Makefile.defs + +LOCAL_SRC_FILES:= \ + audioin.c \ + audioinwrapper.cpp \ + filter.c \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../../../portable/include \ + +LOCAL_CFLAGS := \ + +LOCAL_CFLAGS += \ + $(ASR_GLOBAL_DEFINES) \ + $(ASR_GLOBAL_CPPFLAGS) \ + +LOCAL_MODULE:= libSR_AudioIn + +include $(BUILD_STATIC_LIBRARY) diff --git a/audio/AudioIn/UNIX/src/audioin.c b/audio/AudioIn/UNIX/src/audioin.c new file mode 100644 index 0000000..5d20062 --- /dev/null +++ b/audio/AudioIn/UNIX/src/audioin.c @@ -0,0 +1,1442 @@ +/*---------------------------------------------------------------------------* + * audioin.c * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +/* -------------------------------------------------------------------------+ + | ScanSoft Inc. | + + -------------------------------------------------------------------------*/ + + + +/* -------------------------------------------------------------------------+ + | Project : ScanSoft AudioIn + | Module : audioin + | File name : audioin.c + | Description : This module contains the main implementation for the audioIn + | component. + | Reference(s) : wavein, audioout, audioin.chm, audioin.doc, audioin.hlp, + | SltGl00001_audioin_gl1.doc + | Status : Version 1.2 + + -------------------------------------------------------------------------*/ +/* Feb/25/2002: First QNX/SH4 "draft" version. Version 1.1 */ +/* Nov/25/2004: clean up and minor changes like choice of the codec */ +/* frame size which is now automatically selected */ +/*--------------------------------------------------------------------------*/ + +#if !defined(ANDROID) || defined(__ARM_ARCH_5__) + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "plog.h" +#include "audioin.h" + +#if defined(ANDROID) +#include "audioinwrapper.h" +#else +#include +#endif + +// #define SAVE_RAW_AUDIO 1 + +#ifdef SAVE_RAW_AUDIO +#include +#include + +static FILE *audio_data; +static struct timeval buffer_save_audio; +#endif + +/*#define FILTER_ON*/ + +#ifdef FILTER_ON +#include "filter.h" +#endif + +/* -------------------------------------------------------------------------+ + | EXTERNAL DATA (+ meaning) | + + -------------------------------------------------------------------------*/ + +/* none */ + +/* -------------------------------------------------------------------------+ + | MACROS | + + -------------------------------------------------------------------------*/ + +#define NR_OF_CHANNELS 1 + +#if defined(ANDROID) +/* size in samples */ +/* We really no longer use this for ANDROID but more changes are needed to remove it. SteveR */ +#define SAMPLES_BUFFER_SIZE (8*1024) +#define SAMPLES_BUFFER_HIGH_WATERMARK (6*1024) +#else +#define SAMPLES_BUFFER_SIZE (50*4410) +#define SAMPLES_BUFFER_HIGH_WATERMARK (40*4410) +#endif + +/* IMPORTANT NOTE: + Here a "frame" is an ALSA term. A frame is comprised of 1 sample if mono, + and 2 samples if stereo. This should be distinguished from what the + ASR engine and lhs_audioin*() API functions refer to as a frame which is + a set of consecutive samples. + (see http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html) */ +#if defined(ANDROID) +#define CODEC_FRAGMENT_SIZE_IN_FRAMES 1024 +#else +//read the equivalent of 100 ms per buffer. Note: we are recording at 44 kHz +#define CODEC_FRAGMENT_SIZE_IN_FRAMES 4410 +#endif + +/* -------------------------------------------------------------------------+ + | TYPE DEFINITIONS | + + -------------------------------------------------------------------------*/ + +/* -------------------------------------------------------------------------+ + | GLOBAL CONSTANTS | + + -------------------------------------------------------------------------*/ + + +/* -------------------------------------------------------------------------+ + | GLOBAL VARIABLES | + + -------------------------------------------------------------------------*/ + +#if !defined(ANDROID) +static snd_pcm_t *ghPCM; /* handle to the PCM recording device */ +#endif + +static int gCodecFragmentSizeInFrames = CODEC_FRAGMENT_SIZE_IN_FRAMES; /* fragment size used by the codec driver */ +static audioinSample gSamplesBufferCircularFifo[SAMPLES_BUFFER_SIZE]; /* circular buffer that buffers the incoming samples */ + +static int gWriteIndexPointer = 0; /* write pointer in the circular FIFO samples buffer */ +static int gReadIndexPointer = 0; /* read pointer in the circular FIFO samples buffer */ +static AUDIOIN_INFO gAudioInInfo; /* to store the info about the acquisition */ +static pthread_mutex_t gAudioMutex; /* to prevent using the read/write pointers at the same time in both threads */ + +static pthread_cond_t gThreadRunning; /* synchronize when the AcquisitionThreadID is running*/ +static int gThreadRunningSignaled = 0; + +static pthread_cond_t gOpenExCalled; /* synchronize when the lhs_audioinOpenEx is called*/ +static int gOpenExCalledSignaled = 0; + +static pthread_cond_t gCloseCalled; /* synchronize when the lhs_audioinClose is called*/ +static int gCloseCalledSignaled = 0; + +static pthread_t AcquisitionThreadID; /* acquisition thread id */ + +static int gInitialized = 0; /* did we initialize some of the variables*/ +static int gTerminateThread = 0; +static struct timeval timer; /* timer used by select to relinquish cpu times */ + +static int gRecordingVolume = -1; /* recording volume ; number between 0 and 15 */ +static int bRecord = 0; /* recording state is off */ +static int bClose = 1; /* audio pipe is closed */ + +#ifdef FILTER_ON +static FIR_struct *pFIR = NULL; /* pointer to FIR structure */ +#endif + +#ifdef AUDIOIN_SUPPORT_CALLBACK +static pCallbackFunc gpCallback = NULL; +static void *gpCallbackInstance = NULL; +static unsigned long gnCallbackSamples = 0; +#endif + +/* -------------------------------------------------------------------------+ + | LOCAL FUNCTION PROTOTYPES | + + -------------------------------------------------------------------------*/ + +static void *AcquisitionThread(void *data); /* Entry function for the acquisition thread */ +static int OpenAndPrepareSound(unsigned long ulFrequency); + +/** + * returns 0 if success + */ +static int Initialize(AUDIOIN_H * phAudioIn) +{ + int doneWaiting = 0; + + if( gInitialized == 1 ) + return 0; + + /* creates the mutex that will be used to lock/unlock access to some variables/code */ + if (pthread_mutex_init(&gAudioMutex, NULL) != 0) + { + return 1; + } + + if(pthread_cond_init(&gThreadRunning, 0) != 0 ) + { + return 1; + } + + if(pthread_cond_init(&gOpenExCalled, 0) != 0 ) + { + return 1; + } + + if(pthread_cond_init(&gCloseCalled, 0) != 0 ) + { + return 1; + } + + pthread_mutex_lock(&gAudioMutex); + + /* create a thread with very high priority that will do the acquisition */ + if (pthread_create(&AcquisitionThreadID, NULL, AcquisitionThread, phAudioIn) != 0) + { + return 1; + } + + //wait for the thread to run + while (!doneWaiting) + { + int rc = pthread_cond_wait(&gThreadRunning, &gAudioMutex); + switch (rc) + { + case 0: + if (!gThreadRunningSignaled) + { + // Avoid spurious wakeups + continue; + } + else + { + gThreadRunningSignaled = 0; + doneWaiting = 1; + break; + } + break; + default: + pthread_mutex_unlock(&gAudioMutex); + return 1; + } + } + + pthread_mutex_unlock(&gAudioMutex); + + + //thread is now running. + + gInitialized = 1; + + return 0; +} + +#if 0 +/* disable this unused function for now until we decide what to do with this */ + +/** + * returns 0 if success + */ +static int UnInitialize() +{ + //signal the thread that it has to stop running. + pthread_mutex_lock ( &gAudioMutex ); + gTerminateThread = 1; + + //signal to tell that our thread is now running. + if ( pthread_cond_signal ( &gOpenExCalled ) != 0 ) + { + pthread_mutex_unlock ( &gAudioMutex ); + PLogError ( "Audio In Error pthread_cond_signal\n" ); + return 1; + } + gOpenExCalledSignaled = 1; + pthread_mutex_unlock ( &gAudioMutex ); + + /* wait until thread exits */ + if (pthread_join(AcquisitionThreadID, NULL) != 0) + { + return 1; + } + + /* destroy the mutex */ + if (pthread_mutex_destroy(&gAudioMutex) !=0 ) + { + return 1; + } + if( pthread_cond_destroy(&gThreadRunning) != 0 ) + { + return 1; + } + if( pthread_cond_destroy(&gOpenExCalled) != 0 ) + { + return 1; + } + if( pthread_cond_destroy(&gCloseCalled) != 0 ) + { + return 1; + } + gInitialized = 0; + return 0; +} +#endif + +/* -------------------------------------------------------------------------+ + | LOCAL FUNCTION (should be static) | + + -------------------------------------------------------------------------*/ + +static void setRecordOn(void) +{ + bRecord = 1; +} + +static void setRecordOff(void) +{ + bRecord = 0; +} + +static int getRecord(void) +{ + return bRecord; +} + +static void setCloseOn(void) +{ + bClose = 1; +} + +static void setCloseOff(void) +{ + bClose = 0; +} + +static int getClose(void) +{ + return bClose; +} + + +/************************************************************** + * AcquisitionThread * + * * + * This function is the entry function of a thread created by * + * lhs_audioinOpen and which is responsible of getting the * + * samples from the codec and store them in a big circular * + * FIFO buffer. * + * The priority of this thread has been set to high in order * + * to prevent codec buffer overrun. Since the FIFO is limited * + * in size (5 sec default ; see SAMPLES_BUFFER_SIZE * + * parameter), the application must still be fast enough to * + * prevent FIFO overflow/overrun * + **************************************************************/ +#if defined(ANDROID) + +void *AcquisitionThread ( void *data ) +{ + int doneWaiting = 0; + audioinSample *CodecBuffer; + long x; + long y; +#ifdef AUDIOIN_SUPPORT_CALLBACK + AUDIOIN_H *phAudioIn = (AUDIOIN_H *)data; + AUDIOIN_WAVEHDR *pwhdr; +#endif + + + pthread_mutex_lock ( &gAudioMutex ); + + //signal to tell that our thread is now running. + if ( pthread_cond_signal ( &gThreadRunning ) != 0 ) + { + pthread_mutex_unlock ( &gAudioMutex ); + PLogError ( "Audio In Error pthread_cond_signal\n" ); + exit ( 1 ); + } + gThreadRunningSignaled = 1; + + while( 1 ) + { + + while (!doneWaiting) + { + int rc = pthread_cond_wait(&gOpenExCalled, &gAudioMutex); + switch (rc) + { + case 0: + if (!gOpenExCalledSignaled) + { + // Avoid spurious wakeups + continue; + } + else + { + gOpenExCalledSignaled = 0; + doneWaiting = 1; + break; + } + break; + default: + PLogError ( "Audio In Error pthread_cond_signal\n" ); + pthread_mutex_unlock(&gAudioMutex); + return ( (void *)NULL ); + } + } + doneWaiting = 0; + pthread_mutex_unlock(&gAudioMutex); + + if( gTerminateThread == 1 ) + break; + + + + /* buffer of 16 bits samples */ + CodecBuffer = (audioinSample *)malloc ( gCodecFragmentSizeInFrames * sizeof ( audioinSample ) ); + + if ( CodecBuffer == NULL ) + { + PLogError ( "Audio In Error malloc\n" ); + exit ( 1 ); + } + pwhdr = malloc ( sizeof ( AUDIOIN_WAVEHDR ) ); + + if ( pwhdr == NULL ) + { + PLogError ( "Audio In Error malloc\n" ); + exit ( 1 ); + } + + while ( !getClose ( ) ) + { + + int iReadFrames = 0; /* number of frames acquired by the codec */ + /* NOTE: here a frame is comprised of 1 sample if mono, 2 samples if stereo, etc */ + int iReadSamples = 0; /* number of samples acquired by the codec */ + int frames_to_read; /* Actual number to read */ + int frames_read; /* Frames read on one read */ + + iReadFrames = 0; + + do + { + frames_to_read = gCodecFragmentSizeInFrames - iReadFrames; + /* AudioRead() - output: number of frames (mono: 1 sample, stereo: 2 samples)*/ + frames_read = AudioRead ( CodecBuffer + iReadFrames, frames_to_read ); + + if ( frames_read > 0 ) + iReadFrames += frames_read; + } + while ( ( iReadFrames < gCodecFragmentSizeInFrames ) && ( frames_read > 0 ) ); + iReadSamples = iReadFrames; + + if ( getRecord ( ) ) /* else continue to read from driver but discard samples */ + { + if ( iReadSamples < 0 ) + { + iReadSamples = 0; + gAudioInInfo.eStatusInfo = AUDIOIN_HWOVERRUN; + } + else + { +#ifdef FILTER_ON + /* x: index for start of input samples; y: index for output sample */ + for ( x = 0, y = 0; x < iReadSamples; x += pFIR->factor_down ) + { + FIR_downsample ( pFIR->factor_down, &( CodecBuffer[x] ), &( CodecBuffer[y++] ), pFIR ); + } + /* update the number samples */ + iReadSamples = y; +#endif + pthread_mutex_lock ( &gAudioMutex ); + + if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_SIZE ) + { + gAudioInInfo.u32SamplesAvailable = SAMPLES_BUFFER_SIZE; + gAudioInInfo.eStatusInfo = AUDIOIN_FIFOOVERRUN; + } + else + { + if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_HIGH_WATERMARK ) + { + gAudioInInfo.eStatusInfo = AUDIOIN_HIGHWATERMARK; + } + else if ( gAudioInInfo.eStatusInfo != AUDIOIN_FIFOOVERRUN ) + { + gAudioInInfo.eStatusInfo = AUDIOIN_NORMAL; + } + gAudioInInfo.u32SamplesAvailable += iReadSamples; + } + if ( gWriteIndexPointer + iReadSamples <= SAMPLES_BUFFER_SIZE ) + { + memcpy ( &( gSamplesBufferCircularFifo[gWriteIndexPointer] ), CodecBuffer, + iReadSamples * sizeof ( audioinSample ) ); + gWriteIndexPointer += iReadSamples; + + if ( gWriteIndexPointer >= SAMPLES_BUFFER_SIZE ) + gWriteIndexPointer = 0; + } + else + { + int NbToCopy; + + NbToCopy = SAMPLES_BUFFER_SIZE - gWriteIndexPointer; + memcpy ( &( gSamplesBufferCircularFifo [gWriteIndexPointer] ), CodecBuffer, + NbToCopy * sizeof ( audioinSample ) ); + gWriteIndexPointer = 0; + memcpy ( gSamplesBufferCircularFifo, &( CodecBuffer [NbToCopy] ), + ( iReadSamples-NbToCopy ) * sizeof ( audioinSample ) ); + gWriteIndexPointer = iReadSamples - NbToCopy; + } + +#ifdef AUDIOIN_SUPPORT_CALLBACK + /* Callback notification. Ideally this audio acquisition thread should be very lean. + It should simply read from the low level driver, store the filtered samples in + the FIFO, then go back to reading from the driver. The additional data copy + for the callback function is ok despite the overhead incurred, but only because + there's some buffering done by the low level driver. This design should be + revisited to make it more general purpose. + */ + if ( gpCallback != NULL ) + { + pwhdr->nBufferLength = iReadSamples * sizeof ( audioinSample ); + pwhdr->nBytesRecorded = pwhdr->nBufferLength; + pwhdr->status = AUDIOIN_NORMAL; + pwhdr->pData = CodecBuffer; + /* pass samples to callback function who should deallocate the buffer and structure */ + gpCallback ( *phAudioIn, AUDIOIN_MSG_DATA, gpCallbackInstance, pwhdr, NULL ); + } +#endif + /* samples are available to read */ + pthread_mutex_unlock ( &gAudioMutex ); + timer.tv_sec = 0; + timer.tv_usec = 200; + select ( 0, NULL, NULL, NULL, &timer ); + } + } /* if (getRecord()) */ + + } /* while (!getClose()) */ + if ( AudioClose ( ) !=0 ) + { + PLogError ( "Audio In Error Closing Hardware\n" ); + } + free ( CodecBuffer ); + + pthread_mutex_lock ( &gAudioMutex ); + //signal to tell that our thread is now running. + if ( pthread_cond_signal ( &gCloseCalled ) != 0 ) + { + pthread_mutex_unlock ( &gAudioMutex ); + PLogError ( "Audio In Error pthread_cond_signal\n" ); + exit ( 1 ); + } + gCloseCalledSignaled = 1; + } + + pthread_exit ( (void *)NULL ); + return ( (void *)NULL ); +} + +#else +/* non-ANDROID version */ + +void *AcquisitionThread ( void *data ) +{ + int doneWaiting = 0; + audioinSample *CodecBuffer; +#ifdef FILTER_ON + long x; + long y; +#endif +#ifdef AUDIOIN_SUPPORT_CALLBACK + AUDIOIN_H *phAudioIn = (AUDIOIN_H *)data; +#endif + + pthread_mutex_lock ( &gAudioMutex ); + + //signal to tell that our thread is now running. + if ( pthread_cond_signal ( &gThreadRunning ) != 0 ) + { + pthread_mutex_unlock ( &gAudioMutex ); + PLogError ( "Audio In Error pthread_cond_signal\n" ); + exit ( 1 ); + } + gThreadRunningSignaled = 1; + + while( 1 ) + { + while (!doneWaiting) + { + int rc = pthread_cond_wait(&gOpenExCalled, &gAudioMutex); + switch (rc) + { + case 0: + if (!gOpenExCalledSignaled) + { + // Avoid spurious wakeups + continue; + } + else + { + gOpenExCalledSignaled = 0; + doneWaiting = 1; + break; + } + break; + default: + PLogError ( "Audio In Error pthread_cond_wait\n" ); + pthread_mutex_unlock(&gAudioMutex); + return ( (void *)NULL ); + } + } + doneWaiting = 0; + pthread_mutex_unlock(&gAudioMutex); + + if( gTerminateThread == 1 ) + break; + + /* buffer of 16 bits samples */ + CodecBuffer = (audioinSample *)malloc ( gCodecFragmentSizeInFrames * sizeof ( audioinSample ) ); + + if ( CodecBuffer == NULL ) + { + PLogError ( "Audio In Error pthread_cond_signal\n" ); + exit ( 1 ); + } + + while ( !getClose ( ) ) + { + int iReadFrames = 0; /* number of frames acquired by the codec */ + /* NOTE: here a frame is comprised of 1 sample if mono, 2 samples if stereo, etc */ + int iReadSamples = 0; /* number of samples acquired by the codec */ + if ( ( iReadFrames = snd_pcm_readi ( ghPCM, (void *)CodecBuffer, gCodecFragmentSizeInFrames ) ) < 0 ) + { + if ( iReadFrames == -EBADFD ) + { + PLogError ( "Audio In Error PCM Not In The Right State\n" ); + } + else if ( iReadFrames == -EPIPE ) + { + snd_pcm_prepare(ghPCM); + PLogError ( "Audio In Error Overrun\n" ); + } + else if ( iReadFrames == -ESTRPIPE ) + { + PLogError ( "Audio In Error Stream Suspended\n" ); + } + } + iReadSamples = iReadFrames; + + if ( getRecord ( ) ) /* else continue to read from driver but discard samples */ + { + if ( iReadSamples < 0 ) + { + iReadSamples = 0; + gAudioInInfo.eStatusInfo = AUDIOIN_HWOVERRUN; + } + else + { +#ifdef FILTER_ON + /* x: index for start of input samples; y: index for output sample */ + for ( x = 0, y = 0; x < iReadSamples; x += pFIR->factor_down ) + { + FIR_downsample ( pFIR->factor_down, &( CodecBuffer[x] ), &( CodecBuffer[y++] ), pFIR ); + } + /* update the number samples */ + iReadSamples = y; +#endif +#ifdef SAVE_RAW_AUDIO + if ( iReadSamples > 0 ) + fwrite ( CodecBuffer, 2, iReadSamples, audio_data ); +#endif + + pthread_mutex_lock ( &gAudioMutex ); + + if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_SIZE ) + { + gAudioInInfo.u32SamplesAvailable = SAMPLES_BUFFER_SIZE; + gAudioInInfo.eStatusInfo = AUDIOIN_FIFOOVERRUN; + } + else + { + if ( gAudioInInfo.u32SamplesAvailable + iReadSamples > SAMPLES_BUFFER_HIGH_WATERMARK ) + { + gAudioInInfo.eStatusInfo = AUDIOIN_HIGHWATERMARK; + } + else if ( gAudioInInfo.eStatusInfo != AUDIOIN_FIFOOVERRUN ) + { + gAudioInInfo.eStatusInfo = AUDIOIN_NORMAL; + } + gAudioInInfo.u32SamplesAvailable += iReadSamples; + } + if ( gWriteIndexPointer + iReadSamples <= SAMPLES_BUFFER_SIZE ) + { + memcpy ( &( gSamplesBufferCircularFifo[gWriteIndexPointer] ), CodecBuffer, + iReadSamples * sizeof ( audioinSample ) ); + gWriteIndexPointer += iReadSamples; + + if ( gWriteIndexPointer >= SAMPLES_BUFFER_SIZE ) + gWriteIndexPointer = 0; + } + else + { + int NbToCopy; + + NbToCopy = SAMPLES_BUFFER_SIZE - gWriteIndexPointer; + memcpy ( &( gSamplesBufferCircularFifo [gWriteIndexPointer] ), CodecBuffer, + NbToCopy * sizeof ( audioinSample ) ); + gWriteIndexPointer = 0; + memcpy ( gSamplesBufferCircularFifo, &( CodecBuffer [NbToCopy] ), + ( iReadSamples-NbToCopy ) * sizeof ( audioinSample ) ); + gWriteIndexPointer = iReadSamples - NbToCopy; + } +#ifdef AUDIOIN_SUPPORT_CALLBACK + /* Callback notification. Ideally this audio acquisition thread should be very lean. + It should simply read from the low level driver, store the filtered samples in + the FIFO, then go back to reading from the driver. The additional data copy + for the callback function is ok despite the overhead incurred, but only because + there's some buffering done by the low level driver. This design should be + revisited to make it more general purpose. + */ + while ( ( gpCallback != NULL ) && ( gAudioInInfo.u32SamplesAvailable >= gnCallbackSamples ) ) + { + AUDIOIN_WAVEHDR *pwhdr; + + pwhdr = malloc ( sizeof ( AUDIOIN_WAVEHDR ) ); + + if ( pwhdr != NULL ) + { + pwhdr->nBufferLength = gnCallbackSamples * sizeof ( audioinSample ); + pwhdr->nBytesRecorded = pwhdr->nBufferLength; + pwhdr->status = gAudioInInfo.eStatusInfo; + pwhdr->pData = malloc ( pwhdr->nBufferLength ); + + if ( pwhdr->pData != NULL ) + { + if ( gReadIndexPointer + gnCallbackSamples <= SAMPLES_BUFFER_SIZE ) + { + memcpy ( pwhdr->pData, &( gSamplesBufferCircularFifo [gReadIndexPointer] ), + pwhdr->nBufferLength ); + gReadIndexPointer += gnCallbackSamples; + + if ( gReadIndexPointer >= SAMPLES_BUFFER_SIZE ) + gReadIndexPointer = 0; + } + else + { + size_t nSamplesPart1 = SAMPLES_BUFFER_SIZE - gReadIndexPointer; + size_t nSamplesPart2 = gnCallbackSamples - nSamplesPart1; + + memcpy ( pwhdr->pData, &( gSamplesBufferCircularFifo [gReadIndexPointer] ), + nSamplesPart1*sizeof ( audioinSample ) ); + gReadIndexPointer = 0; + memcpy ( pwhdr->pData + nSamplesPart1 * sizeof (audioinSample ), + gSamplesBufferCircularFifo, nSamplesPart2 * sizeof ( audioinSample ) ); + gReadIndexPointer = nSamplesPart2; + } + gAudioInInfo.u32SamplesAvailable -= gnCallbackSamples; + /* pass samples to callback function who should deallocate the buffer and structure */ + gpCallback ( *phAudioIn, AUDIOIN_MSG_DATA, gpCallbackInstance, pwhdr, NULL ); + } + else + { + // error + } + } + else + { + // error + } + } +#endif + /* samples are available to read */ + pthread_mutex_unlock ( &gAudioMutex ); + timer.tv_sec = 0; + timer.tv_usec = 200; + select ( 0, NULL, NULL, NULL, &timer ); + } + } /* if (getRecord()) */ + + } /* while (!getClose()) */ + + if ( snd_pcm_close ( ghPCM ) !=0 ) + { + PLogError ( "Audio In Error Closing Hardware\n" ); + } + + free ( CodecBuffer ); + + pthread_mutex_lock ( &gAudioMutex ); + //signal to tell that our thread is now running. + if ( pthread_cond_signal ( &gCloseCalled ) != 0 ) + { + pthread_mutex_unlock ( &gAudioMutex ); + PLogError ( "Audio In Error pthread_cond_signal\n" ); + exit ( 1 ); + } + gCloseCalledSignaled = 1; + } + pthread_exit ( (void *)NULL ); + return ( (void *)NULL ); +} +#endif + +/************************************************************** + * OpenAndPrepareSound * + *************************************************************/ + + +static int OpenAndPrepareSound(unsigned long ulFrequency) +{ +#if defined(ANDROID) + + /* Only support certain frequencies. Modify this to check frequency + against a structure of valid frequencies */ +#ifdef FILTER_ON + if ( ulFrequency == 11025 ) + { + if ( AudioSetInputFormat ( 44100, NR_OF_CHANNELS ) != 0 ) /* sample at 44100 then downsample */ + { + PLogError ( "Audio In Error OpenAndPrepareSound - AudioSetInputFormat failed!\n"); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + } + else + { + PLogError ( "Audio In Error OpenAndPrepareSound - invalid frequency!"); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } +#else + if ( ( ulFrequency == 11025 ) || ( ulFrequency == 8000 ) ) + { + if ( AudioSetInputFormat ( ulFrequency, NR_OF_CHANNELS ) != 0 ) + { + PLogError ( "Audio In Error OpenAndPrepareSound - AudioSetInputFormat failed!"); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + } + else + { + PLogError ( "Audio In Error OpenAndPrepareSound - invalid frequency!"); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } +#endif + + /* set some variables */ + gAudioInInfo.u32SamplesAvailable = 0; + + /* Open Audio driver */ + if (AudioOpen() < 0) + { + PLogError ( "Audio In Error OpenAndPrepareSound - AudioOpen failed!"); + return ~LHS_AUDIOIN_OK; + } + +#else + + snd_pcm_hw_params_t *hwparams; + unsigned int exact_rate; + int dir; + int rc; + + /* step 1 : open the sound device */ + /* ------------------------------ */ + if ((rc = snd_pcm_open(&ghPCM, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0) + { + PLogError ( "Audio In Error snd_pcm_open() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + if ((rc = snd_pcm_hw_params_malloc(&hwparams)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_malloc() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + /* step 2 : configuring the audio channel */ + /* -------------------------------------- */ + + if ((rc = snd_pcm_hw_params_any(ghPCM, hwparams)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_any() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + if ((rc = snd_pcm_hw_params_set_access(ghPCM, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_set_access() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + if ((rc = snd_pcm_hw_params_set_format(ghPCM, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_set_format() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + +#ifdef FILTER_ON + if (ulFrequency == 11025) + { + exact_rate = 44100; + } + else + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; +#else + exact_rate = ulFrequency; +#endif + + dir = 0; + +#if 0 + /* This version seems to have problems when the code is compiled into a shared library. + The subsequent call to snd_pcm_hw_params() fails. */ + if ((rc = snd_pcm_hw_params_set_rate_near(ghPCM, hwparams, &exact_rate, &dir)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_set_rate_near() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } +#else + /* This version works better and in fact makes more sense. */ + if ((rc = snd_pcm_hw_params_set_rate(ghPCM, hwparams, exact_rate, dir)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_set_rate() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } +#endif + + + if ((rc = snd_pcm_hw_params_set_channels(ghPCM, hwparams, NR_OF_CHANNELS)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params_set_channels() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + if ((rc = snd_pcm_hw_params(ghPCM, hwparams)) < 0) + { + PLogError ( "Audio In Error snd_pcm_hw_params() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + /* step 3 : preparing for read */ + /* --------------------------- */ + + /*prepare the channel */ + + if ((rc = snd_pcm_prepare(ghPCM)) < 0) + { + PLogError ( "Audio In Error snd_pcm_prepare() (rc = %d: %s)\n", rc, snd_strerror(rc)); + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + /* set some variables */ + gAudioInInfo.u32SamplesAvailable = 0; + + +#endif + + /* prepare to read samples */ + setCloseOff(); + + return 0; +} + + +/* -------------------------------------------------------------------------+ + | GLOBAL FUNCTIONS (prototypes in header file) | + + -------------------------------------------------------------------------*/ + +/************************************************************** + * lhs_audioinOpenEx * + * * + * notes : * + * -the input parameters are in fact not used but present * + * to ensure compatibility with Win32 implementations * + **************************************************************/ +LHS_AUDIOIN_ERROR lhs_audioinOpenEx ( + unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available + devices on the system). You can also use the following flag + instead of a device identifier. + = The function selects a + waveform-audio input device capable of recording in the + specified format. Declared in Mmsystem.h from + the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */ + unsigned long u32NbrOfFrames, /*@parm [in] Number of frames buffered internally. */ + unsigned long u32SamplesPerFrame, /*@parm [in] Size, in samples, of each individual frame. */ + AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */ + ) +{ + //initialize some of the static variables. + if( Initialize(phAudioIn) ) + return ~LHS_AUDIOIN_OK; + + + /* prepare sound */ + if (OpenAndPrepareSound(u32Frequency) != 0) + { + return LHS_E_AUDIOIN_COULDNOTOPENDEVICE; + } + + //signal the thread that it has to stop running. + pthread_mutex_lock ( &gAudioMutex ); + //signal to tell that our thread is now running. + if ( pthread_cond_signal ( &gOpenExCalled ) != 0 ) + { + pthread_mutex_unlock ( &gAudioMutex ); + PLogError ( "Audio In Error pthread_cond_signal\n" ); + exit ( 1 ); + } + gOpenExCalledSignaled = 1; + pthread_mutex_unlock ( &gAudioMutex ); + +#ifdef FILTER_ON + /* need to make this more generic to support different filters */ + pFIR = FIR_construct(filter_length, ps16FilterCoeff_up1_down4, u16ScaleFilterCoeff_up1_down4, FACTOR_UP, FACTOR_DOWN); + if (pFIR == NULL) + { + // TO DO: HANDLE THIS (or modify for static allocation) + } +#endif + + /* set the status to normal */ + gAudioInInfo.eStatusInfo = AUDIOIN_NORMAL; + + /* do not care, but some applications are checking a NULL handle */ + *phAudioIn = (void *)10; + +#ifdef AUDIOIN_SUPPORT_CALLBACK + gpCallback = NULL; + gpCallbackInstance = NULL; + gnCallbackSamples = 0; +#endif + + return LHS_AUDIOIN_OK; +} + +/************************************************************** + * lhs_audioinOpen * + * * + * notes : * + * -the input parameters are in fact not used but present * + * to ensure compatibility with Win32 implementation * + **************************************************************/ +LHS_AUDIOIN_ERROR lhs_audioinOpen ( + unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available + devices on the system). You can also use the following flag + instead of a device identifier. + = The function selects a + waveform-audio input device capable of recording in the + specified format. Declared in Mmsystem.h from + the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */ + AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */ + ) +{ + return lhs_audioinOpenEx(u32AudioInID, u32Frequency, 0, 0, phAudioIn); +} /* lhs_audioinOpen */ + +#ifdef AUDIOIN_SUPPORT_CALLBACK +/************************************************************** + * lhs_audioinOpenCallback * + * * + * notes : * + * -the input parameters are in fact not used but present * + * to ensure compatibility with Win32 implementation * + **************************************************************/ +LHS_AUDIOIN_ERROR lhs_audioinOpenCallback ( + unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available + devices on the system). You can also use the following flag + instead of a device identifier. + = The function selects a + waveform-audio input device capable of recording in the + specified format. Declared in Mmsystem.h from + the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */ + unsigned long u32NbrOfSamples, /*@parm [in] Number of samples requested per callback */ + pCallbackFunc pCallback, /*@parm [in] callback function */ + void *pCallbackInstance, /*@parm [in] callback instance */ + AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */ + ) +{ + LHS_AUDIOIN_ERROR lhsErr; + +#ifdef FILTER_ON + gCodecFragmentSizeInFrames = u32NbrOfSamples * 4; +#else + gCodecFragmentSizeInFrames = u32NbrOfSamples; +#endif + + if ((pCallback == NULL) || (u32NbrOfSamples == 0)) + { + return LHS_E_AUDIOIN_INVALIDARG; + } + lhsErr = lhs_audioinOpenEx(u32AudioInID, u32Frequency, 0, 0, phAudioIn); + if (lhsErr != LHS_AUDIOIN_OK) + { + return lhsErr; + } + + /* install callback */ + gpCallback = pCallback; + gpCallbackInstance = pCallbackInstance; + gnCallbackSamples = u32NbrOfSamples; + + /* callback notification */ + gpCallback(*phAudioIn, AUDIOIN_MSG_OPEN, gpCallbackInstance, NULL, NULL); + + return LHS_AUDIOIN_OK; + +} /* lhs_audioinOpenCallback */ +#endif + +/************************************************************** + * lhs_audioinClose * + * * + * notes : * + * -the input parameters are in fact not used but present * + * to ensure compatibility with Win32 implementations * + **************************************************************/ + +LHS_AUDIOIN_ERROR lhs_audioinClose(AUDIOIN_H *phAudioIn) +{ + int doneWaiting = 0; + + /* Validate the handle */ + if ((phAudioIn == NULL) || (*phAudioIn == NULL)) + { + return LHS_E_AUDIOIN_NULLPOINTER; + } + + /* stop recording audio samples */ + setRecordOff(); + + /* stop reading audio samples */ + setCloseOn(); + + //wait for the thread to stop reading samples. + pthread_mutex_lock ( &gAudioMutex ); + + while (!doneWaiting) + { + int rc = pthread_cond_wait(&gCloseCalled, &gAudioMutex); + switch (rc) + { + case 0: + if (!gCloseCalledSignaled) + { + // Avoid spurious wakeups + continue; + } + else + { + gCloseCalledSignaled = 0; + doneWaiting = 1; + break; + } + break; + default: + PLogError ( "Audio In Error pthread_cond_wait\n" ); + pthread_mutex_unlock(&gAudioMutex); + return ~LHS_AUDIOIN_OK; + } + } + pthread_mutex_unlock(&gAudioMutex); + +#ifdef FILTER_ON + FIR_deconstruct(pFIR); +#endif + +#ifdef AUDIOIN_SUPPORT_CALLBACK + /* callback notification */ + if (gpCallback != NULL) gpCallback(*phAudioIn, AUDIOIN_MSG_CLOSE, gpCallbackInstance, NULL, NULL); +#endif + + return LHS_AUDIOIN_OK; +} + +/************************************************************** + * lhs_audioinStart * + * * + * notes : * + * -the input parameters are in fact not used but present * + * to ensure compatibility with Win32 implementations * + * -in fact the recording is never stopped or started, when * + * non in 'start' status, the samples are just ignored * + **************************************************************/ + +LHS_AUDIOIN_ERROR lhs_audioinStart(AUDIOIN_H hAudioIn) +{ +#ifdef SAVE_RAW_AUDIO + char file_name [256]; + + gettimeofday ( &buffer_save_audio, NULL ); + sprintf ( file_name, "data_%ld_%ld.raw", buffer_save_audio.tv_sec, buffer_save_audio.tv_usec ); + audio_data = fopen ( file_name, "w" ); +#endif + if (hAudioIn == NULL) + { + return LHS_E_AUDIOIN_NULLPOINTER; + } + + pthread_mutex_lock ( &gAudioMutex ); + +#ifdef FILTER_ON + FIR_reset(pFIR); +#endif + + gWriteIndexPointer = 0; + gReadIndexPointer = 0; + gAudioInInfo.u32SamplesAvailable = 0; + + /* start recording */ + setRecordOn(); + +#ifdef AUDIOIN_SUPPORT_CALLBACK + /* callback notification */ + if (gpCallback != NULL) gpCallback(hAudioIn, AUDIOIN_MSG_START, gpCallbackInstance, NULL, NULL); +#endif + pthread_mutex_unlock ( &gAudioMutex ); + + return LHS_AUDIOIN_OK; +} + +/************************************************************** + * lhs_audioinStop * + * * + * notes : * + * -the input parameters are in fact not used but present * + * to ensure compatibility with Win32 implementations * + * -in fact the recording is never stopped or started, when * + * non in 'start' status, the samples are just ignored * + **************************************************************/ + +LHS_AUDIOIN_ERROR lhs_audioinStop(AUDIOIN_H hAudioIn) +{ +#ifdef SAVE_RAW_AUDIO + fclose ( audio_data ); +#endif + if (hAudioIn == NULL) + { + return LHS_E_AUDIOIN_NULLPOINTER; + } + pthread_mutex_lock ( &gAudioMutex ); + + /* stop recording (discard samples) */ + setRecordOff(); + +#ifdef AUDIOIN_SUPPORT_CALLBACK + /* callback notification */ + if (gpCallback != NULL) gpCallback(hAudioIn, AUDIOIN_MSG_STOP, gpCallbackInstance, NULL, NULL); +#endif + pthread_mutex_unlock ( &gAudioMutex ); + + return LHS_AUDIOIN_OK; +} + +/************************************************************** + * lhs_audioinGetSamples * + * * + * notes : * + **************************************************************/ + +LHS_AUDIOIN_ERROR lhs_audioinGetSamples(AUDIOIN_H hAudioIn, unsigned long * u32NbrOfSamples, void * pAudioBuffer, AUDIOIN_INFO * pgAudioInInfo) +{ + unsigned long cSamples; + //unsigned long nToCopy; + + /* Check if the handle is valid */ + if (hAudioIn == NULL) + { + return LHS_E_AUDIOIN_NULLPOINTER; + } + + cSamples = 0; + + while (1) + { + /* wait until we have enough samples */ + if (*u32NbrOfSamples <= gAudioInInfo.u32SamplesAvailable) + { + /* lock the code to prevent dual access to some variables */ + pthread_mutex_lock(&gAudioMutex); + + /* TO DO: consider copying in chunks (like in AquisitionThread) + rather than 1 sample at a time. */ + + /* copy all samples into the input buffer */ + while ((cSamples < *u32NbrOfSamples)) + { + ((audioinSample *)pAudioBuffer)[cSamples++] = gSamplesBufferCircularFifo[gReadIndexPointer++]; + + /* adapt the parameters */ + gAudioInInfo.u32SamplesAvailable -= 1; + + /* adapt circular buffer */ + if (gReadIndexPointer >= SAMPLES_BUFFER_SIZE) + { + gReadIndexPointer = 0; + } + + /* enough samples */ + if (cSamples == *u32NbrOfSamples) + { + /* return the audioin info structure */ + memcpy(pgAudioInInfo, &gAudioInInfo, sizeof(AUDIOIN_INFO)); + pthread_mutex_unlock(&gAudioMutex); + return LHS_AUDIOIN_OK; + } + } + } + else + { + /* relinquish CPU. select() is more reliable than usleep(). */ + timer.tv_sec = 0; + timer.tv_usec = 10000; + select(0, NULL, NULL, NULL, &timer); + } + } /* while (1) */ +} + +/************************************************************** + * lhs_audioinGetVersion * + * * + * notes : not implemented * + **************************************************************/ + +LHS_AUDIOIN_ERROR lhs_audioinGetVersion(unsigned long *pu32Version) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + + +/************************************************************** + * lhs_audioinGetVolume/lhs_audioinSetVolume * + * * + * notes : not implemented * + **************************************************************/ + +LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume) +{ + *pu32Volume = gRecordingVolume; + return LHS_AUDIOIN_OK; +} + +LHS_AUDIOIN_ERROR lhs_audioinSetVolume(AUDIOIN_H hAudioIn, unsigned long u32Volume) +{ + gRecordingVolume = u32Volume; + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +/************************************************************** + * lhs_audioinErrorGetString * + * * + * notes : not implemented * + **************************************************************/ + +const char *lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error) +{ + return ("unknown error"); +} + + +#else +/******************************************************************************/ +/* STUB FUNCTIONS FOR SIMULATOR BUILD (DOES NOT SUPPORT THREADS) */ +/* This code is enabled if both ANDROID and __ARM_ARCH_5__ are defined. */ +/******************************************************************************/ + +#include "audioin.h" + +LHS_AUDIOIN_ERROR lhs_audioinOpenEx ( + unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available + devices on the system). You can also use the following flag + instead of a device identifier. + = The function selects a + waveform-audio input device capable of recording in the + specified format. Declared in Mmsystem.h from + the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */ + unsigned long u32NbrOfFrames, /*@parm [in] Number of frames buffered internally. */ + unsigned long u32SamplesPerFrame, /*@parm [in] Size, in samples, of each individual frame. */ + AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */ + ) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinOpen ( + unsigned long u32AudioInID, /*@parm [in] Audio-in device ID (ranges from 0 to a number of available + devices on the system). You can also use the following flag + instead of a device identifier. + = The function selects a + waveform-audio input device capable of recording in the + specified format. Declared in Mmsystem.h from + the Windows Multimedia: Platform SDK.*/ + unsigned long u32Frequency, /*@parm [in] Frequency of the recognition engine in Hz. */ + AUDIOIN_H * phAudioIn /*@parm [out] Handle to the audio-in device */ + ) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +#ifdef AUDIOIN_SUPPORT_CALLBACK +LHS_AUDIOIN_ERROR lhs_audioinOpenCallback(unsigned long u32AudioInID, unsigned long u32Frequency, unsigned long u32NbrOfSamples, pCallbackFunc pCallback, void* pCallbackInstance, AUDIOIN_H * phAudioIn) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} +#endif + +LHS_AUDIOIN_ERROR lhs_audioinClose(AUDIOIN_H *phAudioIn) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinStart(AUDIOIN_H hAudioIn) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinStop(AUDIOIN_H hAudioIn) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinGetSamples(AUDIOIN_H hAudioIn, unsigned long * u32NbrOfSamples, void * pAudioBuffer, AUDIOIN_INFO * pgAudioInInfo) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinGetVersion(unsigned long *pu32Version) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinGetVolume(AUDIOIN_H hAudioIn, unsigned long *pu32Volume) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +LHS_AUDIOIN_ERROR lhs_audioinSetVolume(AUDIOIN_H hAudioIn, unsigned long u32Volume) +{ + return LHS_E_AUDIOIN_NOTIMPLEMENTED; +} + +const char *lhs_audioinErrorGetString(const LHS_AUDIOIN_ERROR Error) +{ + return "LHS_E_AUDIOIN_NOTIMPLEMENTED"; +} + +#endif diff --git a/audio/AudioIn/UNIX/src/audioinwrapper.cpp b/audio/AudioIn/UNIX/src/audioinwrapper.cpp new file mode 100644 index 0000000..6d3ff99 --- /dev/null +++ b/audio/AudioIn/UNIX/src/audioinwrapper.cpp @@ -0,0 +1,276 @@ +/*---------------------------------------------------------------------------* + * audioinwrapper.cpp * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + + +#if defined(ANDROID) && defined(__ARM_ARCH_5__) + +//#define USE_DEV_EAC_FILE 1 + +#if defined(USE_DEV_EAC_FILE) +#include +#define N_CHANNELS 1 +#else +#include +#include +using namespace android; +#endif + +#endif // defined(ANDROID) && defined(__ARM_ARCH_5__) + +#include "plog.h" + +// #define SAVE_RAW_AUDIO 1 + +#ifdef SAVE_RAW_AUDIO +#include +#include + + +static FILE *audio_data; +static struct timeval buffer_save_audio; +#endif + + +// #define MEASURE_SAMPLE_TIMES 1 + +#ifdef MEASURE_SAMPLE_TIMES +#include +#include +#include + + +#define MAX_SAMPLES_TO_MEASURE 500 + +static long sample_buffers_received = 0; +static long total_samples_received = 0; +static long samples_in_buffer [MAX_SAMPLES_TO_MEASURE]; +static long seconds_buffer_received [MAX_SAMPLES_TO_MEASURE]; +static long micro_seconds_buffer_received [MAX_SAMPLES_TO_MEASURE]; +static struct timeval buffer_received_time; + +static void AudioIn_Log_Samples_Received ( void ); + +static void AudioIn_Log_Samples_Received ( void ) + { + FILE *log_file; + char file_name [256]; + char log_buffer [256]; + long loop_counter; + + if ( sample_buffers_received > 0 ) + { + gettimeofday ( &buffer_received_time, NULL ); + sprintf ( file_name, "aud_in_%ld_%ld.txt", buffer_received_time.tv_sec, buffer_received_time.tv_usec ); + log_file = fopen ( file_name, "w" ); + + if ( log_file != NULL ) + { + for ( loop_counter = 0; loop_counter < sample_buffers_received; loop_counter++ ) + { + sprintf ( log_buffer, "%ld %ld %ld %ld\n", loop_counter + 1, samples_in_buffer [loop_counter], + seconds_buffer_received [loop_counter], micro_seconds_buffer_received [loop_counter] ); + fwrite ( log_buffer, 1, strlen ( log_buffer ), log_file ); + } + fclose ( log_file ); + } + sample_buffers_received = 0; + } + } +#endif + + +extern "C" +{ + +#if defined(ANDROID) && defined(__ARM_ARCH_5__) + +#if defined(USE_DEV_EAC_FILE) +static int audiofd = -1; +#else +static AudioRecord* record; +static int sampleRate = 8000; +static int numChannels = 1; +#endif + +// called before AudioOpen +int AudioSetInputFormat(int sample_rate, int channel_count) +{ +#if defined(USE_DEV_EAC_FILE) + return 0; +#else + sampleRate = sample_rate; + numChannels = channel_count; + return 0; +#endif +} + +int AudioOpen(void) +{ +#if defined(USE_DEV_EAC_FILE) + audiofd = open("/dev/eac", O_RDONLY, 0666); + if (audiofd >= 0) { + //fcntl(audiofd, F_SETFL, O_NONBLOCK); + + // possibly lame attempt to get Sooner audio input working + struct { unsigned long param1, param2, param3; } params = { 11025, 0, 0 }; + ioctl(audiofd, 317, ¶ms, sizeof(params)); + } + + return audiofd; +#else + #ifdef SAVE_RAW_AUDIO + char file_name [256]; + + gettimeofday ( &buffer_save_audio, NULL ); + sprintf ( file_name, "data_%ld_%ld.raw", buffer_save_audio.tv_sec, buffer_save_audio.tv_usec ); + audio_data = fopen ( file_name, "w" ); + #endif + record = new android::AudioRecord( + android::AudioRecord::DEFAULT_INPUT, sampleRate, + android::AudioSystem::PCM_16_BIT, numChannels, 8, 0); + + if (!record) return -1; + + return record->start() == NO_ERROR ? 0 : -1; +#endif +} + +int AudioClose(void) +{ +#if defined(USE_DEV_EAC_FILE) + return close(audiofd); +#else + #ifdef MEASURE_SAMPLE_TIMES + AudioIn_Log_Samples_Received ( ); + #endif + record->stop(); + delete record; + #ifdef SAVE_RAW_AUDIO + fclose ( audio_data ); + #endif + return 0; +#endif +} + +int AudioRead(short *buffer, int frame_count) +{ + int n; +#if defined(USE_DEV_EAC_FILE) + n = read(audiofd, buffer, frame_count*sizeof(short)*N_CHANNELS); + n /= sizeof(short)*N_CHANNELS; + return n; +#else + int nreq = frame_count * sizeof(short); + n = record->read(buffer, nreq); + if (n > 0) { + if (n != nreq) { + PLogError ( "AudioRead error: not enough data %d vs %d\n", n, nreq ); + } + n /= sizeof(short); + } + #ifdef MEASURE_SAMPLE_TIMES + if ( sample_buffers_received < MAX_SAMPLES_TO_MEASURE ) + { + gettimeofday ( &buffer_received_time, NULL ); + seconds_buffer_received [sample_buffers_received] = buffer_received_time.tv_sec; + micro_seconds_buffer_received [sample_buffers_received] = buffer_received_time.tv_usec; + samples_in_buffer [sample_buffers_received] = n; + total_samples_received += n; + sample_buffers_received++; + } + #endif + + #ifdef SAVE_RAW_AUDIO + if ( n > 0 ) + fwrite ( buffer, 2, n, audio_data ); + #endif + return n; +#endif +} + +int AudioSetVolume(int stream_type, int volume) +{ +#if defined(USE_DEV_EAC_FILE) + return 0; +#else + return AudioSystem::setStreamVolume(stream_type, (float)volume/100.0f); +#endif +} + +int AudioGetVolume(int stream_type) +{ +#if defined(USE_DEV_EAC_FILE) + return 0; +#else + float v = 0; + AudioSystem::getStreamVolume(stream_type, &v); + return int(v * 100.0f); +#endif +} + +#else + +int AudioOpen(void) +{ + return -1; +} + +int AudioClose(void) +{ + return -1; +} + +int AudioSetInputFormat(int sample_rate, int channel_count) +{ + return -1; +} + +int AudioSetOutputFormat(int sample_rate, int channel_count) +{ + return -1; +} + +int AudioRead(short *buffer, int frame_count) +{ + return -1; +} + +int AudioWrite(short *buffer, int frame_count) +{ + return -1; +} + +int AudioSetStreamType(int stream_type) +{ + return -1; +} + +int AudioSetVolume(int stream_type, int volume) +{ + return -1; +} + +int AudioGetVolume(int stream_type) +{ + return -1; +} + +#endif + +} // extern "C" diff --git a/audio/AudioIn/UNIX/src/filter.c b/audio/AudioIn/UNIX/src/filter.c new file mode 100644 index 0000000..9e983d0 --- /dev/null +++ b/audio/AudioIn/UNIX/src/filter.c @@ -0,0 +1,376 @@ +/*---------------------------------------------------------------------------* + * filter.c * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#define _ROUNDOFF + +/**************************************************************************** + * FILENAME + * pcm44pcm11.c + * + * DESCRIPTION + * + * Apply FIR filter to 44 kHz raw 16-bit PCM linear audio then + * downsample to 11 kHz. + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "filter.h" + +/**************************************************************************** + * FIR FILTER * + ****************************************************************************/ + +/* b = firls(120, [0 5000 6000 44000/2]/44000*2, [1 1 0 0]); */ +/* bRounded = round(b*2^15); */ + +const typeCoeff ps16FilterCoeff_up1_down4[] = { + + 1, 9, 13, 10, -1, -16, -24, -18, 2, 25, + 38, 28, -2, -38, -57, -42, 3, 55, 81, 60, + -3, -76, -113, -84, 4, 104, 153, 114, -5, -138, + -205, -152, 5, 183, 271, 202, -6, -241, -360, -269, + 6, 321, 482, 364, -6, -438, -667, -511, 7, 632, + 986, 778, -7, -1030, -1704, -1450, 7, 2451, 5204, 7366, + 8185, 7366, 5204, 2451, 7, -1450, -1704, -1030, -7, 778, + 986, 632, 7, -511, -667, -438, -6, 364, 482, 321, + 6, -269, -360, -241, -6, 202, 271, 183, 5, -152, + -205, -138, -5, 114, 153, 104, 4, -84, -113, -76, + -3, 60, 81, 55, 3, -42, -57, -38, -2, 28, + 38, 25, 2, -18, -24, -16, -1, 10, 13, 9, + 1, +}; +unsigned int filter_length = sizeof(ps16FilterCoeff_up1_down4)/sizeof(typeCoeff); + +/**************************************************************************** + * FIR_struct *FIR_construct(unsigned int nTaps, FIR_type *pCoeffs) + * + * DESCRIPTION + * allocate and initialize FIR structure + * + * INPUT + * nTaps - length of FIR filter + * pCoeffs - pointer to FIR filter coefficients + * scale - fixed point scale factor + * + * OUTPUT + * returns pointer to FIR structure; NULL if error + ****************************************************************************/ +FIR_struct* FIR_construct(unsigned int nTaps, const typeCoeff *pCoeffs, int scale, int factor_up, int factor_down) +{ +FIR_struct *pFIR; + + if (nTaps == 0) + return NULL; + + pFIR = malloc(sizeof(FIR_struct)); + if (pFIR == NULL) + return NULL; + + // alloocate space for delay line use calloc to avoid uninitialized memory + // that causes an audible "pop" at the beginning of audio. SteveR + pFIR->z = calloc(nTaps * sizeof(typeSample), 1); + if (pFIR->z == NULL) + { + free(pFIR); + return NULL; + } + + pFIR->factor_up = factor_up; + pFIR->factor_down = factor_down; + + pFIR->state = 0; + pFIR->h = pCoeffs; + pFIR->nTaps = nTaps; + pFIR->scale = scale; + pFIR->round = (1 << (scale-1)); + + return pFIR; +} + +/**************************************************************************** + * int FIR_deconstruct(FIR_struct *pFIR) + * + * DESCRIPTION + * deallocate FIR structure + * + * INPUT + * pFIR - pointer to FIR structure + * + * OUTPUT + * returns 0 for success; 1 for failure + ****************************************************************************/ + +int FIR_deconstruct(FIR_struct *pFIR) +{ + if (pFIR == NULL) + return 1; + + if (pFIR->z == NULL) + return 1; + + free(pFIR->z); + free(pFIR); + + return 0; +} + +/**************************************************************************** + * void FIR_reset(FIR_struct *pFIR) + * + * DESCRIPTION + * + * reset FIR state + * + * INPUT + * pFIR - pointer to FIR structure + * + * OUTPUT + * pFIR->state initialized + ****************************************************************************/ + +void FIR_reset(FIR_struct *pFIR) +{ + pFIR->state = 0; + + memset(pFIR->z, pFIR->nTaps, sizeof(typeSample)); +} + +/***************************************************************************** + * FIR_type FIR_downsample(unsigned int nInput, typeSample *pInput, + * typeSample *pOutput, FIR_struct *pFIR) + * + * DESCRIPTION + * + * Apply FIR filter to input data. If nInput > 1, this will also + * decimate by a factor of nInput. That is, the filter will only be + * evaluated every nInput samples, not at each of the nInput samples. + * + * Breakup filter computation into 2 parts to avoid doing a wraparound + * check inside the loop. + * + * Example: + * + * pFIR->nTaps = 8 + * pFIR->state = 2 + * nInput = 1 + * *pInput = s20 + * + * (a) Store new sample(s) in delay buffer z[] + * + * Since pFIR->state == 2, store new sample s20 at location z[2] + * + * *** latest input stored at z[pFIR->state] + * * + * ------------------------------------------------- + * z | s14 | s13 | s20 | s19 | s18 | s17 | s16 | s15 | + * ------------------------------------------------- + * h | h0 | h1 | h2 | h3 | h4 | h5 | h6 | h7 | + * ------------------------------------------------- + * 0 1 2 3 4 5 6 7 + * + * (b) Update state to point to newest sample, wrap if < 0 + * + * Since nInput == 1, state for newest sample is still 2 + * (otherwise, update state -= nInput-1; wrap by adding nTaps if < 0) + * + * (c) Accumulate "end part" first + * + * z: start with latest sample at z[pFIR->state], then advance to right + * h: start with 1st filter coefficient, then advance to right + * + * acc = h0*s20 + h1*s19 + h2*s18 + h3*s17 + h4*s16 + h5*s15 + * + * (d) Accumulate "beginning part" + + * z: start with sample at beginning of delay buffer, then advance + * to sample before latest one at z[pFIR->state] + * h: continue with next filter coefficient from step (a) + * + * acc += (h6*s14 + h7*s13) FIR filter output + * *pOutput = acc + * + * (e) Update FIR state + * + * state--, wrapping if < 0 to simulate circular buffer + * + * INPUT + * + * nInput - number of new input samples; evaluate FIR at this point + * pInput - pointer to input sample buffer + * pOutput - pointer to output sample buffer + * pFIR - pointer to FIR structure + * + * OUTPUT + * + *****************************************************************************/ + +void FIR_downsample(unsigned int nInput, typeSample *pInput, + typeSample *pOutput, FIR_struct *pFIR) +{ +typeAccum accum; +typeCoeff const *ph; // pointer to coefficients +typeSample *pz; // pointer to delay line +typeSample *pz_beg; // pointer to beginning of delay line +typeSample *pz_end; // pointer to last slot in delay line +unsigned int nTaps_end; +unsigned int nTaps_beg; +unsigned int i; + + // initialize + accum = 0; + ph = pFIR->h; // point to coefficients + pz_beg = pFIR->z; // start of delay line + pz_end = pFIR->z + pFIR->nTaps - 1; // end of delay line + + // (a) Store new input samples in delay line (circular addressing would help a lot) + pz = pFIR->z + pFIR->state; // point to next empty slot in delay line + for (i = 0; i < nInput; i++) + { + *pz-- = *pInput++; + if (pz < pz_beg) + pz = pz_end; // wrap around (circular buffer) + } + + // (b) adjust state to reflect addition of samples + pFIR->state -= nInput-1; + if (pFIR->state < 0) + pFIR->state += pFIR->nTaps; // wrap + + // (c) Accumulate "end part" + pz = pFIR->z + pFIR->state; + nTaps_end = pFIR->nTaps - pFIR->state; + for (i = 0; i < nTaps_end; i++) + { + accum += *ph++ * *pz++; + } + + // (d) Accumulate "beginning part" + pz = pFIR->z; + nTaps_beg = pFIR->state; + for (i = 0; i < nTaps_beg; i++) + { + accum += *ph++ * *pz++; + } + + // (e) Update FIR state for next batch of incoming samples + pFIR->state--; + if (pFIR->state < 0) + pFIR->state += pFIR->nTaps; // wrap + +#ifdef _ROUNDOFF + if (accum >= 0) + accum += pFIR->round; + else + accum -= pFIR->round; +#endif + + *pOutput = (typeSample) (accum >> pFIR->scale); +} + +#if 0 +/***************************************************************************** + * main + *****************************************************************************/ + +int main(int argc, char* argv[]) +{ +FILE *fpInputSamples; // input raw PCM file +FILE *fpOutputSamples; // output raw PCM file + +typeSample s_in[FACTOR_DOWN]; // input samples +typeSample s_out; // filtered sample +FIR_struct *pFIR; // pointer to FIR structure +int nSampleGet; // number of samples to read from input speech file +int nSampleRead; // number of samples read from input speech file +unsigned long nSampleTot; // total number of samples read so far +time_t t0; // time upon entry + + t0 = time(NULL); // get time upon entry + + // Check Command-line Parameters + if (argc != 3) + { + fprintf(stderr, "pcm44pcm11 v1.0\n"); + fprintf(stderr, " - downsamples 44 kHz to 11 kHz (16-bit PCM, Intel byte order)\n"); + fprintf(stderr, "Usage: pcm44pcm11 \n\n"); + return 0; + } + + // Open input sample file + if ((fpInputSamples = fopen(argv[1], "rb")) == NULL) + { + fprintf(stderr, "Error reading input sample file: %s\n\n", argv[1]); + exit(1); // abnormal exit + } + + // Create output sample file + if ((fpOutputSamples = fopen(argv[2], "wb")) == NULL) + { + fprintf(stderr, "Error creating output file: %s\n\n", argv[2]); + fclose(fpInputSamples); + exit(1); // abnormal exit + } + + // ************************************************************************************** + // Begin filtering... + // ************************************************************************************** + + pFIR = FIR_construct(filter_length, + ps16FilterCoeff_up1_down4, + u16ScaleFilterCoeff_up1_down4, + FACTOR_UP, + FACTOR_DOWN); + + fprintf(stdout, "Filtering...\n"); + + FIR_reset(pFIR); + + nSampleTot = 0; + while (!feof(fpInputSamples)) + { + nSampleGet = pFIR->factor_down; // if downsampling, only filter every factor_down samples + nSampleRead = fread(s_in, sizeof(typeSample), nSampleGet, fpInputSamples); + if (feof(fpInputSamples) || (nSampleRead != nSampleGet)) + break; // done with input file + nSampleTot += nSampleRead; + + FIR_downsample(nSampleRead, s_in, &s_out, pFIR); + + if (nSampleTot < pFIR->nTaps) + continue; // wait until delay buffer has been filled to skip transients + + fwrite(&s_out, sizeof(typeSample), 1, fpOutputSamples); + } + + fprintf(stdout, "\n\nTime elapsed: %d sec\n", time(NULL)-t0); + + FIR_deconstruct(pFIR); + + fclose(fpInputSamples); + fclose(fpOutputSamples); + + return 0; +} + +#endif diff --git a/audio/test/Android.mk b/audio/test/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/audio/test/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/audio/test/AudioHardwareRecord/Android.mk b/audio/test/AudioHardwareRecord/Android.mk new file mode 100644 index 0000000..cfd8b1c --- /dev/null +++ b/audio/test/AudioHardwareRecord/Android.mk @@ -0,0 +1,29 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# common settings for all ASR builds, exports some variables for sub-makes +include $(ASR_MAKE_DIR)/Makefile.defs + +LOCAL_SRC_FILES:= \ + src/AudioHardwareRecord.c \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(ASR_ROOT_DIR)/audio/AudioIn/UNIX/include \ + +LOCAL_CFLAGS := \ + +LOCAL_SHARED_LIBRARIES := \ + libUAPI_jni \ + libutils \ + libhardware \ + +LOCAL_MODULE:= AudioHardwareRecord + +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +include $(BUILD_EXECUTABLE) diff --git a/audio/test/AudioHardwareRecord/src/AudioHardwareRecord.c b/audio/test/AudioHardwareRecord/src/AudioHardwareRecord.c new file mode 100644 index 0000000..49a85fa --- /dev/null +++ b/audio/test/AudioHardwareRecord/src/AudioHardwareRecord.c @@ -0,0 +1,99 @@ +/*---------------------------------------------------------------------------* + * AudioHardwareRecord.c * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "audioinwrapper.h" + +#define SAMPLING_RATE 44100 + +#define N_FRAMES_PER_BUFFER 512 /* low-level driver counts in terms of frames, not samples */ +#define N_TUPLES_PER_FRAME 1 /* tuple: a set of samples (set of 1 if mono, set of 2 if stereo */ + +#define N_CHANNELS_PER_TUPLE 1 /* 1: mono; 2: stereo */ + +#define N_TUPLES_PER_BUFFER (N_FRAMES_PER_BUFFER * N_TUPLES_PER_FRAME) +#define N_SAMPLES_PER_BUFFER (N_TUPLES_PER_BUFFER * N_CHANNELS_PER_TUPLE) + +#define N_SECONDS_TO_RECORD 10 +#define N_SAMPLES_TO_RECORD (SAMPLING_RATE * N_SECONDS_TO_RECORD * N_CHANNELS_PER_TUPLE) + +typedef short typeSample; + +/* store incoming samples here, then write to file at the end */ +typeSample recordedSamples[N_SAMPLES_TO_RECORD]; + + +int main(int argc, char* argv[]) +{ + int rc; + unsigned int i; + + memset(recordedSamples, 0, N_SAMPLES_TO_RECORD * sizeof(typeSample)); + + rc = AudioSetInputFormat(SAMPLING_RATE, N_CHANNELS_PER_TUPLE); + if (rc != 0) + { + printf("ERROR: AudioSetInputFormat() returns %d\n", rc); + exit(1); + } + + rc = AudioOpen(); + if (rc < 0) + { + printf("ERROR: AudioOpen() returns %d (device handle/ID)\n", rc); + exit(1); + } + + i = 0; + while (i <= N_SAMPLES_TO_RECORD - N_SAMPLES_PER_BUFFER) + { + rc = AudioRead(&(recordedSamples[i]), N_FRAMES_PER_BUFFER); + if (rc > 0) + i += (rc * N_TUPLES_PER_FRAME * N_CHANNELS_PER_TUPLE); + else + printf("ERROR: AudioRead() returns %d\n", rc); + } + + rc = AudioClose(); + if (rc != 0) + { + printf("ERROR: AudioClose() returns %d\n", rc); + exit(1); + } + + /* write to file */ + { + FILE *fpOutput; + char *szFilename = "output_AudioHardwareRecord.pcm"; + + fpOutput = fopen(szFilename, "wb"); + if (fpOutput == NULL) + { + printf("ERROR: cannot create '%s'\n", szFilename); + exit(1); + } + fwrite(recordedSamples, sizeof(typeSample), i, fpOutput); + fclose(fpOutput); + } + + return 0; +} diff --git a/audio/test/AudioHardwareRecordLoop/Android.mk b/audio/test/AudioHardwareRecordLoop/Android.mk new file mode 100644 index 0000000..b7fab3a --- /dev/null +++ b/audio/test/AudioHardwareRecordLoop/Android.mk @@ -0,0 +1,29 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# common settings for all ASR builds, exports some variables for sub-makes +include $(ASR_MAKE_DIR)/Makefile.defs + +LOCAL_SRC_FILES:= \ + src/AudioHardwareRecordLoop.c \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(ASR_ROOT_DIR)/audio/AudioIn/UNIX/include \ + +LOCAL_CFLAGS := \ + +LOCAL_SHARED_LIBRARIES := \ + libUAPI_jni \ + libutils \ + libhardware \ + +LOCAL_MODULE:= AudioHardwareRecordLoop + +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +include $(BUILD_EXECUTABLE) diff --git a/audio/test/AudioHardwareRecordLoop/src/AudioHardwareRecordLoop.c b/audio/test/AudioHardwareRecordLoop/src/AudioHardwareRecordLoop.c new file mode 100644 index 0000000..9908c0b --- /dev/null +++ b/audio/test/AudioHardwareRecordLoop/src/AudioHardwareRecordLoop.c @@ -0,0 +1,140 @@ +/*---------------------------------------------------------------------------* + * AudioHardwareRecord.c * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include "audioinwrapper.h" + +#define SAMPLING_RATE 8000 + +#define N_FRAMES_PER_BUFFER 512 /* low-level driver counts in terms of frames, not samples */ +#define N_TUPLES_PER_FRAME 1 /* tuple: a set of samples (set of 1 if mono, set of 2 if stereo */ + +#define N_CHANNELS_PER_TUPLE 1 /* 1: mono; 2: stereo */ + +#define N_TUPLES_PER_BUFFER (N_FRAMES_PER_BUFFER * N_TUPLES_PER_FRAME) +#define N_SAMPLES_PER_BUFFER (N_TUPLES_PER_BUFFER * N_CHANNELS_PER_TUPLE) + +#define N_RECORDINGS 1000 +#define N_SECONDS_TO_RECORD 5 +#define N_SAMPLES_TO_RECORD (SAMPLING_RATE * N_SECONDS_TO_RECORD * N_CHANNELS_PER_TUPLE) + +typedef short typeSample; + +/* store incoming samples here, then write to file at the end */ +typeSample recordedSamples[N_SAMPLES_TO_RECORD]; + +//#define AUDIO_SET_FORMAT_ONCE_ONLY + +int main(int argc, char* argv[]) +{ + int rc; + unsigned int iFile; + + const unsigned short delay_ms = 2000; //1800 //340; + + printf("For debugging, this is configured to sleep for %u milliseconds before AudioSetInputFormat(%u)\n\n", delay_ms, SAMPLING_RATE); + +#if defined(AUDIO_SET_FORMAT_ONCE_ONLY) + rc = AudioSetInputFormat(SAMPLING_RATE, N_CHANNELS_PER_TUPLE); + if (rc != 0) + { + printf("ERROR: AudioSetInputFormat() returns %d\n", rc); + exit(1); + } +#endif + + for (iFile = 1; iFile <= N_RECORDINGS; iFile++) + { + unsigned int i; + +#if !defined(AUDIO_SET_FORMAT_ONCE_ONLY) + { + // see how much of a delay is needed to get rid of error when calling + // AudioSetInputFormat() immediately after AudioClose() + struct timeval sleep_time_struct; + sleep_time_struct.tv_sec = 0; + sleep_time_struct.tv_usec = delay_ms*1000; // microseconds + select(0, NULL, NULL, NULL, &sleep_time_struct); + } + + rc = AudioSetInputFormat(SAMPLING_RATE, N_CHANNELS_PER_TUPLE); + if (rc != 0) + { + printf("ERROR: AudioSetInputFormat() returns %d\n", rc); + exit(1); + } +#endif + + printf("Recording: %3d of %3d\n", iFile, N_RECORDINGS); + + memset(recordedSamples, 0, N_SAMPLES_TO_RECORD * sizeof(typeSample)); + + rc = AudioOpen(); + if (rc < 0) + { + printf("ERROR: AudioOpen() returns %d (device handle/ID)\n", rc); + exit(1); + } + + i = 0; + while (i <= N_SAMPLES_TO_RECORD - N_SAMPLES_PER_BUFFER) + { + rc = AudioRead(&(recordedSamples[i]), N_FRAMES_PER_BUFFER); + if (rc > 0) + i += (rc * N_TUPLES_PER_FRAME * N_CHANNELS_PER_TUPLE); + else + printf("ERROR: AudioRead() returns %d\n", rc); + } + + rc = AudioClose(); + if (rc != 0) + { + printf("ERROR: AudioClose() returns %d\n", rc); + exit(1); + } + + /* write to file */ +#if 0 + { + FILE *fpOutput; + char szFilename[256]; + + sprintf(szFilename, "output_AudioHardwareRecordLoop_%03d.pcm", iFile); + + fpOutput = fopen(szFilename, "wb"); + if (fpOutput == NULL) + { + printf("ERROR: cannot create '%s'\n", szFilename); + exit(1); + } + fwrite(recordedSamples, sizeof(typeSample), i, fpOutput); + fclose(fpOutput); + + printf("Recording: saved '%s'\n", szFilename); + } +#endif + } + + return 0; +} diff --git a/audio/test/AudioInRecord/Android.mk b/audio/test/AudioInRecord/Android.mk new file mode 100644 index 0000000..d8b6ddd --- /dev/null +++ b/audio/test/AudioInRecord/Android.mk @@ -0,0 +1,29 @@ +# Copyright 2006 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# common settings for all ASR builds, exports some variables for sub-makes +include $(ASR_MAKE_DIR)/Makefile.defs + +LOCAL_SRC_FILES:= \ + src/AudioInRecord.c \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(ASR_ROOT_DIR)/audio/AudioIn/UNIX/include \ + +LOCAL_CFLAGS := \ + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libhardware \ + libUAPI_jni \ + +LOCAL_MODULE:= AudioInRecord + +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +include $(BUILD_EXECUTABLE) diff --git a/audio/test/AudioInRecord/src/AudioInRecord.c b/audio/test/AudioInRecord/src/AudioInRecord.c new file mode 100644 index 0000000..043d09a --- /dev/null +++ b/audio/test/AudioInRecord/src/AudioInRecord.c @@ -0,0 +1,147 @@ +/*---------------------------------------------------------------------------* + * AudioInRecord.c * + * * + * Copyright 2007, 2008 Nuance Communciations, Inc. * + * * + * Licensed under the Apache License, Version 2.0 (the 'License'); * + * you may not use this file except in compliance with the License. * + * * + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an 'AS IS' BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * * + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#endif +#include "audioin.h" + +#define SAMPLING_RATE 11025 + +#define N_FRAMES_PER_BUFFER 512 /* low-level driver counts in terms of frames, not samples */ +#define N_TUPLES_PER_FRAME 1 /* tuple: a set of samples (set of 1 if mono, set of 2 if stereo */ +#define N_CHANNELS_PER_TUPLE 1 /* 1: mono; 2: stereo */ + +#define N_TUPLES_PER_BUFFER (N_FRAMES_PER_BUFFER * N_TUPLES_PER_FRAME) +#define N_SAMPLES_PER_BUFFER (N_TUPLES_PER_BUFFER * N_CHANNELS_PER_TUPLE) + +#define N_SECONDS_TO_RECORD 10 +#define N_SAMPLES_TO_RECORD (N_SECONDS_TO_RECORD * SAMPLING_RATE * N_CHANNELS_PER_TUPLE) + +#define OUTPUT_FILENAME "output_AudioInRecord.pcm" + +typedef short typeSample; + +/* store incoming samples here, then write to file at the end */ +typeSample recordedSamples[N_SAMPLES_TO_RECORD]; + + +int main(int argc, char* argv[]) +{ + AUDIOIN_H hAudioIn; + AUDIOIN_INFO AudioInInfo; + LHS_AUDIOIN_ERROR lhsErr; + unsigned int nSamples; + + printf("\nAudioTestRecord: capturing %u seconds of audio at %u Hz\n\n", N_SECONDS_TO_RECORD, SAMPLING_RATE); + + memset(recordedSamples, 0, N_SAMPLES_TO_RECORD * sizeof(typeSample)); + + printf("Opening the AudioIn device: "); + lhsErr = lhs_audioinOpen(WAVE_MAPPER, SAMPLING_RATE, &hAudioIn); + printf("lhs_audioinOpen() returns %ld\n", lhsErr); + if (lhsErr != LHS_AUDIOIN_OK) + { + printf("ERROR: Unable to open audio device\n\n"); + return 1; + } + + printf("Starting the AudioIn device: "); + lhsErr = lhs_audioinStart(hAudioIn); + printf("lhs_audioinStart() returns %ld\n", lhsErr); + if (lhsErr != LHS_AUDIOIN_OK) + { + printf("ERROR: Unable to start audio device\n\n"); + printf("Closing the AudioIn device: "); + lhsErr = lhs_audioinClose(&hAudioIn); + printf("lhs_audioinClose() returns %ld\n", lhsErr); + if (lhsErr != LHS_AUDIOIN_OK) + { + printf("ERROR: Unable to close audio device\n\n"); + return 1; + } + return 1; + } + + printf("... Start Speaking ...\n"); + + nSamples = 0; + while (nSamples <= N_SAMPLES_TO_RECORD - N_SAMPLES_PER_BUFFER) + { + unsigned long u32NbrOfSamples; + + u32NbrOfSamples = N_SAMPLES_PER_BUFFER / N_CHANNELS_PER_TUPLE; /* audioin only does mono */ + lhsErr = lhs_audioinGetSamples(hAudioIn, &u32NbrOfSamples, &(recordedSamples[nSamples]), &AudioInInfo); + if (lhsErr == LHS_AUDIOIN_OK) + nSamples += u32NbrOfSamples; + else + printf("ERROR: lhs_audioinGetSamples() returns %ld\n", lhsErr); + } + + printf("Stopping the AudioIn device: "); + lhsErr = lhs_audioinStop(hAudioIn); + printf("lhs_audioinStop() returns %ld\n", lhsErr); + if (lhsErr != LHS_AUDIOIN_OK) + { + printf("ERROR: Unable to stop audio device\n\n"); + printf("Closing the AudioIn device: "); + lhsErr = lhs_audioinClose(&hAudioIn); + printf("lhs_audioinClose() returns %ld\n", lhsErr); + if (lhsErr != LHS_AUDIOIN_OK) + { + printf("ERROR: Unable to close audio device\n\n"); + return 1; + } + return 1; + } + + printf("Closing the AudioIn device: "); + lhsErr = lhs_audioinClose(&hAudioIn); + printf("lhs_audioinClose() returns %ld\n", lhsErr); + if (lhsErr != LHS_AUDIOIN_OK) + { + printf("ERROR: Unable to close audio device\n\n"); + return 1; + } + + /* write to file */ + { + FILE *fpOutput; + char *szFilename = OUTPUT_FILENAME; + + fpOutput = fopen(szFilename, "wb"); + if (fpOutput == NULL) + { + printf("ERROR: cannot create output file: '%s'\n", szFilename); + return 1; + } + fwrite(recordedSamples, sizeof(typeSample), nSamples, fpOutput); + fclose(fpOutput); + + printf("\nOutput audio saved to '%s'\n\n", szFilename); + } + + + return 0; +} -- cgit v1.2.3