AudioRecord.cpp revision 7a2146d5807030b2629f347736be5301b61e8811
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    // TODO: Get input frame count from hardware.
132    int minFrameCount = 1024*2;
133
134    if (frameCount == 0) {
135        frameCount = minFrameCount;
136    } else if (frameCount < minFrameCount) {
137        return BAD_VALUE;
138    }
139
140    if (notificationFrames == 0) {
141        notificationFrames = frameCount/2;
142    }
143
144    // open record channel
145    status_t status;
146    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
147            sampleRate, format, channelCount, frameCount, flags, &status);
148    if (record == 0) {
149        LOGE("AudioFlinger could not create record track, status: %d", status);
150        return status;
151    }
152    sp<IMemory> cblk = record->getCblk();
153    if (cblk == 0) {
154        return NO_INIT;
155    }
156    if (cbf != 0) {
157        mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
158        if (mClientRecordThread == 0) {
159            return NO_INIT;
160        }
161    }
162
163    mStatus = NO_ERROR;
164
165    mAudioFlinger = audioFlinger;
166    mAudioRecord = record;
167    mCblkMemory = cblk;
168    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
169    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
170    mCblk->out = 0;
171    mSampleRate = sampleRate;
172    mFormat = format;
173    // Update buffer size in case it has been limited by AudioFlinger during track creation
174    mFrameCount = mCblk->frameCount;
175    mChannelCount = channelCount;
176    mActive = 0;
177    mCbf = cbf;
178    mNotificationFrames = notificationFrames;
179    mRemainingFrames = notificationFrames;
180    mUserData = user;
181    // TODO: add audio hardware input latency here
182    mLatency = (1000*mFrameCount) / mSampleRate;
183    mMarkerPosition = 0;
184    mNewPosition = 0;
185    mUpdatePeriod = 0;
186
187    return NO_ERROR;
188}
189
190status_t AudioRecord::initCheck() const
191{
192    return mStatus;
193}
194
195// -------------------------------------------------------------------------
196
197uint32_t AudioRecord::latency() const
198{
199    return mLatency;
200}
201
202uint32_t AudioRecord::sampleRate() const
203{
204    return mSampleRate;
205}
206
207int AudioRecord::format() const
208{
209    return mFormat;
210}
211
212int AudioRecord::channelCount() const
213{
214    return mChannelCount;
215}
216
217uint32_t AudioRecord::frameCount() const
218{
219    return mFrameCount;
220}
221
222int AudioRecord::frameSize() const
223{
224    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
225}
226
227// -------------------------------------------------------------------------
228
229status_t AudioRecord::start()
230{
231    status_t ret = NO_ERROR;
232    sp<ClientRecordThread> t = mClientRecordThread;
233
234    LOGV("start");
235
236    if (t != 0) {
237        if (t->exitPending()) {
238            if (t->requestExitAndWait() == WOULD_BLOCK) {
239                LOGE("AudioRecord::start called from thread");
240                return WOULD_BLOCK;
241            }
242        }
243        t->mLock.lock();
244     }
245
246    if (android_atomic_or(1, &mActive) == 0) {
247        mNewPosition = mCblk->user + mUpdatePeriod;
248        mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
249        mCblk->waitTimeMs = 0;
250        if (t != 0) {
251           t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
252        } else {
253            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
254        }
255        ret = mAudioRecord->start();
256    }
257
258    if (t != 0) {
259        t->mLock.unlock();
260    }
261
262    return ret;
263}
264
265status_t AudioRecord::stop()
266{
267    sp<ClientRecordThread> t = mClientRecordThread;
268
269    LOGV("stop");
270
271    if (t != 0) {
272        t->mLock.lock();
273     }
274
275    if (android_atomic_and(~1, &mActive) == 1) {
276        mAudioRecord->stop();
277        if (t != 0) {
278            t->requestExit();
279        } else {
280            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
281        }
282    }
283
284    if (t != 0) {
285        t->mLock.unlock();
286    }
287
288    return NO_ERROR;
289}
290
291bool AudioRecord::stopped() const
292{
293    return !mActive;
294}
295
296status_t AudioRecord::setMarkerPosition(uint32_t marker)
297{
298    if (mCbf == 0) return INVALID_OPERATION;
299
300    mMarkerPosition = marker;
301
302    return NO_ERROR;
303}
304
305status_t AudioRecord::getMarkerPosition(uint32_t *marker)
306{
307    if (marker == 0) return BAD_VALUE;
308
309    *marker = mMarkerPosition;
310
311    return NO_ERROR;
312}
313
314status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
315{
316    if (mCbf == 0) return INVALID_OPERATION;
317
318    uint32_t curPosition;
319    getPosition(&curPosition);
320    mNewPosition = curPosition + updatePeriod;
321    mUpdatePeriod = updatePeriod;
322
323    return NO_ERROR;
324}
325
326status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
327{
328    if (updatePeriod == 0) return BAD_VALUE;
329
330    *updatePeriod = mUpdatePeriod;
331
332    return NO_ERROR;
333}
334
335status_t AudioRecord::getPosition(uint32_t *position)
336{
337    if (position == 0) return BAD_VALUE;
338
339    *position = mCblk->user;
340
341    return NO_ERROR;
342}
343
344
345// -------------------------------------------------------------------------
346
347status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
348{
349    int active;
350    int timeout = 0;
351    status_t result;
352    audio_track_cblk_t* cblk = mCblk;
353    uint32_t framesReq = audioBuffer->frameCount;
354
355    audioBuffer->frameCount  = 0;
356    audioBuffer->size        = 0;
357
358    uint32_t framesReady = cblk->framesReady();
359
360    if (framesReady == 0) {
361        Mutex::Autolock _l(cblk->lock);
362        goto start_loop_here;
363        while (framesReady == 0) {
364            active = mActive;
365            if (UNLIKELY(!active))
366                return NO_MORE_BUFFERS;
367            if (UNLIKELY(!waitCount))
368                return WOULD_BLOCK;
369            timeout = 0;
370            result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
371            if (__builtin_expect(result!=NO_ERROR, false)) {
372                cblk->waitTimeMs += WAIT_PERIOD_MS;
373                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
374                    LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
375                            "user=%08x, server=%08x", cblk->user, cblk->server);
376                    timeout = 1;
377                    cblk->waitTimeMs = 0;
378                }
379                if (--waitCount == 0) {
380                    return TIMED_OUT;
381                }
382            }
383            // read the server count again
384        start_loop_here:
385            framesReady = cblk->framesReady();
386        }
387    }
388
389    LOGW_IF(timeout,
390        "*** SERIOUS WARNING *** obtainBuffer() timed out "
391        "but didn't need to be locked. We recovered, but "
392        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
393
394    cblk->waitTimeMs = 0;
395
396    if (framesReq > framesReady) {
397        framesReq = framesReady;
398    }
399
400    uint32_t u = cblk->user;
401    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
402
403    if (u + framesReady > bufferEnd) {
404        framesReq = bufferEnd - u;
405    }
406
407    audioBuffer->flags       = 0;
408    audioBuffer->channelCount= mChannelCount;
409    audioBuffer->format      = mFormat;
410    audioBuffer->frameCount  = framesReq;
411    audioBuffer->size        = framesReq*mChannelCount*sizeof(int16_t);
412    audioBuffer->raw         = (int8_t*)cblk->buffer(u);
413    active = mActive;
414    return active ? status_t(NO_ERROR) : status_t(STOPPED);
415}
416
417void AudioRecord::releaseBuffer(Buffer* audioBuffer)
418{
419    audio_track_cblk_t* cblk = mCblk;
420    cblk->stepUser(audioBuffer->frameCount);
421}
422
423// -------------------------------------------------------------------------
424
425ssize_t AudioRecord::read(void* buffer, size_t userSize)
426{
427    ssize_t read = 0;
428    Buffer audioBuffer;
429    int8_t *dst = static_cast<int8_t*>(buffer);
430
431    if (ssize_t(userSize) < 0) {
432        // sanity-check. user is most-likely passing an error code.
433        LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
434                buffer, userSize, userSize);
435        return BAD_VALUE;
436    }
437
438    LOGV("read size: %d", userSize);
439
440    do {
441
442        audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
443
444        // Calling obtainBuffer() with a negative wait count causes
445        // an (almost) infinite wait time.
446        status_t err = obtainBuffer(&audioBuffer, -1);
447        if (err < 0) {
448            // out of buffers, return #bytes written
449            if (err == status_t(NO_MORE_BUFFERS))
450                break;
451            return ssize_t(err);
452        }
453
454        size_t bytesRead = audioBuffer.size;
455        memcpy(dst, audioBuffer.i8, bytesRead);
456
457        dst += bytesRead;
458        userSize -= bytesRead;
459        read += bytesRead;
460
461        releaseBuffer(&audioBuffer);
462    } while (userSize);
463
464    return read;
465}
466
467// -------------------------------------------------------------------------
468
469bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
470{
471    Buffer audioBuffer;
472    uint32_t frames = mRemainingFrames;
473    size_t readSize;
474
475    // Manage marker callback
476    if (mMarkerPosition > 0) {
477        if (mCblk->user >= mMarkerPosition) {
478            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
479            mMarkerPosition = 0;
480        }
481    }
482
483    // Manage new position callback
484    if (mUpdatePeriod > 0) {
485        while (mCblk->user >= mNewPosition) {
486            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
487            mNewPosition += mUpdatePeriod;
488        }
489    }
490
491    do {
492        audioBuffer.frameCount = frames;
493        // Calling obtainBuffer() with a wait count of 1
494        // limits wait time to WAIT_PERIOD_MS. This prevents from being
495        // stuck here not being able to handle timed events (position, markers).
496        status_t err = obtainBuffer(&audioBuffer, 1);
497        if (err < NO_ERROR) {
498            if (err != TIMED_OUT) {
499                LOGE("Error obtaining an audio buffer, giving up.");
500                return false;
501            }
502            break;
503        }
504        if (err == status_t(STOPPED)) return false;
505
506        size_t reqSize = audioBuffer.size;
507        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
508        readSize = audioBuffer.size;
509
510        // Sanity check on returned size
511        if (ssize_t(readSize) <= 0) break;
512        if (readSize > reqSize) readSize = reqSize;
513
514        audioBuffer.size = readSize;
515        audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
516        frames -= audioBuffer.frameCount;
517
518        releaseBuffer(&audioBuffer);
519
520    } while (frames);
521
522
523    // Manage overrun callback
524    if (mActive && (mCblk->framesAvailable_l() == 0)) {
525        LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
526        if (mCblk->flowControlFlag == 0) {
527            mCbf(EVENT_OVERRUN, mUserData, 0);
528            mCblk->flowControlFlag = 1;
529        }
530    }
531
532    if (frames == 0) {
533        mRemainingFrames = mNotificationFrames;
534    } else {
535        mRemainingFrames = frames;
536    }
537    return true;
538}
539
540// =========================================================================
541
542AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
543    : Thread(bCanCallJava), mReceiver(receiver)
544{
545}
546
547bool AudioRecord::ClientRecordThread::threadLoop()
548{
549    return mReceiver.processAudioBuffer(this);
550}
551
552// -------------------------------------------------------------------------
553
554}; // namespace android
555
556