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