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
- Audio笔记之AudioTrack::play
- Audio笔记之AudioTrack
- Audio笔记之AudioTrack::write
- Android Audio Subsystem - AudioTrack - play
- audio system分析之audiotrack.java
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio第一部分 AudioTrack分析
- (转)Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- Android深入浅出之Audio 第一部分 AudioTrack分析
- 我的外包日记
- 引用和指针的却别
- 《罗辑思维》的逻辑缺陷
- Heroku第三方服务接入指南(二)
- 参数个数不确定
- Audio笔记之AudioTrack::play
- C# 动态修改web.config
- CSS学习中的十条速记口诀
- PAAS云服务平台
- merge into的用法
- 1.2 VoltDB Basics: Development Process
- 分布式搜索 Lucene全文检索基本原理
- 用.htaccess伪静态将域名绑定子目录
- Linux的watch命令 — 实时监测命令的运行结果