Audio笔记之AudioTrack::play

来源:互联网 发布:金额分摊算法 编辑:程序博客网 时间:2024/05/05 23:31
    public void play()    throws IllegalStateException {        if (mState != STATE_INITIALIZED) {            throw new IllegalStateException("play() called on uninitialized AudioTrack.");        }        synchronized(mPlayStateLock) {            native_start();            mPlayState = PLAYSTATE_PLAYING;        }    }static voidandroid_media_AudioTrack_start(JNIEnv *env, jobject thiz){    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);    if (lpTrack == NULL) {        jniThrowException(env, "java/lang/IllegalStateException",            "Unable to retrieve AudioTrack pointer for start()");        return;    }    lpTrack->start();}status_t AudioTrack::start(){    AutoMutex lock(mLock);    if (mState == STATE_ACTIVE) {        return INVALID_OPERATION;    }    mInUnderrun = true;    State previousState = mState;    if (previousState == STATE_PAUSED_STOPPING) {        mState = STATE_STOPPING;    } else {        mState = STATE_ACTIVE;    }    if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {        // reset current position as seen by client to 0        mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());        // force refresh of remaining frames by processAudioBuffer() as last        // write before stop could be partial.        mRefreshRemaining = true;    }    mNewPosition = mProxy->getPosition() + mUpdatePeriod;    int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);    sp<AudioTrackThread> t = mAudioTrackThread;    if (t != 0) {        if (previousState == STATE_STOPPING) {            mProxy->interrupt();        } else {            t->resume();        }    } else {        mPreviousPriority = getpriority(PRIO_PROCESS, 0);        get_sched_policy(0, &mPreviousSchedulingGroup);        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);    }    status_t status = NO_ERROR;    if (!(flags & CBLK_INVALID)) {        status = mAudioTrack->start();        if (status == DEAD_OBJECT) {            flags |= CBLK_INVALID;        }    }    if (flags & CBLK_INVALID) {        status = restoreTrack_l("start");    }    if (status != NO_ERROR) {        ALOGE("start() status %d", status);        mState = previousState;        if (t != 0) {            if (previousState != STATE_STOPPING) {                t->pause();            }        } else {            setpriority(PRIO_PROCESS, 0, mPreviousPriority);            set_sched_policy(0, mPreviousSchedulingGroup);        }    }    return status;}status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event,                                                    int triggerSession){    status_t status = NO_ERROR;    ALOGV("start(%d), calling pid %d session %d",            mName, IPCThreadState::self()->getCallingPid(), mSessionId);    sp<ThreadBase> thread = mThread.promote();    if (thread != 0) {        if (isOffloaded()) {            Mutex::Autolock _laf(thread->mAudioFlinger->mLock);            Mutex::Autolock _lth(thread->mLock);            sp<EffectChain> ec = thread->getEffectChain_l(mSessionId);            if (thread->mAudioFlinger->isNonOffloadableGlobalEffectEnabled_l() ||                    (ec != 0 && ec->isNonOffloadableEnabled())) {                invalidate();                return PERMISSION_DENIED;            }        }        Mutex::Autolock _lth(thread->mLock);        track_state state = mState;        // here the track could be either new, or restarted        // in both cases "unstop" the track        if (state == PAUSED) {            if (mResumeToStopping) {                // happened we need to resume to STOPPING_1                mState = TrackBase::STOPPING_1;                ALOGV("PAUSED => STOPPING_1 (%d) on thread %p", mName, this);            } else {                mState = TrackBase::RESUMING;                ALOGV("PAUSED => RESUMING (%d) on thread %p", mName, this);            }        } else {            mState = TrackBase::ACTIVE;            ALOGV("? => ACTIVE (%d) on thread %p", mName, this);        }         //将本track加入到active track列队,同时通过mWaitWorkCV唤醒playbackThread中        //的线程,具体实现为PlaybackThread::threadLoop函数中的mWaitWorkCV.wait(mLock)        //当线程运行到此处时会阻塞,等待track的消息,收到消息后才继续运行        //重点:此处实现了生产者和消费者的通信        PlaybackThread *playbackThread = (PlaybackThread *)thread.get();        status = playbackThread->addTrack_l(this);                if (status == INVALID_OPERATION || status == PERMISSION_DENIED) {            triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);            //  restore previous state if start was rejected by policy manager            if (status == PERMISSION_DENIED) {                mState = state;            }        }        // track was already in the active list, not a problem        if (status == ALREADY_EXISTS) {            status = NO_ERROR;        } else {            // Acknowledge any pending flush(), so that subsequent new data isn't discarded.            // It is usually unsafe to access the server proxy from a binder thread.            // But in this case we know the mixer thread (whether normal mixer or fast mixer)            // isn't looking at this track yet:  we still hold the normal mixer thread lock,            // and for fast tracks the track is not yet in the fast mixer thread's active set.            ServerProxy::Buffer buffer;            buffer.mFrameCount = 1;            (void) mAudioTrackServerProxy->obtainBuffer(&buffer, true /*ackFlush*/);        }    } else {        status = BAD_VALUE;    }    return status;}//虽然之前已经调用线程创建了track,但是只是进行了初始化,并将其添加到线程的mTracks中,//直到调用track的start函数才将其添加到线程的mActiveTracks中status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track){    status_t status = ALREADY_EXISTS;    // set retry count for buffer fill    track->mRetryCount = kMaxTrackStartupRetries;    if (mActiveTracks.indexOf(track) < 0) {        // the track is newly added, make sure it fills up all its        // buffers before playing. This is to ensure the client will        // effectively get the latency it requested.        // 确保缓冲区已经填满        if (!track->isOutputTrack()) {            TrackBase::track_state state = track->mState;            mLock.unlock();            status = AudioSystem::startOutput(mId, track->streamType(), track->sessionId());            mLock.lock();            // abort track was stopped/paused while we released the lock            // 确认track的状态没有改变,否则释放与该track关联的输入资源            if (state != track->mState) {                if (status == NO_ERROR) {                    mLock.unlock();                    AudioSystem::stopOutput(mId, track->streamType(), track->sessionId());                    mLock.lock();                }                return INVALID_OPERATION;            }            // abort if start is rejected by audio policy manager            // 确认已经成功打开输出            if (status != NO_ERROR) {                return PERMISSION_DENIED;            }#ifdef ADD_BATTERY_DATA            // to track the speaker usage            addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStart);#endif        }        //设置缓冲区填充情况,如果等于0,则表示正在缓冲,STREAM模式的初始值就是0        //此处应该就是设置STREAM模式的初始状态为正在缓冲,对应STATCI来说,        //由于是一次性写入,就不存在是否正在缓冲了        track->mFillingUpStatus = track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;        track->mResetDone = false;        track->mPresentationCompleteFrames = 0;        mActiveTracks.add(track);        mWakeLockUids.add(track->uid());        mActiveTracksGeneration++;        mLatestActiveTrack = track;        sp<EffectChain> chain = getEffectChain_l(track->sessionId());        if (chain != 0) {            ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),                    track->sessionId());            chain->incActiveTrackCnt();        }        status = NO_ERROR;    }    ALOGV("signal playback thread");    broadcast_l();    return status;}void AudioFlinger::PlaybackThread::broadcast_l(){    // Thread could be blocked waiting for async    // so signal it to handle state changes immediately    // If threadLoop is currently unlocked a signal of mWaitWorkCV will    // be lost so we also flag to prevent it blocking on mWaitWorkCV    mSignalPending = true;    //触发广播事件,通知有active track加入,启动线程的loop函数    //具体过程,需要在threadloop函数中分析    mWaitWorkCV.broadcast();}status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,                                             AudioSystem::stream_type stream,                                             int session){    ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);    ssize_t index = mOutputs.indexOfKey(output);    if (index < 0) {        ALOGW("startOutput() unknow output %d", output);        return BAD_VALUE;    }    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);    // increment usage count for this stream on the requested output:    // NOTE that the usage count is the same for duplicated output and hardware output which is    // necessary for a correct control of hardware output routing by startOutput() and stopOutput()    outputDesc->changeRefCount(stream, 1);    if (outputDesc->mRefCount[stream] == 1) {        audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);        routing_strategy strategy = getStrategy(stream);        bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||                            (strategy == STRATEGY_SONIFICATION_RESPECTFUL);        uint32_t waitMs = 0;        bool force = false;        for (size_t i = 0; i < mOutputs.size(); i++) {            AudioOutputDescriptor *desc = mOutputs.valueAt(i);            if (desc != outputDesc) {                // force a device change if any other output is managed by the same hw                // module and has a current device selection that differs from selected device.                // In this case, the audio HAL must receive the new device selection so that it can                // change the device currently selected by the other active output.                if (outputDesc->sharesHwModuleWith(desc) &&                    desc->device() != newDevice) {                    force = true;                }                // wait for audio on other active outputs to be presented when starting                // a notification so that audio focus effect can propagate.                uint32_t latency = desc->latency();                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {                    waitMs = latency;                }            }        }        uint32_t muteWaitMs = setOutputDevice(output, newDevice, force);        // handle special case for sonification while in call        if (isInCall()) {            handleIncallSonification(stream, true, false);        }        // apply volume rules for current stream and device if necessary        checkAndSetVolume(stream,                          mStreams[stream].getVolumeIndex(newDevice),                          output,                          newDevice);        // update the outputs if starting an output with a stream that can affect notification        // routing        handleNotificationRoutingForStream(stream);        if (waitMs > muteWaitMs) {            usleep((waitMs - muteWaitMs) * 2 * 1000);        }    }    return NO_ERROR;}status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,                                            AudioSystem::stream_type stream,                                            int session){    ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);    ssize_t index = mOutputs.indexOfKey(output);    if (index < 0) {        ALOGW("stopOutput() unknow output %d", output);        return BAD_VALUE;    }    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);    // handle special case for sonification while in call    if (isInCall()) {        handleIncallSonification(stream, false, false);    }    if (outputDesc->mRefCount[stream] > 0) {        // decrement usage count of this stream on the output        outputDesc->changeRefCount(stream, -1);        // store time at which the stream was stopped - see isStreamActive()        if (outputDesc->mRefCount[stream] == 0) {            outputDesc->mStopTime[stream] = systemTime();            audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);            // delay the device switch by twice the latency because stopOutput() is executed when            // the track stop() command is received and at that time the audio track buffer can            // still contain data that needs to be drained. The latency only covers the audio HAL            // and kernel buffers. Also the latency does not always include additional delay in the            // audio path (audio DSP, CODEC ...)            setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);            // force restoring the device selection on other active outputs if it differs from the            // one being selected for this output            for (size_t i = 0; i < mOutputs.size(); i++) {                audio_io_handle_t curOutput = mOutputs.keyAt(i);                AudioOutputDescriptor *desc = mOutputs.valueAt(i);                if (curOutput != output &&                        desc->isActive() &&                        outputDesc->sharesHwModuleWith(desc) &&                        (newDevice != desc->device())) {                    setOutputDevice(curOutput,                                    getNewDevice(curOutput, false /*fromCache*/),                                    true,                                    outputDesc->mLatency*2);                }            }            // update the outputs if stopping one with a stream that can affect notification routing            handleNotificationRoutingForStream(stream);        }        return NO_ERROR;    } else {        ALOGW("stopOutput() refcount is already 0 for output %d", output);        return INVALID_OPERATION;    }}


0 0
原创粉丝点击