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 
audioRecorder_setPreset(CAudioRecorder * ar,SLuint32 recordPreset)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 
audioRecorder_getPreset(CAudioRecorder * ar,SLuint32 * pPreset)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 
audioRecorder_handleNewPos_lockRecord(CAudioRecorder * ar)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 
audioRecorder_handleMarker_lockRecord(CAudioRecorder * ar)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 
audioRecorder_handleOverrun_lockRecord(CAudioRecorder * ar)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 //-----------------------------------------------------------------------------
android_audioRecorder_checkSourceSinkSupport(CAudioRecorder * ar)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 //-----------------------------------------------------------------------------
audioRecorder_callback(int event,void * user,void * info)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 //-----------------------------------------------------------------------------
android_audioRecorder_create(CAudioRecorder * ar)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 //-----------------------------------------------------------------------------
android_audioRecorder_setConfig(CAudioRecorder * ar,const SLchar * configKey,const void * pConfigValue,SLuint32 valueSize)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 //-----------------------------------------------------------------------------
android_audioRecorder_getConfig(CAudioRecorder * ar,const SLchar * configKey,SLuint32 * pValueSize,void * pConfigValue)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 //-----------------------------------------------------------------------------
android_audioRecorder_realize(CAudioRecorder * ar,SLboolean async)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  */
android_audioRecorder_preDestroy(CAudioRecorder * ar)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 //-----------------------------------------------------------------------------
android_audioRecorder_destroy(CAudioRecorder * ar)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 //-----------------------------------------------------------------------------
android_audioRecorder_setRecordState(CAudioRecorder * ar,SLuint32 state)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 //-----------------------------------------------------------------------------
android_audioRecorder_useRecordEventMask(CAudioRecorder * ar)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 //-----------------------------------------------------------------------------
android_audioRecorder_getPosition(CAudioRecorder * ar,SLmillisecond * pPosMsec)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