AudioRecorder_to_android.cpp revision 904b880cdd214729d04b2cbd374287c3bb6c6606
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    // Sink check:
159    // only buffer queue sinks are supported, regardless of the data source
160    if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE != *(SLuint32 *)pAudioSnk->pLocator) {
161        SL_LOGE(ERROR_RECORDER_SINK_MUST_BE_ANDROIDSIMPLEBUFFERQUEUE);
162        return SL_RESULT_PARAMETER_INVALID;
163    } else {
164        // only PCM buffer queues are supported
165        SLuint32 formatType = *(SLuint32 *)pAudioSnk->pFormat;
166        if (SL_DATAFORMAT_PCM == formatType) {
167            SLDataFormat_PCM *df_pcm = (SLDataFormat_PCM *)ar->mDataSink.u.mSink.pFormat;
168            ar->mSampleRateMilliHz = df_pcm->samplesPerSec;
169            ar->mNumChannels = df_pcm->numChannels;
170            SL_LOGV("AudioRecorder requested sample rate = %u mHz, %u channel(s)",
171                    ar->mSampleRateMilliHz, ar->mNumChannels);
172        }
173        else {
174            SL_LOGE(ERROR_RECORDER_SINK_FORMAT_MUST_BE_PCM);
175            return SL_RESULT_PARAMETER_INVALID;
176        }
177    }
178
179    // Source check:
180    // only input device sources are supported
181    // check it's an IO device
182    if (SL_DATALOCATOR_IODEVICE != *(SLuint32 *)pAudioSrc->pLocator) {
183        SL_LOGE(ERROR_RECORDER_SOURCE_MUST_BE_IODEVICE);
184        return SL_RESULT_PARAMETER_INVALID;
185    } else {
186
187        // check it's an input device
188        SLDataLocator_IODevice *dl_iod = (SLDataLocator_IODevice *) pAudioSrc->pLocator;
189        if (SL_IODEVICE_AUDIOINPUT != dl_iod->deviceType) {
190            SL_LOGE(ERROR_RECORDER_IODEVICE_MUST_BE_AUDIOINPUT);
191            return SL_RESULT_PARAMETER_INVALID;
192        }
193
194        // check it's the default input device, others aren't supported here
195        if (SL_DEFAULTDEVICEID_AUDIOINPUT != dl_iod->deviceID) {
196            SL_LOGE(ERROR_RECORDER_INPUT_ID_MUST_BE_DEFAULT);
197            return SL_RESULT_PARAMETER_INVALID;
198        }
199    }
200
201    return SL_RESULT_SUCCESS;
202}
203//-----------------------------------------------------------------------------
204static void audioRecorder_callback(int event, void* user, void *info) {
205    //SL_LOGV("audioRecorder_callback(%d, %p, %p) entering", event, user, info);
206
207    CAudioRecorder *ar = (CAudioRecorder *)user;
208
209    if (!android::CallbackProtector::enterCbIfOk(ar->mCallbackProtector)) {
210        // it is not safe to enter the callback (the track is about to go away)
211        return;
212    }
213
214    void * callbackPContext = NULL;
215
216    switch (event) {
217    case android::AudioRecord::EVENT_MORE_DATA: {
218        slBufferQueueCallback callback = NULL;
219        android::AudioRecord::Buffer* pBuff = (android::AudioRecord::Buffer*)info;
220
221        // push data to the buffer queue
222        interface_lock_exclusive(&ar->mBufferQueue);
223
224        if (ar->mBufferQueue.mState.count != 0) {
225            assert(ar->mBufferQueue.mFront != ar->mBufferQueue.mRear);
226
227            BufferHeader *oldFront = ar->mBufferQueue.mFront;
228            BufferHeader *newFront = &oldFront[1];
229
230            // FIXME handle 8bit based on buffer format
231            short *pDest = (short*)((char *)oldFront->mBuffer + ar->mBufferQueue.mSizeConsumed);
232            if (ar->mBufferQueue.mSizeConsumed + pBuff->size < oldFront->mSize) {
233                // can't consume the whole or rest of the buffer in one shot
234                ar->mBufferQueue.mSizeConsumed += pBuff->size;
235                // leave pBuff->size untouched
236                // consume data
237                // FIXME can we avoid holding the lock during the copy?
238                memcpy (pDest, pBuff->i16, pBuff->size);
239            } else {
240                // finish pushing the buffer or push the buffer in one shot
241                pBuff->size = oldFront->mSize - ar->mBufferQueue.mSizeConsumed;
242                ar->mBufferQueue.mSizeConsumed = 0;
243                if (newFront == &ar->mBufferQueue.mArray[ar->mBufferQueue.mNumBuffers + 1]) {
244                    newFront = ar->mBufferQueue.mArray;
245                }
246                ar->mBufferQueue.mFront = newFront;
247
248                ar->mBufferQueue.mState.count--;
249                ar->mBufferQueue.mState.playIndex++;
250                // consume data
251                // FIXME can we avoid holding the lock during the copy?
252                memcpy (pDest, pBuff->i16, pBuff->size);
253                // data has been copied to the buffer, and the buffer queue state has been updated
254                // we will notify the client if applicable
255                callback = ar->mBufferQueue.mCallback;
256                // save callback data
257                callbackPContext = ar->mBufferQueue.mContext;
258            }
259        } else {
260            // no destination to push the data
261            pBuff->size = 0;
262        }
263
264        interface_unlock_exclusive(&ar->mBufferQueue);
265        // notify client
266        if (NULL != callback) {
267            (*callback)(&ar->mBufferQueue.mItf, callbackPContext);
268        }
269        }
270        break;
271
272    case android::AudioRecord::EVENT_OVERRUN:
273        audioRecorder_handleOverrun_lockRecord(ar);
274        break;
275
276    case android::AudioRecord::EVENT_MARKER:
277        audioRecorder_handleMarker_lockRecord(ar);
278        break;
279
280    case android::AudioRecord::EVENT_NEW_POS:
281        audioRecorder_handleNewPos_lockRecord(ar);
282        break;
283
284    case android::AudioRecord::EVENT_NEW_IAUDIORECORD:
285        // ignore for now
286        break;
287
288    default:
289        SL_LOGE("Encountered unknown AudioRecord event %d for CAudioRecord %p", event, ar);
290        break;
291    }
292
293    ar->mCallbackProtector->exitCb();
294}
295
296
297//-----------------------------------------------------------------------------
298SLresult android_audioRecorder_create(CAudioRecorder* ar) {
299    SL_LOGV("android_audioRecorder_create(%p) entering", ar);
300
301    const SLDataSource *pAudioSrc = &ar->mDataSource.u.mSource;
302    const SLDataSink *pAudioSnk = &ar->mDataSink.u.mSink;
303    SLresult result = SL_RESULT_SUCCESS;
304
305    const SLuint32 sourceLocatorType = *(SLuint32 *)pAudioSrc->pLocator;
306    const SLuint32 sinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator;
307
308    //  the following platform-independent fields have been initialized in CreateAudioRecorder()
309    //    ar->mNumChannels
310    //    ar->mSampleRateMilliHz
311
312    if ((SL_DATALOCATOR_IODEVICE == sourceLocatorType) &&
313            (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE == sinkLocatorType)) {
314        // microphone to simple buffer queue
315        ar->mAndroidObjType = AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE;
316        ar->mAudioRecord.clear();
317        ar->mCallbackProtector = new android::CallbackProtector();
318        ar->mRecordSource = AUDIO_SOURCE_DEFAULT;
319    } else {
320        result = SL_RESULT_CONTENT_UNSUPPORTED;
321    }
322
323    return result;
324}
325
326
327//-----------------------------------------------------------------------------
328SLresult android_audioRecorder_setConfig(CAudioRecorder* ar, const SLchar *configKey,
329        const void *pConfigValue, SLuint32 valueSize) {
330
331    SLresult result;
332
333    assert(NULL != ar && NULL != configKey && NULL != pConfigValue);
334    if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
335
336        // recording preset
337        if (KEY_RECORDING_PRESET_PARAMSIZE > valueSize) {
338            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
339            result = SL_RESULT_BUFFER_INSUFFICIENT;
340        } else {
341            result = audioRecorder_setPreset(ar, *(SLuint32*)pConfigValue);
342        }
343
344    } else {
345        SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
346        result = SL_RESULT_PARAMETER_INVALID;
347    }
348
349    return result;
350}
351
352
353//-----------------------------------------------------------------------------
354SLresult android_audioRecorder_getConfig(CAudioRecorder* ar, const SLchar *configKey,
355        SLuint32* pValueSize, void *pConfigValue) {
356
357    SLresult result;
358
359    assert(NULL != ar && NULL != configKey && NULL != pValueSize);
360    if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
361
362        // recording preset
363        if (NULL == pConfigValue) {
364            result = SL_RESULT_SUCCESS;
365        } else if (KEY_RECORDING_PRESET_PARAMSIZE > *pValueSize) {
366            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
367            result = SL_RESULT_BUFFER_INSUFFICIENT;
368        } else {
369            result = audioRecorder_getPreset(ar, (SLuint32*)pConfigValue);
370        }
371        *pValueSize = KEY_RECORDING_PRESET_PARAMSIZE;
372
373    } else {
374        SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
375        result = SL_RESULT_PARAMETER_INVALID;
376    }
377
378    return result;
379}
380
381
382//-----------------------------------------------------------------------------
383SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
384    SL_LOGV("android_audioRecorder_realize(%p) entering", ar);
385
386    SLresult result = SL_RESULT_SUCCESS;
387
388    // initialize platform-independent CAudioRecorder fields
389    if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE != ar->mDataSink.mLocator.mLocatorType) {
390        SL_LOGE(ERROR_RECORDER_SINK_MUST_BE_ANDROIDSIMPLEBUFFERQUEUE);
391        return SL_RESULT_CONTENT_UNSUPPORTED;
392    }
393    //  the following platform-independent fields have been initialized in CreateAudioRecorder()
394    //    ar->mNumChannels
395    //    ar->mSampleRateMilliHz
396
397    SL_LOGV("new AudioRecord %u channels, %u mHz", ar->mNumChannels, ar->mSampleRateMilliHz);
398
399    // currently nothing analogous to canUseFastTrack() for recording
400    audio_input_flags_t policy = AUDIO_INPUT_FLAG_FAST;
401
402    // initialize platform-specific CAudioRecorder fields
403    ar->mAudioRecord = new android::AudioRecord(android::String16());
404    android::status_t status = ar->mAudioRecord->set(
405            ar->mRecordSource,     // source
406            sles_to_android_sampleRate(ar->mSampleRateMilliHz), // sample rate in Hertz
407            AUDIO_FORMAT_PCM_16_BIT,   //FIXME use format from buffer queue sink
408            sles_to_android_channelMaskIn(ar->mNumChannels, 0 /*no channel mask*/),
409                                   // channel config
410            0,                     //frameCount min
411            audioRecorder_callback,// callback_t
412            (void*)ar,             // user, callback data, here the AudioRecorder
413            0,                     // notificationFrames
414            false,                 // threadCanCallJava, note: this will prevent direct Java
415                                   //   callbacks, but we don't want them in the recording loop
416            0,                     // session ID
417            android::AudioRecord::TRANSFER_CALLBACK,
418                                   // transfer type
419            policy);               // audio_input_flags_t
420
421    if (android::NO_ERROR != status) {
422        SL_LOGE("android_audioRecorder_realize(%p) error creating AudioRecord object; status %d",
423                ar, status);
424        // FIXME should return a more specific result depending on status
425        result = SL_RESULT_CONTENT_UNSUPPORTED;
426        ar->mAudioRecord.clear();
427    }
428
429    return result;
430}
431
432
433//-----------------------------------------------------------------------------
434/**
435 * Called with a lock on AudioRecorder, and blocks until safe to destroy
436 */
437void android_audioRecorder_preDestroy(CAudioRecorder* ar) {
438    object_unlock_exclusive(&ar->mObject);
439    if (ar->mCallbackProtector != 0) {
440        ar->mCallbackProtector->requestCbExitAndWait();
441    }
442    object_lock_exclusive(&ar->mObject);
443}
444
445
446//-----------------------------------------------------------------------------
447void android_audioRecorder_destroy(CAudioRecorder* ar) {
448    SL_LOGV("android_audioRecorder_destroy(%p) entering", ar);
449
450    if (ar->mAudioRecord != 0) {
451        ar->mAudioRecord->stop();
452        ar->mAudioRecord.clear();
453    }
454    // explicit destructor
455    ar->mAudioRecord.~sp();
456    ar->mCallbackProtector.~sp();
457}
458
459
460//-----------------------------------------------------------------------------
461void android_audioRecorder_setRecordState(CAudioRecorder* ar, SLuint32 state) {
462    SL_LOGV("android_audioRecorder_setRecordState(%p, %u) entering", ar, state);
463
464    if (ar->mAudioRecord == 0) {
465        return;
466    }
467
468    switch (state) {
469     case SL_RECORDSTATE_STOPPED:
470         ar->mAudioRecord->stop();
471         break;
472     case SL_RECORDSTATE_PAUSED:
473         // Note that pausing is treated like stop as this implementation only records to a buffer
474         //  queue, so there is no notion of destination being "opened" or "closed" (See description
475         //  of SL_RECORDSTATE in specification)
476         ar->mAudioRecord->stop();
477         break;
478     case SL_RECORDSTATE_RECORDING:
479         ar->mAudioRecord->start();
480         break;
481     default:
482         break;
483     }
484
485}
486
487
488//-----------------------------------------------------------------------------
489void android_audioRecorder_useRecordEventMask(CAudioRecorder *ar) {
490    IRecord *pRecordItf = &ar->mRecord;
491    SLuint32 eventFlags = pRecordItf->mCallbackEventsMask;
492
493    if (ar->mAudioRecord == 0) {
494        return;
495    }
496
497    if ((eventFlags & SL_RECORDEVENT_HEADATMARKER) && (pRecordItf->mMarkerPosition != 0)) {
498        ar->mAudioRecord->setMarkerPosition((uint32_t)((((int64_t)pRecordItf->mMarkerPosition
499                * sles_to_android_sampleRate(ar->mSampleRateMilliHz)))/1000));
500    } else {
501        // clear marker
502        ar->mAudioRecord->setMarkerPosition(0);
503    }
504
505    if (eventFlags & SL_RECORDEVENT_HEADATNEWPOS) {
506        SL_LOGV("pos update period %d", pRecordItf->mPositionUpdatePeriod);
507         ar->mAudioRecord->setPositionUpdatePeriod(
508                (uint32_t)((((int64_t)pRecordItf->mPositionUpdatePeriod
509                * sles_to_android_sampleRate(ar->mSampleRateMilliHz)))/1000));
510    } else {
511        // clear periodic update
512        ar->mAudioRecord->setPositionUpdatePeriod(0);
513    }
514
515    if (eventFlags & SL_RECORDEVENT_HEADATLIMIT) {
516        // FIXME support SL_RECORDEVENT_HEADATLIMIT
517        SL_LOGD("[ FIXME: IRecord_SetCallbackEventsMask(SL_RECORDEVENT_HEADATLIMIT) on an "
518                    "SL_OBJECTID_AUDIORECORDER to be implemented ]");
519    }
520
521    if (eventFlags & SL_RECORDEVENT_HEADMOVING) {
522        // FIXME support SL_RECORDEVENT_HEADMOVING
523        SL_LOGD("[ FIXME: IRecord_SetCallbackEventsMask(SL_RECORDEVENT_HEADMOVING) on an "
524                "SL_OBJECTID_AUDIORECORDER to be implemented ]");
525    }
526
527    if (eventFlags & SL_RECORDEVENT_BUFFER_FULL) {
528        // nothing to do for SL_RECORDEVENT_BUFFER_FULL since this will not be encountered on
529        // recording to buffer queues
530    }
531
532    if (eventFlags & SL_RECORDEVENT_HEADSTALLED) {
533        // nothing to do for SL_RECORDEVENT_HEADSTALLED, callback event will be checked against mask
534        // when AudioRecord::EVENT_OVERRUN is encountered
535
536    }
537
538}
539
540
541//-----------------------------------------------------------------------------
542void android_audioRecorder_getPosition(CAudioRecorder *ar, SLmillisecond *pPosMsec) {
543    if ((NULL == ar) || (ar->mAudioRecord == 0)) {
544        *pPosMsec = 0;
545    } else {
546        uint32_t positionInFrames;
547        ar->mAudioRecord->getPosition(&positionInFrames);
548        if (ar->mSampleRateMilliHz == UNKNOWN_SAMPLERATE) {
549            *pPosMsec = 0;
550        } else {
551            *pPosMsec = ((int64_t)positionInFrames * 1000) /
552                    sles_to_android_sampleRate(ar->mSampleRateMilliHz);
553        }
554    }
555}
556