AudioRecord.cpp revision 99ffda877980468a9ae31e013cd10fb3645df1b0
1/*
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "AudioRecord"
20
21#include <stdint.h>
22#include <sys/types.h>
23
24#include <sched.h>
25#include <sys/resource.h>
26
27#include <private/media/AudioTrackShared.h>
28
29#include <media/AudioSystem.h>
30#include <media/AudioRecord.h>
31
32#include <utils/IServiceManager.h>
33#include <utils/Log.h>
34#include <utils/MemoryDealer.h>
35#include <utils/Parcel.h>
36#include <utils/IPCThreadState.h>
37#include <utils/Timers.h>
38#include <cutils/atomic.h>
39
40#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
41#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
42
43namespace android {
44
45// ---------------------------------------------------------------------------
46
47AudioRecord::AudioRecord()
48    : mStatus(NO_INIT)
49{
50}
51
52AudioRecord::AudioRecord(
53        int streamType,
54        uint32_t sampleRate,
55        int format,
56        int channelCount,
57        int frameCount,
58        uint32_t flags,
59        callback_t cbf,
60        void* user,
61        int notificationFrames)
62    : mStatus(NO_INIT)
63{
64    mStatus = set(streamType, sampleRate, format, channelCount,
65            frameCount, flags, cbf, user, notificationFrames);
66}
67
68AudioRecord::~AudioRecord()
69{
70    if (mStatus == NO_ERROR) {
71        // Make sure that callback function exits in the case where
72        // it is looping on buffer empty condition in obtainBuffer().
73        // Otherwise the callback thread will never exit.
74        stop();
75        if (mClientRecordThread != 0) {
76            mCblk->cv.signal();
77            mClientRecordThread->requestExitAndWait();
78            mClientRecordThread.clear();
79        }
80        mAudioRecord.clear();
81        IPCThreadState::self()->flushCommands();
82    }
83}
84
85status_t AudioRecord::set(
86        int streamType,
87        uint32_t sampleRate,
88        int format,
89        int channelCount,
90        int frameCount,
91        uint32_t flags,
92        callback_t cbf,
93        void* user,
94        int notificationFrames,
95        bool threadCanCallJava)
96{
97
98    LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
99    if (mAudioFlinger != 0) {
100        return INVALID_OPERATION;
101    }
102
103    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
104    if (audioFlinger == 0) {
105        return NO_INIT;
106    }
107
108    if (streamType == DEFAULT_INPUT) {
109        streamType = MIC_INPUT;
110    }
111
112    if (sampleRate == 0) {
113        sampleRate = DEFAULT_SAMPLE_RATE;
114    }
115    // these below should probably come from the audioFlinger too...
116    if (format == 0) {
117        format = AudioSystem::PCM_16_BIT;
118    }
119    if (channelCount == 0) {
120        channelCount = 1;
121    }
122
123    // validate parameters
124    if (format != AudioSystem::PCM_16_BIT) {
125        return BAD_VALUE;
126    }
127    if (channelCount != 1 && channelCount != 2) {
128        return BAD_VALUE;
129    }
130
131    // validate framecount
132    size_t inputBuffSizeInBytes = -1;
133    if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
134            != NO_ERROR) {
135        LOGE("AudioSystem could not query the input buffer size.");
136        return NO_INIT;
137    }
138    if (inputBuffSizeInBytes == 0) {
139        LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
140            sampleRate, channelCount, format);
141        return BAD_VALUE;
142    }
143    int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
144
145    // We use 2* size of input buffer for ping pong use of record buffer.
146    int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
147    LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
148
149    if (frameCount == 0) {
150        frameCount = minFrameCount;
151    } else if (frameCount < minFrameCount) {
152        return BAD_VALUE;
153    }
154
155    if (notificationFrames == 0) {
156        notificationFrames = frameCount/2;
157    }
158
159    // open record channel
160    status_t status;
161    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
162                                                       sampleRate, format,
163                                                       channelCount,
164                                                       frameCount,
165                                                       ((uint16_t)flags) << 16,
166                                                       &status);
167    if (record == 0) {
168        LOGE("AudioFlinger could not create record track, status: %d", status);
169        return status;
170    }
171    sp<IMemory> cblk = record->getCblk();
172    if (cblk == 0) {
173        return NO_INIT;
174    }
175    if (cbf != 0) {
176        mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
177        if (mClientRecordThread == 0) {
178            return NO_INIT;
179        }
180    }
181
182    mStatus = NO_ERROR;
183
184    mAudioFlinger = audioFlinger;
185    mAudioRecord = record;
186    mCblkMemory = cblk;
187    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
188    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
189    mCblk->out = 0;
190    mSampleRate = sampleRate;
191    mFormat = format;
192    // Update buffer size in case it has been limited by AudioFlinger during track creation
193    mFrameCount = mCblk->frameCount;
194    mChannelCount = channelCount;
195    mActive = 0;
196    mCbf = cbf;
197    mNotificationFrames = notificationFrames;
198    mRemainingFrames = notificationFrames;
199    mUserData = user;
200    // TODO: add audio hardware input latency here
201    mLatency = (1000*mFrameCount) / mSampleRate;
202    mMarkerPosition = 0;
203    mNewPosition = 0;
204    mUpdatePeriod = 0;
205
206    return NO_ERROR;
207}
208
209status_t AudioRecord::initCheck() const
210{
211    return mStatus;
212}
213
214// -------------------------------------------------------------------------
215
216uint32_t AudioRecord::latency() const
217{
218    return mLatency;
219}
220
221uint32_t AudioRecord::sampleRate() const
222{
223    return mSampleRate;
224}
225
226int AudioRecord::format() const
227{
228    return mFormat;
229}
230
231int AudioRecord::channelCount() const
232{
233    return mChannelCount;
234}
235
236uint32_t AudioRecord::frameCount() const
237{
238    return mFrameCount;
239}
240
241int AudioRecord::frameSize() const
242{
243    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
244}
245
246// -------------------------------------------------------------------------
247
248status_t AudioRecord::start()
249{
250    status_t ret = NO_ERROR;
251    sp<ClientRecordThread> t = mClientRecordThread;
252
253    LOGV("start");
254
255    if (t != 0) {
256        if (t->exitPending()) {
257            if (t->requestExitAndWait() == WOULD_BLOCK) {
258                LOGE("AudioRecord::start called from thread");
259                return WOULD_BLOCK;
260            }
261        }
262        t->mLock.lock();
263     }
264
265    if (android_atomic_or(1, &mActive) == 0) {
266        mNewPosition = mCblk->user + mUpdatePeriod;
267        mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
268        mCblk->waitTimeMs = 0;
269        if (t != 0) {
270           t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
271        } else {
272            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
273        }
274        ret = mAudioRecord->start();
275    }
276
277    if (t != 0) {
278        t->mLock.unlock();
279    }
280
281    return ret;
282}
283
284status_t AudioRecord::stop()
285{
286    sp<ClientRecordThread> t = mClientRecordThread;
287
288    LOGV("stop");
289
290    if (t != 0) {
291        t->mLock.lock();
292     }
293
294    if (android_atomic_and(~1, &mActive) == 1) {
295        mAudioRecord->stop();
296        if (t != 0) {
297            t->requestExit();
298        } else {
299            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
300        }
301    }
302
303    if (t != 0) {
304        t->mLock.unlock();
305    }
306
307    return NO_ERROR;
308}
309
310bool AudioRecord::stopped() const
311{
312    return !mActive;
313}
314
315status_t AudioRecord::setMarkerPosition(uint32_t marker)
316{
317    if (mCbf == 0) return INVALID_OPERATION;
318
319    mMarkerPosition = marker;
320
321    return NO_ERROR;
322}
323
324status_t AudioRecord::getMarkerPosition(uint32_t *marker)
325{
326    if (marker == 0) return BAD_VALUE;
327
328    *marker = mMarkerPosition;
329
330    return NO_ERROR;
331}
332
333status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
334{
335    if (mCbf == 0) return INVALID_OPERATION;
336
337    uint32_t curPosition;
338    getPosition(&curPosition);
339    mNewPosition = curPosition + updatePeriod;
340    mUpdatePeriod = updatePeriod;
341
342    return NO_ERROR;
343}
344
345status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
346{
347    if (updatePeriod == 0) return BAD_VALUE;
348
349    *updatePeriod = mUpdatePeriod;
350
351    return NO_ERROR;
352}
353
354status_t AudioRecord::getPosition(uint32_t *position)
355{
356    if (position == 0) return BAD_VALUE;
357
358    *position = mCblk->user;
359
360    return NO_ERROR;
361}
362
363
364// -------------------------------------------------------------------------
365
366status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
367{
368    int active;
369    int timeout = 0;
370    status_t result;
371    audio_track_cblk_t* cblk = mCblk;
372    uint32_t framesReq = audioBuffer->frameCount;
373
374    audioBuffer->frameCount  = 0;
375    audioBuffer->size        = 0;
376
377    uint32_t framesReady = cblk->framesReady();
378
379    if (framesReady == 0) {
380        Mutex::Autolock _l(cblk->lock);
381        goto start_loop_here;
382        while (framesReady == 0) {
383            active = mActive;
384            if (UNLIKELY(!active))
385                return NO_MORE_BUFFERS;
386            if (UNLIKELY(!waitCount))
387                return WOULD_BLOCK;
388            timeout = 0;
389            result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
390            if (__builtin_expect(result!=NO_ERROR, false)) {
391                cblk->waitTimeMs += WAIT_PERIOD_MS;
392                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
393                    LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
394                            "user=%08x, server=%08x", cblk->user, cblk->server);
395                    timeout = 1;
396                    cblk->waitTimeMs = 0;
397                }
398                if (--waitCount == 0) {
399                    return TIMED_OUT;
400                }
401            }
402            // read the server count again
403        start_loop_here:
404            framesReady = cblk->framesReady();
405        }
406    }
407
408    LOGW_IF(timeout,
409        "*** SERIOUS WARNING *** obtainBuffer() timed out "
410        "but didn't need to be locked. We recovered, but "
411        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
412
413    cblk->waitTimeMs = 0;
414
415    if (framesReq > framesReady) {
416        framesReq = framesReady;
417    }
418
419    uint32_t u = cblk->user;
420    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
421
422    if (u + framesReq > bufferEnd) {
423        framesReq = bufferEnd - u;
424    }
425
426    audioBuffer->flags       = 0;
427    audioBuffer->channelCount= mChannelCount;
428    audioBuffer->format      = mFormat;
429    audioBuffer->frameCount  = framesReq;
430    audioBuffer->size        = framesReq*mChannelCount*sizeof(int16_t);
431    audioBuffer->raw         = (int8_t*)cblk->buffer(u);
432    active = mActive;
433    return active ? status_t(NO_ERROR) : status_t(STOPPED);
434}
435
436void AudioRecord::releaseBuffer(Buffer* audioBuffer)
437{
438    audio_track_cblk_t* cblk = mCblk;
439    cblk->stepUser(audioBuffer->frameCount);
440}
441
442// -------------------------------------------------------------------------
443
444ssize_t AudioRecord::read(void* buffer, size_t userSize)
445{
446    ssize_t read = 0;
447    Buffer audioBuffer;
448    int8_t *dst = static_cast<int8_t*>(buffer);
449
450    if (ssize_t(userSize) < 0) {
451        // sanity-check. user is most-likely passing an error code.
452        LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
453                buffer, userSize, userSize);
454        return BAD_VALUE;
455    }
456
457    LOGV("read size: %d", userSize);
458
459    do {
460
461        audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
462
463        // Calling obtainBuffer() with a negative wait count causes
464        // an (almost) infinite wait time.
465        status_t err = obtainBuffer(&audioBuffer, -1);
466        if (err < 0) {
467            // out of buffers, return #bytes written
468            if (err == status_t(NO_MORE_BUFFERS))
469                break;
470            return ssize_t(err);
471        }
472
473        size_t bytesRead = audioBuffer.size;
474        memcpy(dst, audioBuffer.i8, bytesRead);
475
476        dst += bytesRead;
477        userSize -= bytesRead;
478        read += bytesRead;
479
480        releaseBuffer(&audioBuffer);
481    } while (userSize);
482
483    return read;
484}
485
486// -------------------------------------------------------------------------
487
488bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
489{
490    Buffer audioBuffer;
491    uint32_t frames = mRemainingFrames;
492    size_t readSize;
493
494    // Manage marker callback
495    if (mMarkerPosition > 0) {
496        if (mCblk->user >= mMarkerPosition) {
497            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
498            mMarkerPosition = 0;
499        }
500    }
501
502    // Manage new position callback
503    if (mUpdatePeriod > 0) {
504        while (mCblk->user >= mNewPosition) {
505            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
506            mNewPosition += mUpdatePeriod;
507        }
508    }
509
510    do {
511        audioBuffer.frameCount = frames;
512        // Calling obtainBuffer() with a wait count of 1
513        // limits wait time to WAIT_PERIOD_MS. This prevents from being
514        // stuck here not being able to handle timed events (position, markers).
515        status_t err = obtainBuffer(&audioBuffer, 1);
516        if (err < NO_ERROR) {
517            if (err != TIMED_OUT) {
518                LOGE("Error obtaining an audio buffer, giving up.");
519                return false;
520            }
521            break;
522        }
523        if (err == status_t(STOPPED)) return false;
524
525        size_t reqSize = audioBuffer.size;
526        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
527        readSize = audioBuffer.size;
528
529        // Sanity check on returned size
530        if (ssize_t(readSize) <= 0) break;
531        if (readSize > reqSize) readSize = reqSize;
532
533        audioBuffer.size = readSize;
534        audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
535        frames -= audioBuffer.frameCount;
536
537        releaseBuffer(&audioBuffer);
538
539    } while (frames);
540
541
542    // Manage overrun callback
543    if (mActive && (mCblk->framesAvailable_l() == 0)) {
544        LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
545        if (mCblk->flowControlFlag == 0) {
546            mCbf(EVENT_OVERRUN, mUserData, 0);
547            mCblk->flowControlFlag = 1;
548        }
549    }
550
551    if (frames == 0) {
552        mRemainingFrames = mNotificationFrames;
553    } else {
554        mRemainingFrames = frames;
555    }
556    return true;
557}
558
559// =========================================================================
560
561AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
562    : Thread(bCanCallJava), mReceiver(receiver)
563{
564}
565
566bool AudioRecord::ClientRecordThread::threadLoop()
567{
568    return mReceiver.processAudioBuffer(this);
569}
570
571// -------------------------------------------------------------------------
572
573}; // namespace android
574
575