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