201711211840->unity调用安卓方法

本文详细介绍如何使用Eclipse创建Android工程并将其集成到Unity项目中,包括配置步骤、常见错误排查等,适合Unity开发者扩展功能使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工具:unity5.5.3p2 eclipse

思路:

1.利用eclipse新建安卓工程,写入自己相应的方法

2.将src文件夹导出jar包

3.设置好AndroidManifest.xml里的配置

4.将res,lib,AndroidManifest以及导出的jar包放到unity工程asset/plugins/android下边

5.检查配置表,res下所有配置表

6.在untiy中写入自己的调用方法

详细步骤:


新建安卓工程


填好包名,一切默认


新建好工程之后就直接导入unity中的classes.jar,这个文件会根据版本不同文件未知也不同


写好需要调用的类,import需要调用的包,然后继承于unityplayeractivity


写好配置表


导出src文件夹


将导出的jir包与lib与res以及配置表拉入unity中





将三个values里边的文件家的style文件夹注销所有皮肤配置


删掉menu里边的item配置


写入自己的调用方法,导出apk,然后真机调试


注意点:

re-package error是指资源打包失败,报这个错就检查所有资源配置以及资源路径就可以勒


/ prepareTracks_l() must be called with ThreadBase::mLock held AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l( Vector< sp<Track> > *tracksToRemove) { mixer_state mixerStatus = MIXER_IDLE; // find out which tracks need to be processed size_t count = mActiveTracks.size(); size_t mixedTracks = 0; size_t tracksWithEffect = 0; // counts only _active_ fast tracks size_t fastTracks = 0; uint32_t resetMask = 0; // bit mask of fast tracks that need to be reset float masterVolume = mMasterVolume; bool masterMute = mMasterMute; if (masterMute) { masterVolume = 0; } // Delegate master volume control to effect in output mix effect chain if needed sp<EffectChain> chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); if (chain != 0) { uint32_t v = (uint32_t)(masterVolume * (1 << 24)); chain->setVolume_l(&v, &v); masterVolume = (float)((v + (1 << 23)) >> 24); chain.clear(); } // prepare a new state to push FastMixerStateQueue *sq = NULL; FastMixerState *state = NULL; bool didModify = false; FastMixerStateQueue::block_t block = FastMixerStateQueue::BLOCK_UNTIL_PUSHED; if (mFastMixer != 0) { sq = mFastMixer->sq(); state = sq->begin(); } mMixerBufferValid = false; // mMixerBuffer has no valid data until appropriate tracks found. mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found. for (size_t i=0 ; i<count ; i++) { const sp<Track> t = mActiveTracks[i].promote(); if (t == 0) { continue; } // this const just means the local variable doesn't change Track* const track = t.get(); // process fast tracks if (track->isFastTrack()) { // It's theoretically possible (though unlikely) for a fast track to be created // and then removed within the same normal mix cycle. This is not a problem, as // the track never becomes active so it's fast mixer slot is never touched. // The converse, of removing an (active) track and then creating a new track // at the identical fast mixer slot within the same normal mix cycle, // is impossible because the slot isn't marked available until the end of each cycle. int j = track->mFastIndex; ALOG_ASSERT(0 < j && j < (int)FastMixerState::sMaxFastTracks); ALOG_ASSERT(!(mFastTrackAvailMask & (1 << j))); FastTrack *fastTrack = &state->mFastTracks[j]; // Determine whether the track is currently in underrun condition, // and whether it had a recent underrun. FastTrackDump *ftDump = &mFastMixerDumpState.mTracks[j]; FastTrackUnderruns underruns = ftDump->mUnderruns; uint32_t recentFull = (underruns.mBitFields.mFull - track->mObservedUnderruns.mBitFields.mFull) & UNDERRUN_MASK; uint32_t recentPartial = (underruns.mBitFields.mPartial - track->mObservedUnderruns.mBitFields.mPartial) & UNDERRUN_MASK; uint32_t recentEmpty = (underruns.mBitFields.mEmpty - track->mObservedUnderruns.mBitFields.mEmpty) & UNDERRUN_MASK; uint32_t recentUnderruns = recentPartial + recentEmpty; track->mObservedUnderruns = underruns; // don't count underruns that occur while stopping or pausing // or stopped which can occur when flush() is called while active if (!(track->isStopping() || track->isPausing() || track->isStopped()) && recentUnderruns > 0) { // FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount); } else { track->mAudioTrackServerProxy->tallyUnderrunFrames(0); } // This is similar to the state machine for normal tracks, // with a few modifications for fast tracks. bool isActive = true; switch (track->mState) { case TrackBase::STOPPING_1: // track stays active in STOPPING_1 state until first underrun if (recentUnderruns > 0 || track->isTerminated()) { track->mState = TrackBase::STOPPING_2; } break; case TrackBase::PAUSING: // ramp down is not yet implemented track->setPaused(); break; case TrackBase::RESUMING: // ramp up is not yet implemented track->mState = TrackBase::ACTIVE; break; case TrackBase::ACTIVE: if (recentFull > 0 || recentPartial > 0) { // track has provided at least some frames recently: reset retry count track->mRetryCount = kMaxTrackRetries; } if (recentUnderruns == 0) { // no recent underruns: stay active break; } // there has recently been an underrun of some kind if (track->sharedBuffer() == 0) { // were any of the recent underruns "empty" (no frames available)? if (recentEmpty == 0) { // no, then ignore the partial underruns as they are allowed indefinitely break; } // there has recently been an "empty" underrun: decrement the retry counter if (--(track->mRetryCount) > 0) { break; } // indicate to client process that the track was disabled because of underrun; // it will then automatically call start() when data is available track->disable(); // remove from active list, but state remains ACTIVE [confusing but true] isActive = false; break; } // fall through case TrackBase::STOPPING_2: case TrackBase::PAUSED: case TrackBase::STOPPED: case TrackBase::FLUSHED: // flush() while active // Check for presentation complete if track is inactive // We have consumed all the buffers of this track. // This would be incomplete if we auto-paused on underrun { size_t audioHALFrames = (mOutput->stream->get_latency(mOutput->stream)*mSampleRate) / 1000; int64_t framesWritten = mBytesWritten / mFrameSize; if (!(mStandby || track->presentationComplete(framesWritten, audioHALFrames))) { // track stays in active list until presentation is complete break; } } if (track->isStopping_2()) { track->mState = TrackBase::STOPPED; } if (track->isStopped()) { // Can't reset directly, as fast mixer is still polling this track // track->reset(); // So instead mark this track as needing to be reset after push with ack resetMask |= 1 << i; } isActive = false; break; case TrackBase::IDLE: default: LOG_ALWAYS_FATAL("unexpected track state %d", track->mState); } if (isActive) { // was it previously inactive? if (!(state->mTrackMask & (1 << j))) { ExtendedAudioBufferProvider *eabp = track; VolumeProvider *vp = track; fastTrack->mBufferProvider = eabp; fastTrack->mVolumeProvider = vp; fastTrack->mChannelMask = track->mChannelMask; fastTrack->mFormat = track->mFormat; fastTrack->mGeneration++; state->mTrackMask |= 1 << j; didModify = true; // no acknowledgement required for newly active tracks } // cache the combined master volume and stream type volume for fast mixer; this // lacks any synchronization or barrier so VolumeProvider may read a stale value track->mCachedVolume = masterVolume * mStreamTypes[track->streamType()].volume; ++fastTracks; } else { // was it previously active? if (state->mTrackMask & (1 << j)) { fastTrack->mBufferProvider = NULL; fastTrack->mGeneration++; state->mTrackMask &= ~(1 << j); didModify = true; // If any fast tracks were removed, we must wait for acknowledgement // because we're about to decrement the last sp<> on those tracks. block = FastMixerStateQueue::BLOCK_UNTIL_ACKED; } else { LOG_ALWAYS_FATAL("fast track %d should have been active; " "mState=%d, mTrackMask=%#x, recentUnderruns=%u, isShared=%d", j, track->mState, state->mTrackMask, recentUnderruns, track->sharedBuffer() != 0); } tracksToRemove->add(track); // Avoids a misleading display in dumpsys track->mObservedUnderruns.mBitFields.mMostRecent = UNDERRUN_FULL; } continue; } { // local variable scope to avoid goto warning audio_track_cblk_t* cblk = track->cblk(); // The first time a track is added we wait // for all its buffers to be filled before processing it int name = track->name(); // make sure that we have enough frames to mix one full buffer. // enforce this condition only once to enable draining the buffer in case the client // app does not call stop() and relies on underrun to stop: // hence the test on (mMixerStatus == MIXER_TRACKS_READY) meaning the track was mixed // during last round size_t desiredFrames; const uint32_t sampleRate = track->mAudioTrackServerProxy->getSampleRate(); AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate(); desiredFrames = sourceFramesNeededWithTimestretch( sampleRate, mNormalFrameCount, mSampleRate, playbackRate.mSpeed); // TODO: ONLY USED FOR LEGACY RESAMPLERS, remove when they are removed. // add frames already consumed but not yet released by the resampler // because mAudioTrackServerProxy->framesReady() will include these frames desiredFrames += mAudioMixer->getUnreleasedFrames(track->name()); uint32_t minFrames = 1; if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing() && (mMixerStatusIgnoringFastTracks == MIXER_TRACKS_READY)) { minFrames = desiredFrames; } size_t framesReady = track->framesReady(); if (ATRACE_ENABLED()) { // I wish we had formatted trace names char traceName[16]; strcpy(traceName, "nRdy"); int name = track->name(); if (AudioMixer::TRACK0 <= name && name < (int) (AudioMixer::TRACK0 + AudioMixer::MAX_NUM_TRACKS)) { name -= AudioMixer::TRACK0; traceName[4] = (name / 10) + '0'; traceName[5] = (name % 10) + '0'; } else { traceName[4] = '?'; traceName[5] = '?'; } traceName[6] = '\0'; ATRACE_INT(traceName, framesReady); } if ((framesReady >= minFrames) && track->isReady() && !track->isPaused() && !track->isTerminated()) { ALOGVV("track %d s=%08x [OK] on thread %p", name, cblk->mServer, this); mixedTracks++; // track->mainBuffer() != mSinkBuffer or mMixerBuffer means // there is an effect chain connected to the track chain.clear(); if (track->mainBuffer() != mSinkBuffer && track->mainBuffer() != mMixerBuffer) { if (mEffectBufferEnabled) { mEffectBufferValid = true; // Later can set directly. } chain = getEffectChain_l(track->sessionId()); // Delegate volume control to effect in track effect chain if needed if (chain != 0) { tracksWithEffect++; } else { ALOGW("prepareTracks_l(): track %d attached to effect but no chain found on " "session %d", name, track->sessionId()); } } int param = AudioMixer::VOLUME; if (track->mFillingUpStatus == Track::FS_FILLED) { // no ramp for the first volume setting track->mFillingUpStatus = Track::FS_ACTIVE; if (track->mState == TrackBase::RESUMING) { track->mState = TrackBase::ACTIVE; param = AudioMixer::RAMP_VOLUME; } mAudioMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL); // FIXME should not make a decision based on mServer } else if (cblk->mServer != 0) { // If the track is stopped before the first frame was mixed, // do not apply ramp param = AudioMixer::RAMP_VOLUME; } // compute volume for this track uint32_t vl, vr; // in U8.24 integer format float vlf, vrf, vaf; // in [0.0, 1.0] float format if (track->isPausing() || mStreamTypes[track->streamType()].mute) { vl = vr = 0; vlf = vrf = vaf = 0.; if (track->isPausing()) { track->setPaused(); } } else { // read original volumes with volume control float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; //add for boot video:sync audio for boot char value[PROPERTY_VALUE_MAX] = ""; property_get("persist.sys.bootvideo.enable", value, "false"); if(!strcmp(value,"true")){ property_get("sys.bootvideo.closed", value, "1"); if (atoi(value) == 0){ ALOGV("bootvideo running now,audioflinger no need to control volume"); v = 1.0; } } AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy; gain_minifloat_packed_t vlr = proxy->getVolumeLR(); vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); // track volumes come from shared memory, so can't be trusted and must be clamped if (vlf > GAIN_FLOAT_UNITY) { ALOGV("Track left volume out of range: %.3g", vlf); vlf = GAIN_FLOAT_UNITY; } if (vrf > GAIN_FLOAT_UNITY) { ALOGV("Track right volume out of range: %.3g", vrf); vrf = GAIN_FLOAT_UNITY; } // now apply the master volume and stream type volume vlf *= v; vrf *= v; // assuming master volume and stream type volume each go up to 1.0, // then derive vl and vr as U8.24 versions for the effect chain const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT; vl = (uint32_t) (scaleto8_24 * vlf); vr = (uint32_t) (scaleto8_24 * vrf); // vl and vr are now in U8.24 format uint16_t sendLevel = proxy->getSendLevel_U4_12(); // send level comes from shared memory and so may be corrupt if (sendLevel > MAX_GAIN_INT) { ALOGV("Track send level out of range: %04X", sendLevel); sendLevel = MAX_GAIN_INT; } // vaf is represented as [0.0, 1.0] float by rescaling sendLevel vaf = v * sendLevel * (1. / MAX_GAIN_INT); } // Delegate volume control to effect in track effect chain if needed if (chain != 0 && chain->setVolume_l(&vl, &vr)) { // Do not ramp volume if volume is controlled by effect param = AudioMixer::VOLUME; // Update remaining floating point volume levels vlf = (float)vl / (1 << 24); vrf = (float)vr / (1 << 24); track->mHasVolumeController = true; } else { // force no volume ramp when volume controller was just disabled or removed // from effect chain to avoid volume spike if (track->mHasVolumeController) { param = AudioMixer::VOLUME; } track->mHasVolumeController = false; } // XXX: these things DON'T need to be done each time mAudioMixer->setBufferProvider(name, track); mAudioMixer->enable(name); mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, &vlf); mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, &vrf); mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, &vaf); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::FORMAT, (void *)track->format()); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask()); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mChannelMask); // limit track sample rate to 2 x output sample rate, which changes at re-configuration uint32_t maxSampleRate = mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX; uint32_t reqSampleRate = track->mAudioTrackServerProxy->getSampleRate(); if (reqSampleRate == 0) { reqSampleRate = mSampleRate; } else if (reqSampleRate > maxSampleRate) { reqSampleRate = maxSampleRate; } mAudioMixer->setParameter( name, AudioMixer::RESAMPLE, AudioMixer::SAMPLE_RATE, (void *)(uintptr_t)reqSampleRate); AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate(); mAudioMixer->setParameter( name, AudioMixer::TIMESTRETCH, AudioMixer::PLAYBACK_RATE, &playbackRate); /* * Select the appropriate output buffer for the track. * * Tracks with effects go into their own effects chain buffer * and from there into either mEffectBuffer or mSinkBuffer. * * Other tracks can use mMixerBuffer for higher precision * channel accumulation. If this buffer is enabled * (mMixerBufferEnabled true), then selected tracks will accumulate * into it. * */ if (mMixerBufferEnabled && (track->mainBuffer() == mSinkBuffer || track->mainBuffer() == mMixerBuffer)) { mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer); // TODO: override track->mainBuffer()? mMixerBufferValid = true; } else { mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *)AUDIO_FORMAT_PCM_16_BIT); mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer()); } mAudioMixer->setParameter( name, AudioMixer::TRACK, AudioMixer::AUX_BUFFER, (void *)track->auxBuffer()); // reset retry count track->mRetryCount = kMaxTrackRetries; // If one track is ready, set the mixer ready if: // - the mixer was not ready during previous round OR // - no other track is not ready if (mMixerStatusIgnoringFastTracks != MIXER_TRACKS_READY || mixerStatus != MIXER_TRACKS_ENABLED) { mixerStatus = MIXER_TRACKS_READY; } } else { if (framesReady < desiredFrames && !track->isStopped() && !track->isPaused()) { ALOGV("track(%p) underrun, framesReady(%zu) < framesDesired(%zd)", track, framesReady, desiredFrames); track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames); } else { track->mAudioTrackServerProxy->tallyUnderrunFrames(0); } // clear effect chain input buffer if an active track underruns to avoid sending // previous audio buffer again to effects chain = getEffectChain_l(track->sessionId()); if (chain != 0) { chain->clearInputBuffer(); } ALOGVV("track %d s=%08x [NOT READY] on thread %p", name, cblk->mServer, this); if ((track->sharedBuffer() != 0) || track->isTerminated() || track->isStopped() || track->isPaused()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. // TODO: use actual buffer filling status instead of latency when available from // audio HAL size_t audioHALFrames = (latency_l() * mSampleRate) / 1000; int64_t framesWritten = mBytesWritten / mFrameSize; if (mStandby || track->presentationComplete(framesWritten, audioHALFrames)) { if (track->isStopped()) { track->reset(); } tracksToRemove->add(track); } } else { // No buffers for this track. Give it a few chances to // fill a buffer, then remove it from active list. if (--(track->mRetryCount) <= 0) { ALOGI("BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this); tracksToRemove->add(track); // indicate to client process that the track was disabled because of underrun; // it will then automatically call start() when data is available track->disable(); // If one track is not ready, mark the mixer also not ready if: // - the mixer was ready during previous round OR // - no other track is ready } else if (mMixerStatusIgnoringFastTracks == MIXER_TRACKS_READY || mixerStatus != MIXER_TRACKS_READY) { mixerStatus = MIXER_TRACKS_ENABLED; } } mAudioMixer->disable(name); } } // local variable scope to avoid goto warning } // Push the new FastMixer state if necessary bool pauseAudioWatchdog = false; if (didModify) { state->mFastTracksGen++; // if the fast mixer was active, but now there are no fast tracks, then put it in cold idle if (kUseFastMixer == FastMixer_Dynamic && state->mCommand == FastMixerState::MIX_WRITE && state->mTrackMask <= 1) { state->mCommand = FastMixerState::COLD_IDLE; state->mColdFutexAddr = &mFastMixerFutex; state->mColdGen++; mFastMixerFutex = 0; if (kUseFastMixer == FastMixer_Dynamic) { mNormalSink = mOutputSink; } // If we go into cold idle, need to wait for acknowledgement // so that fast mixer stops doing I/O. block = FastMixerStateQueue::BLOCK_UNTIL_ACKED; pauseAudioWatchdog = true; } } if (sq != NULL) { sq->end(didModify); sq->push(block); } #ifdef AUDIO_WATCHDOG if (pauseAudioWatchdog && mAudioWatchdog != 0) { mAudioWatchdog->pause(); } #endif // Now perform the deferred reset on fast tracks that have stopped while (resetMask != 0) { size_t i = __builtin_ctz(resetMask); ALOG_ASSERT(i < count); resetMask &= ~(1 << i); sp<Track> t = mActiveTracks[i].promote(); if (t == 0) { continue; } Track* track = t.get(); ALOG_ASSERT(track->isFastTrack() && track->isStopped()); track->reset(); } // remove all the tracks that need to be... removeTracks_l(*tracksToRemove); if (getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX) != 0) { mEffectBufferValid = true; } if (mEffectBufferValid) { // as long as there are effects we should clear the effects buffer, to avoid // passing a non-clean buffer to the effect chain memset(mEffectBuffer, 0, mEffectBufferSize); } // sink or mix buffer must be cleared if all tracks are connected to an // effect chain as in this case the mixer will not write to the sink or mix buffer // and track effects will accumulate into it if ((mBytesRemaining == 0) && ((mixedTracks != 0 && mixedTracks == tracksWithEffect) || (mixedTracks == 0 && fastTracks > 0))) { // FIXME as a performance optimization, should remember previous zero status if (mMixerBufferValid) { memset(mMixerBuffer, 0, mMixerBufferSize); // TODO: In testing, mSinkBuffer below need not be cleared because // the PlaybackThread::threadLoop() copies mMixerBuffer into mSinkBuffer // after mixing. // // To enforce this guarantee: // ((mixedTracks != 0 && mixedTracks == tracksWithEffect) || // (mixedTracks == 0 && fastTracks > 0)) // must imply MIXER_TRACKS_READY. // Later, we may clear buffers regardless, and skip much of this logic. } // FIXME as a performance optimization, should remember previous zero status memset(mSinkBuffer, 0, mNormalFrameCount * mFrameSize); } // if any fast tracks, then status is ready mMixerStatusIgnoringFastTracks = mixerStatus; if (fastTracks > 0) { mixerStatus = MIXER_TRACKS_READY; } return mixerStatus; } 根据上下文优化这段代码
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值