Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 #include "sles_allinclusive.h"
     19 #include "android_prompts.h"
     20 
     21 #include <system/audio.h>
     22 
     23 // use this flag to dump all recorded audio into a file
     24 //#define MONITOR_RECORDING
     25 #ifdef MONITOR_RECORDING
     26 #define MONITOR_TARGET "/sdcard/monitor.raw"
     27 #include <stdio.h>
     28 static FILE* gMonitorFp = NULL;
     29 #endif
     30 
     31 
     32 #define KEY_RECORDING_SOURCE_PARAMSIZE  sizeof(SLuint32)
     33 #define KEY_RECORDING_PRESET_PARAMSIZE  sizeof(SLuint32)
     34 
     35 //-----------------------------------------------------------------------------
     36 // Internal utility functions
     37 //----------------------------
     38 
     39 SLresult audioRecorder_setPreset(CAudioRecorder* ar, SLuint32 recordPreset) {
     40     SLresult result = SL_RESULT_SUCCESS;
     41 
     42     audio_source_t newRecordSource = AUDIO_SOURCE_DEFAULT;
     43     switch (recordPreset) {
     44     case SL_ANDROID_RECORDING_PRESET_GENERIC:
     45         newRecordSource = AUDIO_SOURCE_DEFAULT;
     46         break;
     47     case SL_ANDROID_RECORDING_PRESET_CAMCORDER:
     48         newRecordSource = AUDIO_SOURCE_CAMCORDER;
     49         break;
     50     case SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION:
     51         newRecordSource = AUDIO_SOURCE_VOICE_RECOGNITION;
     52         break;
     53     case SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION:
     54         newRecordSource = AUDIO_SOURCE_VOICE_COMMUNICATION;
     55         break;
     56     case SL_ANDROID_RECORDING_PRESET_NONE:
     57         // it is an error to set preset "none"
     58     default:
     59         SL_LOGE(ERROR_RECORDERPRESET_SET_UNKNOWN_PRESET);
     60         result = SL_RESULT_PARAMETER_INVALID;
     61     }
     62 
     63     // recording preset needs to be set before the object is realized
     64     // (ap->mAudioRecord is supposed to be 0 until then)
     65     if (SL_OBJECT_STATE_UNREALIZED != ar->mObject.mState) {
     66         SL_LOGE(ERROR_RECORDERPRESET_REALIZED);
     67         result = SL_RESULT_PRECONDITIONS_VIOLATED;
     68     } else {
     69         ar->mRecordSource = newRecordSource;
     70     }
     71 
     72     return result;
     73 }
     74 
     75 
     76 SLresult audioRecorder_getPreset(CAudioRecorder* ar, SLuint32* pPreset) {
     77     SLresult result = SL_RESULT_SUCCESS;
     78 
     79     switch (ar->mRecordSource) {
     80     case AUDIO_SOURCE_DEFAULT:
     81     case AUDIO_SOURCE_MIC:
     82         *pPreset = SL_ANDROID_RECORDING_PRESET_GENERIC;
     83         break;
     84     case AUDIO_SOURCE_VOICE_UPLINK:
     85     case AUDIO_SOURCE_VOICE_DOWNLINK:
     86     case AUDIO_SOURCE_VOICE_CALL:
     87         *pPreset = SL_ANDROID_RECORDING_PRESET_NONE;
     88         break;
     89     case AUDIO_SOURCE_VOICE_RECOGNITION:
     90         *pPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
     91         break;
     92     case AUDIO_SOURCE_CAMCORDER:
     93         *pPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
     94         break;
     95     case AUDIO_SOURCE_VOICE_COMMUNICATION:
     96         *pPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
     97         break;
     98     default:
     99         *pPreset = SL_ANDROID_RECORDING_PRESET_NONE;
    100         result = SL_RESULT_INTERNAL_ERROR;
    101         break;
    102     }
    103 
    104     return result;
    105 }
    106 
    107 
    108 void audioRecorder_handleNewPos_lockRecord(CAudioRecorder* ar) {
    109     //SL_LOGV("received event EVENT_NEW_POS from AudioRecord");
    110     slRecordCallback callback = NULL;
    111     void* callbackPContext = NULL;
    112 
    113     interface_lock_shared(&ar->mRecord);
    114     callback = ar->mRecord.mCallback;
    115     callbackPContext = ar->mRecord.mContext;
    116     interface_unlock_shared(&ar->mRecord);
    117 
    118     if (NULL != callback) {
    119         // getting this event implies SL_RECORDEVENT_HEADATNEWPOS was set in the event mask
    120         (*callback)(&ar->mRecord.mItf, callbackPContext, SL_RECORDEVENT_HEADATNEWPOS);
    121     }
    122 }
    123 
    124 
    125 void audioRecorder_handleMarker_lockRecord(CAudioRecorder* ar) {
    126     //SL_LOGV("received event EVENT_MARKER from AudioRecord");
    127     slRecordCallback callback = NULL;
    128     void* callbackPContext = NULL;
    129 
    130     interface_lock_shared(&ar->mRecord);
    131     callback = ar->mRecord.mCallback;
    132     callbackPContext = ar->mRecord.mContext;
    133     interface_unlock_shared(&ar->mRecord);
    134 
    135     if (NULL != callback) {
    136         // getting this event implies SL_RECORDEVENT_HEADATMARKER was set in the event mask
    137         (*callback)(&ar->mRecord.mItf, callbackPContext, SL_RECORDEVENT_HEADATMARKER);
    138     }
    139 }
    140 
    141 
    142 void audioRecorder_handleOverrun_lockRecord(CAudioRecorder* ar) {
    143     //SL_LOGV("received event EVENT_OVERRUN from AudioRecord");
    144     slRecordCallback callback = NULL;
    145     void* callbackPContext = NULL;
    146 
    147     interface_lock_shared(&ar->mRecord);
    148     if (ar->mRecord.mCallbackEventsMask & SL_RECORDEVENT_HEADSTALLED) {
    149         callback = ar->mRecord.mCallback;
    150         callbackPContext = ar->mRecord.mContext;
    151     }
    152     interface_unlock_shared(&ar->mRecord);
    153 
    154     if (NULL != callback) {
    155         (*callback)(&ar->mRecord.mItf, callbackPContext, SL_RECORDEVENT_HEADSTALLED);
    156     }
    157 }
    158 
    159 //-----------------------------------------------------------------------------
    160 SLresult android_audioRecorder_checkSourceSinkSupport(CAudioRecorder* ar) {
    161 
    162     const SLDataSource *pAudioSrc = &ar->mDataSource.u.mSource;
    163     const SLDataSink   *pAudioSnk = &ar->mDataSink.u.mSink;
    164 
    165     // Sink check:
    166     // only buffer queue sinks are supported, regardless of the data source
    167     if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE != *(SLuint32 *)pAudioSnk->pLocator) {
    168         SL_LOGE(ERROR_RECORDER_SINK_MUST_BE_ANDROIDSIMPLEBUFFERQUEUE);
    169         return SL_RESULT_PARAMETER_INVALID;
    170     } else {
    171         // only PCM buffer queues are supported
    172         SLuint32 formatType = *(SLuint32 *)pAudioSnk->pFormat;
    173         if (SL_DATAFORMAT_PCM == formatType) {
    174             SLDataFormat_PCM *df_pcm = (SLDataFormat_PCM *)ar->mDataSink.u.mSink.pFormat;
    175             ar->mSampleRateMilliHz = df_pcm->samplesPerSec;
    176             ar->mNumChannels = df_pcm->numChannels;
    177             SL_LOGV("AudioRecorder requested sample rate = %u mHz, %u channel(s)",
    178                     ar->mSampleRateMilliHz, ar->mNumChannels);
    179         }
    180         else {
    181             SL_LOGE(ERROR_RECORDER_SINK_FORMAT_MUST_BE_PCM);
    182             return SL_RESULT_PARAMETER_INVALID;
    183         }
    184     }
    185 
    186     // Source check:
    187     // only input device sources are supported
    188     // check it's an IO device
    189     if (SL_DATALOCATOR_IODEVICE != *(SLuint32 *)pAudioSrc->pLocator) {
    190         SL_LOGE(ERROR_RECORDER_SOURCE_MUST_BE_IODEVICE);
    191         return SL_RESULT_PARAMETER_INVALID;
    192     } else {
    193 
    194         // check it's an input device
    195         SLDataLocator_IODevice *dl_iod = (SLDataLocator_IODevice *) pAudioSrc->pLocator;
    196         if (SL_IODEVICE_AUDIOINPUT != dl_iod->deviceType) {
    197             SL_LOGE(ERROR_RECORDER_IODEVICE_MUST_BE_AUDIOINPUT);
    198             return SL_RESULT_PARAMETER_INVALID;
    199         }
    200 
    201         // check it's the default input device, others aren't supported here
    202         if (SL_DEFAULTDEVICEID_AUDIOINPUT != dl_iod->deviceID) {
    203             SL_LOGE(ERROR_RECORDER_INPUT_ID_MUST_BE_DEFAULT);
    204             return SL_RESULT_PARAMETER_INVALID;
    205         }
    206     }
    207 
    208     return SL_RESULT_SUCCESS;
    209 }
    210 //-----------------------------------------------------------------------------
    211 static void audioRecorder_callback(int event, void* user, void *info) {
    212     //SL_LOGV("audioRecorder_callback(%d, %p, %p) entering", event, user, info);
    213 
    214     CAudioRecorder *ar = (CAudioRecorder *)user;
    215 
    216     if (!android::CallbackProtector::enterCbIfOk(ar->mCallbackProtector)) {
    217         // it is not safe to enter the callback (the track is about to go away)
    218         return;
    219     }
    220 
    221     void * callbackPContext = NULL;
    222 
    223     switch(event) {
    224     case android::AudioRecord::EVENT_MORE_DATA: {
    225         slBufferQueueCallback callback = NULL;
    226         android::AudioRecord::Buffer* pBuff = (android::AudioRecord::Buffer*)info;
    227 
    228         // push data to the buffer queue
    229         interface_lock_exclusive(&ar->mBufferQueue);
    230 
    231         if (ar->mBufferQueue.mState.count != 0) {
    232             assert(ar->mBufferQueue.mFront != ar->mBufferQueue.mRear);
    233 
    234             BufferHeader *oldFront = ar->mBufferQueue.mFront;
    235             BufferHeader *newFront = &oldFront[1];
    236 
    237             // FIXME handle 8bit based on buffer format
    238             short *pDest = (short*)((char *)oldFront->mBuffer + ar->mBufferQueue.mSizeConsumed);
    239             if (ar->mBufferQueue.mSizeConsumed + pBuff->size < oldFront->mSize) {
    240                 // can't consume the whole or rest of the buffer in one shot
    241                 ar->mBufferQueue.mSizeConsumed += pBuff->size;
    242                 // leave pBuff->size untouched
    243                 // consume data
    244                 // FIXME can we avoid holding the lock during the copy?
    245                 memcpy (pDest, pBuff->i16, pBuff->size);
    246 #ifdef MONITOR_RECORDING
    247                 if (NULL != gMonitorFp) { fwrite(pBuff->i16, pBuff->size, 1, gMonitorFp); }
    248 #endif
    249             } else {
    250                 // finish pushing the buffer or push the buffer in one shot
    251                 pBuff->size = oldFront->mSize - ar->mBufferQueue.mSizeConsumed;
    252                 ar->mBufferQueue.mSizeConsumed = 0;
    253                 if (newFront == &ar->mBufferQueue.mArray[ar->mBufferQueue.mNumBuffers + 1]) {
    254                     newFront = ar->mBufferQueue.mArray;
    255                 }
    256                 ar->mBufferQueue.mFront = newFront;
    257 
    258                 ar->mBufferQueue.mState.count--;
    259                 ar->mBufferQueue.mState.playIndex++;
    260                 // consume data
    261                 // FIXME can we avoid holding the lock during the copy?
    262                 memcpy (pDest, pBuff->i16, pBuff->size);
    263 #ifdef MONITOR_RECORDING
    264                 if (NULL != gMonitorFp) { fwrite(pBuff->i16, pBuff->size, 1, gMonitorFp); }
    265 #endif
    266                 // data has been copied to the buffer, and the buffer queue state has been updated
    267                 // we will notify the client if applicable
    268                 callback = ar->mBufferQueue.mCallback;
    269                 // save callback data
    270                 callbackPContext = ar->mBufferQueue.mContext;
    271             }
    272         } else {
    273             // no destination to push the data
    274             pBuff->size = 0;
    275         }
    276 
    277         interface_unlock_exclusive(&ar->mBufferQueue);
    278         // notify client
    279         if (NULL != callback) {
    280             (*callback)(&ar->mBufferQueue.mItf, callbackPContext);
    281         }
    282         }
    283         break;
    284 
    285     case android::AudioRecord::EVENT_OVERRUN:
    286         audioRecorder_handleOverrun_lockRecord(ar);
    287         break;
    288 
    289     case android::AudioRecord::EVENT_MARKER:
    290         audioRecorder_handleMarker_lockRecord(ar);
    291         break;
    292 
    293     case android::AudioRecord::EVENT_NEW_POS:
    294         audioRecorder_handleNewPos_lockRecord(ar);
    295         break;
    296 
    297     }
    298 
    299     ar->mCallbackProtector->exitCb();
    300 }
    301 
    302 
    303 //-----------------------------------------------------------------------------
    304 SLresult android_audioRecorder_create(CAudioRecorder* ar) {
    305     SL_LOGV("android_audioRecorder_create(%p) entering", ar);
    306 
    307     const SLDataSource *pAudioSrc = &ar->mDataSource.u.mSource;
    308     const SLDataSink *pAudioSnk = &ar->mDataSink.u.mSink;
    309     SLresult result = SL_RESULT_SUCCESS;
    310 
    311     const SLuint32 sourceLocatorType = *(SLuint32 *)pAudioSrc->pLocator;
    312     const SLuint32 sinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator;
    313 
    314     //  the following platform-independent fields have been initialized in CreateAudioRecorder()
    315     //    ar->mNumChannels
    316     //    ar->mSampleRateMilliHz
    317 
    318     if ((SL_DATALOCATOR_IODEVICE == sourceLocatorType) &&
    319             (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE == sinkLocatorType)) {
    320         // microphone to simple buffer queue
    321         ar->mAndroidObjType = AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE;
    322         ar->mAudioRecord.clear();
    323         ar->mCallbackProtector = new android::CallbackProtector();
    324         ar->mRecordSource = AUDIO_SOURCE_DEFAULT;
    325     } else {
    326         result = SL_RESULT_CONTENT_UNSUPPORTED;
    327     }
    328 
    329     return result;
    330 }
    331 
    332 
    333 //-----------------------------------------------------------------------------
    334 SLresult android_audioRecorder_setConfig(CAudioRecorder* ar, const SLchar *configKey,
    335         const void *pConfigValue, SLuint32 valueSize) {
    336 
    337     SLresult result;
    338 
    339     assert(NULL != ar && NULL != configKey && NULL != pConfigValue);
    340     if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
    341 
    342         // recording preset
    343         if (KEY_RECORDING_PRESET_PARAMSIZE > valueSize) {
    344             SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
    345             result = SL_RESULT_BUFFER_INSUFFICIENT;
    346         } else {
    347             result = audioRecorder_setPreset(ar, *(SLuint32*)pConfigValue);
    348         }
    349 
    350     } else {
    351         SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
    352         result = SL_RESULT_PARAMETER_INVALID;
    353     }
    354 
    355     return result;
    356 }
    357 
    358 
    359 //-----------------------------------------------------------------------------
    360 SLresult android_audioRecorder_getConfig(CAudioRecorder* ar, const SLchar *configKey,
    361         SLuint32* pValueSize, void *pConfigValue) {
    362 
    363     SLresult result;
    364 
    365     assert(NULL != ar && NULL != configKey && NULL != pValueSize);
    366     if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
    367 
    368         // recording preset
    369         if (NULL == pConfigValue) {
    370             result = SL_RESULT_SUCCESS;
    371         } else if (KEY_RECORDING_PRESET_PARAMSIZE > *pValueSize) {
    372             SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
    373             result = SL_RESULT_BUFFER_INSUFFICIENT;
    374         } else {
    375             result = audioRecorder_getPreset(ar, (SLuint32*)pConfigValue);
    376         }
    377         *pValueSize = KEY_RECORDING_PRESET_PARAMSIZE;
    378 
    379     } else {
    380         SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
    381         result = SL_RESULT_PARAMETER_INVALID;
    382     }
    383 
    384     return result;
    385 }
    386 
    387 
    388 //-----------------------------------------------------------------------------
    389 SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
    390     SL_LOGV("android_audioRecorder_realize(%p) entering", ar);
    391 
    392     SLresult result = SL_RESULT_SUCCESS;
    393 
    394     // initialize platform-independent CAudioRecorder fields
    395     if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE != ar->mDataSink.mLocator.mLocatorType) {
    396         SL_LOGE(ERROR_RECORDER_SINK_MUST_BE_ANDROIDSIMPLEBUFFERQUEUE);
    397         return SL_RESULT_CONTENT_UNSUPPORTED;
    398     }
    399     //  the following platform-independent fields have been initialized in CreateAudioRecorder()
    400     //    ar->mNumChannels
    401     //    ar->mSampleRateMilliHz
    402 
    403     SL_LOGV("new AudioRecord %u channels, %u mHz", ar->mNumChannels, ar->mSampleRateMilliHz);
    404 
    405     // currently nothing analogous to canUseFastTrack() for recording
    406     audio_input_flags_t policy = AUDIO_INPUT_FLAG_FAST;
    407 
    408     // initialize platform-specific CAudioRecorder fields
    409     ar->mAudioRecord = new android::AudioRecord();
    410     ar->mAudioRecord->set(ar->mRecordSource, // source
    411             sles_to_android_sampleRate(ar->mSampleRateMilliHz), // sample rate in Hertz
    412             AUDIO_FORMAT_PCM_16_BIT,   //FIXME use format from buffer queue sink
    413             sles_to_android_channelMaskIn(ar->mNumChannels, 0 /*no channel mask*/),
    414                                    // channel config
    415             0,                     //frameCount min
    416             audioRecorder_callback,// callback_t
    417             (void*)ar,             // user, callback data, here the AudioRecorder
    418             0,                     // notificationFrames
    419             false,                 // threadCanCallJava, note: this will prevent direct Java
    420                                    //   callbacks, but we don't want them in the recording loop
    421             0,                     // session ID
    422             android::AudioRecord::TRANSFER_CALLBACK,
    423                                    // transfer type
    424             policy);               // audio_input_flags_t
    425 
    426     if (android::NO_ERROR != ar->mAudioRecord->initCheck()) {
    427         SL_LOGE("android_audioRecorder_realize(%p) error creating AudioRecord object", ar);
    428         result = SL_RESULT_CONTENT_UNSUPPORTED;
    429     }
    430 
    431 #ifdef MONITOR_RECORDING
    432     gMonitorFp = fopen(MONITOR_TARGET, "w");
    433     if (NULL == gMonitorFp) { SL_LOGE("error opening %s", MONITOR_TARGET); }
    434     else { SL_LOGE("recording to %s", MONITOR_TARGET); } // SL_LOGE so it's always displayed
    435 #endif
    436 
    437     return result;
    438 }
    439 
    440 
    441 //-----------------------------------------------------------------------------
    442 /**
    443  * Called with a lock on AudioRecorder, and blocks until safe to destroy
    444  */
    445 void android_audioRecorder_preDestroy(CAudioRecorder* ar) {
    446     object_unlock_exclusive(&ar->mObject);
    447     if (ar->mCallbackProtector != 0) {
    448         ar->mCallbackProtector->requestCbExitAndWait();
    449     }
    450     object_lock_exclusive(&ar->mObject);
    451 }
    452 
    453 
    454 //-----------------------------------------------------------------------------
    455 void android_audioRecorder_destroy(CAudioRecorder* ar) {
    456     SL_LOGV("android_audioRecorder_destroy(%p) entering", ar);
    457 
    458     if (ar->mAudioRecord != 0) {
    459         ar->mAudioRecord->stop();
    460         ar->mAudioRecord.clear();
    461     }
    462     // explicit destructor
    463     ar->mAudioRecord.~sp();
    464     ar->mCallbackProtector.~sp();
    465 
    466 #ifdef MONITOR_RECORDING
    467     if (NULL != gMonitorFp) {
    468         fclose(gMonitorFp);
    469         gMonitorFp = NULL;
    470     }
    471 #endif
    472 }
    473 
    474 
    475 //-----------------------------------------------------------------------------
    476 void android_audioRecorder_setRecordState(CAudioRecorder* ar, SLuint32 state) {
    477     SL_LOGV("android_audioRecorder_setRecordState(%p, %u) entering", ar, state);
    478 
    479     if (ar->mAudioRecord == 0) {
    480         return;
    481     }
    482 
    483     switch (state) {
    484      case SL_RECORDSTATE_STOPPED:
    485          ar->mAudioRecord->stop();
    486          break;
    487      case SL_RECORDSTATE_PAUSED:
    488          // Note that pausing is treated like stop as this implementation only records to a buffer
    489          //  queue, so there is no notion of destination being "opened" or "closed" (See description
    490          //  of SL_RECORDSTATE in specification)
    491          ar->mAudioRecord->stop();
    492          break;
    493      case SL_RECORDSTATE_RECORDING:
    494          ar->mAudioRecord->start();
    495          break;
    496      default:
    497          break;
    498      }
    499 
    500 }
    501 
    502 
    503 //-----------------------------------------------------------------------------
    504 void android_audioRecorder_useRecordEventMask(CAudioRecorder *ar) {
    505     IRecord *pRecordItf = &ar->mRecord;
    506     SLuint32 eventFlags = pRecordItf->mCallbackEventsMask;
    507 
    508     if (ar->mAudioRecord == 0) {
    509         return;
    510     }
    511 
    512     if ((eventFlags & SL_RECORDEVENT_HEADATMARKER) && (pRecordItf->mMarkerPosition != 0)) {
    513         ar->mAudioRecord->setMarkerPosition((uint32_t)((((int64_t)pRecordItf->mMarkerPosition
    514                 * sles_to_android_sampleRate(ar->mSampleRateMilliHz)))/1000));
    515     } else {
    516         // clear marker
    517         ar->mAudioRecord->setMarkerPosition(0);
    518     }
    519 
    520     if (eventFlags & SL_RECORDEVENT_HEADATNEWPOS) {
    521         SL_LOGV("pos update period %d", pRecordItf->mPositionUpdatePeriod);
    522          ar->mAudioRecord->setPositionUpdatePeriod(
    523                 (uint32_t)((((int64_t)pRecordItf->mPositionUpdatePeriod
    524                 * sles_to_android_sampleRate(ar->mSampleRateMilliHz)))/1000));
    525     } else {
    526         // clear periodic update
    527         ar->mAudioRecord->setPositionUpdatePeriod(0);
    528     }
    529 
    530     if (eventFlags & SL_RECORDEVENT_HEADATLIMIT) {
    531         // FIXME support SL_RECORDEVENT_HEADATLIMIT
    532         SL_LOGD("[ FIXME: IRecord_SetCallbackEventsMask(SL_RECORDEVENT_HEADATLIMIT) on an "
    533                     "SL_OBJECTID_AUDIORECORDER to be implemented ]");
    534     }
    535 
    536     if (eventFlags & SL_RECORDEVENT_HEADMOVING) {
    537         // FIXME support SL_RECORDEVENT_HEADMOVING
    538         SL_LOGD("[ FIXME: IRecord_SetCallbackEventsMask(SL_RECORDEVENT_HEADMOVING) on an "
    539                 "SL_OBJECTID_AUDIORECORDER to be implemented ]");
    540     }
    541 
    542     if (eventFlags & SL_RECORDEVENT_BUFFER_FULL) {
    543         // nothing to do for SL_RECORDEVENT_BUFFER_FULL since this will not be encountered on
    544         // recording to buffer queues
    545     }
    546 
    547     if (eventFlags & SL_RECORDEVENT_HEADSTALLED) {
    548         // nothing to do for SL_RECORDEVENT_HEADSTALLED, callback event will be checked against mask
    549         // when AudioRecord::EVENT_OVERRUN is encountered
    550 
    551     }
    552 
    553 }
    554 
    555 
    556 //-----------------------------------------------------------------------------
    557 void android_audioRecorder_getPosition(CAudioRecorder *ar, SLmillisecond *pPosMsec) {
    558     if ((NULL == ar) || (ar->mAudioRecord == 0)) {
    559         *pPosMsec = 0;
    560     } else {
    561         uint32_t positionInFrames;
    562         ar->mAudioRecord->getPosition(&positionInFrames);
    563         if (ar->mSampleRateMilliHz == UNKNOWN_SAMPLERATE) {
    564             *pPosMsec = 0;
    565         } else {
    566             *pPosMsec = ((int64_t)positionInFrames * 1000) /
    567                     sles_to_android_sampleRate(ar->mSampleRateMilliHz);
    568         }
    569     }
    570 }
    571