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