AudioRecorder_to_android.cpp revision 43f23007e7b6e42fc765e3e7b178492b1a3fc392
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_checkSourceSinkSupport(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    }
285
286    ar->mCallbackProtector->exitCb();
287}
288
289
290//-----------------------------------------------------------------------------
291SLresult android_audioRecorder_create(CAudioRecorder* ar) {
292    SL_LOGV("android_audioRecorder_create(%p) entering", ar);
293
294    const SLDataSource *pAudioSrc = &ar->mDataSource.u.mSource;
295    const SLDataSink *pAudioSnk = &ar->mDataSink.u.mSink;
296    SLresult result = SL_RESULT_SUCCESS;
297
298    const SLuint32 sourceLocatorType = *(SLuint32 *)pAudioSrc->pLocator;
299    const SLuint32 sinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator;
300
301    //  the following platform-independent fields have been initialized in CreateAudioRecorder()
302    //    ar->mNumChannels
303    //    ar->mSampleRateMilliHz
304
305    if ((SL_DATALOCATOR_IODEVICE == sourceLocatorType) &&
306            (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE == sinkLocatorType)) {
307        // microphone to simple buffer queue
308        ar->mAndroidObjType = AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE;
309        ar->mAudioRecord.clear();
310        ar->mCallbackProtector = new android::CallbackProtector();
311        ar->mRecordSource = AUDIO_SOURCE_DEFAULT;
312    } else {
313        result = SL_RESULT_CONTENT_UNSUPPORTED;
314    }
315
316    return result;
317}
318
319
320//-----------------------------------------------------------------------------
321SLresult android_audioRecorder_setConfig(CAudioRecorder* ar, const SLchar *configKey,
322        const void *pConfigValue, SLuint32 valueSize) {
323
324    SLresult result;
325
326    assert(NULL != ar && NULL != configKey && NULL != pConfigValue);
327    if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
328
329        // recording preset
330        if (KEY_RECORDING_PRESET_PARAMSIZE > valueSize) {
331            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
332            result = SL_RESULT_BUFFER_INSUFFICIENT;
333        } else {
334            result = audioRecorder_setPreset(ar, *(SLuint32*)pConfigValue);
335        }
336
337    } else {
338        SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
339        result = SL_RESULT_PARAMETER_INVALID;
340    }
341
342    return result;
343}
344
345
346//-----------------------------------------------------------------------------
347SLresult android_audioRecorder_getConfig(CAudioRecorder* ar, const SLchar *configKey,
348        SLuint32* pValueSize, void *pConfigValue) {
349
350    SLresult result;
351
352    assert(NULL != ar && NULL != configKey && NULL != pValueSize);
353    if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_RECORDING_PRESET) == 0) {
354
355        // recording preset
356        if (NULL == pConfigValue) {
357            result = SL_RESULT_SUCCESS;
358        } else if (KEY_RECORDING_PRESET_PARAMSIZE > *pValueSize) {
359            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
360            result = SL_RESULT_BUFFER_INSUFFICIENT;
361        } else {
362            result = audioRecorder_getPreset(ar, (SLuint32*)pConfigValue);
363        }
364        *pValueSize = KEY_RECORDING_PRESET_PARAMSIZE;
365
366    } else {
367        SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
368        result = SL_RESULT_PARAMETER_INVALID;
369    }
370
371    return result;
372}
373
374
375//-----------------------------------------------------------------------------
376SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
377    SL_LOGV("android_audioRecorder_realize(%p) entering", ar);
378
379    SLresult result = SL_RESULT_SUCCESS;
380
381    // initialize platform-independent CAudioRecorder fields
382    if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE != ar->mDataSink.mLocator.mLocatorType) {
383        SL_LOGE(ERROR_RECORDER_SINK_MUST_BE_ANDROIDSIMPLEBUFFERQUEUE);
384        return SL_RESULT_CONTENT_UNSUPPORTED;
385    }
386    //  the following platform-independent fields have been initialized in CreateAudioRecorder()
387    //    ar->mNumChannels
388    //    ar->mSampleRateMilliHz
389
390    SL_LOGV("new AudioRecord %u channels, %u mHz", ar->mNumChannels, ar->mSampleRateMilliHz);
391
392    // currently nothing analogous to canUseFastTrack() for recording
393    audio_input_flags_t policy = AUDIO_INPUT_FLAG_FAST;
394
395    // initialize platform-specific CAudioRecorder fields
396    ar->mAudioRecord = new android::AudioRecord(android::String16());
397    android::status_t status = ar->mAudioRecord->set(
398            ar->mRecordSource,     // source
399            sles_to_android_sampleRate(ar->mSampleRateMilliHz), // sample rate in Hertz
400            AUDIO_FORMAT_PCM_16_BIT,   //FIXME use format from buffer queue sink
401            sles_to_android_channelMaskIn(ar->mNumChannels, 0 /*no channel mask*/),
402                                   // channel config
403            0,                     //frameCount min
404            audioRecorder_callback,// callback_t
405            (void*)ar,             // user, callback data, here the AudioRecorder
406            0,                     // notificationFrames
407            false,                 // threadCanCallJava, note: this will prevent direct Java
408                                   //   callbacks, but we don't want them in the recording loop
409            0,                     // session ID
410            android::AudioRecord::TRANSFER_CALLBACK,
411                                   // transfer type
412            policy);               // audio_input_flags_t
413
414    if (android::NO_ERROR != status) {
415        SL_LOGE("android_audioRecorder_realize(%p) error creating AudioRecord object; status %d",
416                ar, status);
417        // FIXME should return a more specific result depending on status
418        result = SL_RESULT_CONTENT_UNSUPPORTED;
419        ar->mAudioRecord.clear();
420    }
421
422    return result;
423}
424
425
426//-----------------------------------------------------------------------------
427/**
428 * Called with a lock on AudioRecorder, and blocks until safe to destroy
429 */
430void android_audioRecorder_preDestroy(CAudioRecorder* ar) {
431    object_unlock_exclusive(&ar->mObject);
432    if (ar->mCallbackProtector != 0) {
433        ar->mCallbackProtector->requestCbExitAndWait();
434    }
435    object_lock_exclusive(&ar->mObject);
436}
437
438
439//-----------------------------------------------------------------------------
440void android_audioRecorder_destroy(CAudioRecorder* ar) {
441    SL_LOGV("android_audioRecorder_destroy(%p) entering", ar);
442
443    if (ar->mAudioRecord != 0) {
444        ar->mAudioRecord->stop();
445        ar->mAudioRecord.clear();
446    }
447    // explicit destructor
448    ar->mAudioRecord.~sp();
449    ar->mCallbackProtector.~sp();
450}
451
452
453//-----------------------------------------------------------------------------
454void android_audioRecorder_setRecordState(CAudioRecorder* ar, SLuint32 state) {
455    SL_LOGV("android_audioRecorder_setRecordState(%p, %u) entering", ar, state);
456
457    if (ar->mAudioRecord == 0) {
458        return;
459    }
460
461    switch (state) {
462     case SL_RECORDSTATE_STOPPED:
463         ar->mAudioRecord->stop();
464         break;
465     case SL_RECORDSTATE_PAUSED:
466         // Note that pausing is treated like stop as this implementation only records to a buffer
467         //  queue, so there is no notion of destination being "opened" or "closed" (See description
468         //  of SL_RECORDSTATE in specification)
469         ar->mAudioRecord->stop();
470         break;
471     case SL_RECORDSTATE_RECORDING:
472         ar->mAudioRecord->start();
473         break;
474     default:
475         break;
476     }
477
478}
479
480
481//-----------------------------------------------------------------------------
482void android_audioRecorder_useRecordEventMask(CAudioRecorder *ar) {
483    IRecord *pRecordItf = &ar->mRecord;
484    SLuint32 eventFlags = pRecordItf->mCallbackEventsMask;
485
486    if (ar->mAudioRecord == 0) {
487        return;
488    }
489
490    if ((eventFlags & SL_RECORDEVENT_HEADATMARKER) && (pRecordItf->mMarkerPosition != 0)) {
491        ar->mAudioRecord->setMarkerPosition((uint32_t)((((int64_t)pRecordItf->mMarkerPosition
492                * sles_to_android_sampleRate(ar->mSampleRateMilliHz)))/1000));
493    } else {
494        // clear marker
495        ar->mAudioRecord->setMarkerPosition(0);
496    }
497
498    if (eventFlags & SL_RECORDEVENT_HEADATNEWPOS) {
499        SL_LOGV("pos update period %d", pRecordItf->mPositionUpdatePeriod);
500         ar->mAudioRecord->setPositionUpdatePeriod(
501                (uint32_t)((((int64_t)pRecordItf->mPositionUpdatePeriod
502                * sles_to_android_sampleRate(ar->mSampleRateMilliHz)))/1000));
503    } else {
504        // clear periodic update
505        ar->mAudioRecord->setPositionUpdatePeriod(0);
506    }
507
508    if (eventFlags & SL_RECORDEVENT_HEADATLIMIT) {
509        // FIXME support SL_RECORDEVENT_HEADATLIMIT
510        SL_LOGD("[ FIXME: IRecord_SetCallbackEventsMask(SL_RECORDEVENT_HEADATLIMIT) on an "
511                    "SL_OBJECTID_AUDIORECORDER to be implemented ]");
512    }
513
514    if (eventFlags & SL_RECORDEVENT_HEADMOVING) {
515        // FIXME support SL_RECORDEVENT_HEADMOVING
516        SL_LOGD("[ FIXME: IRecord_SetCallbackEventsMask(SL_RECORDEVENT_HEADMOVING) on an "
517                "SL_OBJECTID_AUDIORECORDER to be implemented ]");
518    }
519
520    if (eventFlags & SL_RECORDEVENT_BUFFER_FULL) {
521        // nothing to do for SL_RECORDEVENT_BUFFER_FULL since this will not be encountered on
522        // recording to buffer queues
523    }
524
525    if (eventFlags & SL_RECORDEVENT_HEADSTALLED) {
526        // nothing to do for SL_RECORDEVENT_HEADSTALLED, callback event will be checked against mask
527        // when AudioRecord::EVENT_OVERRUN is encountered
528
529    }
530
531}
532
533
534//-----------------------------------------------------------------------------
535void android_audioRecorder_getPosition(CAudioRecorder *ar, SLmillisecond *pPosMsec) {
536    if ((NULL == ar) || (ar->mAudioRecord == 0)) {
537        *pPosMsec = 0;
538    } else {
539        uint32_t positionInFrames;
540        ar->mAudioRecord->getPosition(&positionInFrames);
541        if (ar->mSampleRateMilliHz == UNKNOWN_SAMPLERATE) {
542            *pPosMsec = 0;
543        } else {
544            *pPosMsec = ((int64_t)positionInFrames * 1000) /
545                    sles_to_android_sampleRate(ar->mSampleRateMilliHz);
546        }
547    }
548}
549