Android的Audio音頻系統(tǒng).docx 免費(fèi)下載
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、音頻系統(tǒng)JJJNNNIII初始化在 system_init(運(yùn)行在 Simulator 上)或者 main_Mediaserver 中,AudioFlinger 被創(chuàng)建,會(huì)生成一個(gè) AudioHardwareInterface 實(shí)例(Android 定義的音頻設(shè)備的一個(gè)抽象層),并且初始化音頻系統(tǒng)的模式和路由信息如下:mHardwareStatus = AUDIO_HW_IDLE; mAudioHardware = AudioHardwareInterface:create(); mHardwareStatus = AUDIO_HW_INIT;if (mAudioHardware-initCh
2、eck() = NO_ERROR) / open 16-bit output stream for s/w mixer mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;mOutput = mAudioHardware-openOutputStream(AudioSystem:PCM_16_BIT); mHardwareStatus = AUDIO_HW_IDLE;if (mOutput) mSampleRate = mOutput-sampleRate();mChannelCount = mOutput-channelCount();mFormat = mOutp
3、ut-format();mMixBufferSize = mOutput-bufferSize();mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t); mMixBuffer = new int16_tmFrameCount * mChannelCount; memset(mMixBuffer, 0, mMixBufferSize);mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);/ FIXME - this should come from settings
4、 setMasterVolume(1.0f);setRouting(AudioSystem:MODE_NORMAL, AudioSystem:ROUTE_SPEAKER,AudioSystem:ROUTE_ALL);setRouting(AudioSystem:MODE_RINGTONE,AudioSystem:ROUTE_SPEAKER, AudioSystem:ROUTE_ALL); setRouting(AudioSystem:MODE_IN_CALL, AudioSystem:ROUTE_EARPIECE,AudioSystem:ROUTE_ALL); setMode(AudioSys
5、tem:MODE_NORMAL); mMasterMute = false; else LOGE(Failed to initialize output stream); else LOGE(Couldnt even initialize the stubbed audio hardware!);在 SystemServer 啟動(dòng)的時(shí)候,會(huì)生成一個(gè) AudioService 的實(shí)例, try Log.i(TAG, Starting Audio Service);ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(c
6、ontext); catch (Throwable e) Log.e(TAG, Failure starting Volume Service, e);AudioService 的構(gòu)造函數(shù)會(huì)讀取一些關(guān)于音頻的配置信息,比如 Ringer 和 vibrate 信息,private void readPersistedSettings() final ContentResolver cr = mContentResolver;mRingerMode=System.getInt(cr,System.MODE_RINGER,AudioManager.RINGER_MODE_NORMAL);mRinge
7、rModeAffectedStreams = System.getInt(mContentResolver,System.MODE_RINGER_STREAMS_AFFECTED,1AudioSystem.STREAM_RING);mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0);mMuteAffectedStreams = System.getInt(cr,System.MUTE_STREAMS_AFFECTED,(1 AudioSystem.STREAM_MUSIC)|(1 AudioSystem.STREAM_RING)|
8、(1 AudioSystem.STREAM_SYSTEM);/ Each stream will read its own persisted settings/ Broadcast the sticky intent broadcastRingerMode();/ Broadcast vibrate settings broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);同時(shí)也會(huì)從底層音頻系統(tǒng)讀取模式和
9、路由信息:private void readAudioSettings() synchronized (mSettingsLock) mMicMute = AudioSystem.isMicrophoneMuted();mMode = AudioSystem.getMode();for (int mode = 0; mode AudioSystem.NUM_MODES; mode+) mRoutesmode = AudioSystem.getRouting(mode);在 AudioSystem.cpp 第一次調(diào)用 get_audio_flinger 成功后,它會(huì)通過(guò) binder 來(lái)監(jiān)聽運(yùn)行
10、在 media_server 進(jìn)程中的 AudioFlinger 是否活著。/ establish binder interface to AudioFlinger serviceconst sp& AudioSystem:get_audio_flinger()Mutex:Autolock _l(gLock); if (gAudioFlinger.get() = 0) sp sm = defaultServiceManager(); sp binder;do binder = sm-getService(String16(media.audio_flinger); if (binder !=
11、0)break;LOGW(AudioFlinger not published, waiting.);usleep(500000); / 0.5 s while(true);if (gDeathNotifier = NULL) gDeathNotifier = new DeathNotifier(); else if (gAudioErrorCallback) gAudioErrorCallback(NO_ERROR);binder-linkToDeath(gDeathNotifier);gAudioFlinger = interface_cast(binder);LOGE_IF(gAudio
12、Flinger=0, no AudioFlinger!?);return gAudioFlinger;到此,整個(gè)音頻系統(tǒng)初始化完畢。重新啟動(dòng)如果 AudioFlinger 運(yùn)行的 media_server 進(jìn)程異常死掉,AudioSystem 會(huì)收到一個(gè)事件通知, void AudioSystem:DeathNotifier:binderDied(const wp& who) Mutex:Autolock _l(AudioSystem:gLock);AudioSystem:gAudioFlinger.clear();if (gAudioErrorCallback) gAudioErrorCal
13、lback(DEAD_OBJECT);LOGW(AudioFlinger server died!);從而調(diào)用 android_media_AudioSystem.cpp 注冊(cè)下來(lái)的回調(diào)函數(shù),該函數(shù)又是通過(guò) JNI 來(lái)調(diào)用 AudioService.java 注冊(cè)下來(lái)的回調(diào)函數(shù),在該函數(shù)中會(huì)發(fā)送MSG_MEDIA_SERVER_DIED消息,AudioService 會(huì)監(jiān)聽這個(gè)消息,這樣 AudioService 就能知道 AudioFlinger 已不工作,它就接著調(diào)用 getMode 來(lái)嘗試連接到重啟后的 AudioFlinger。case MSG_MEDIA_SERVER_DIED:Lo
14、g.e(TAG, Media server died.);/ Force creation of new IAudioflinger interface mMediaServerOk = false; AudioSystem.getMode();break;當(dāng)連接成功后,AudioFlinger 會(huì)調(diào)用 android_media_AudioSystem.cpp 注冊(cè)下來(lái)的回調(diào)函數(shù),該函數(shù)又是通過(guò) JNI 來(lái)調(diào)用 AudioService.java 注冊(cè)下來(lái)的回調(diào)函數(shù),在該函數(shù)中會(huì)發(fā)送 MSG_MEDIA_SERVER_STARTED 消息。接著 AudioService 就去配置底層音頻系統(tǒng)
15、,包括模式、路由、每一路流的音量大小和 Ringer 狀態(tài)。case MSG_MEDIA_SERVER_STARTED:/ Restore audio routing and stream volumes applyAudioSettings();for (int streamType = AudioSystem.NUM_STREAMS - 1; streamType= 0; streamType-) int volume;VolumeStreamState streamState = mStreamStatesstreamType; if (streamState.muteCount() =
16、 0) volume = streamState.mVolumesstreamState.mIndex; else volume = streamState.mVolumes0;AudioSystem.setVolume(streamType, volume);setRingerMode();Note: AudioSystem 的 Native 實(shí) 現(xiàn) 在 device/libs/android_runtime/android_media_AudioSystem.cpp 中。模式初始的時(shí)候音頻系統(tǒng)是處于 MODE_NORMAL 模式的,下面是其模式狀態(tài)變遷圖:?jiǎn)栴}:當(dāng)一個(gè) Ringtone 放
17、完了之后,理論上系統(tǒng)是否要自動(dòng)切換回 NORMAL 模式而不是必須要主動(dòng)調(diào)用 stopRing?我沒找到相關(guān) code。路由信息1. 當(dāng) HeadsetObserver 檢測(cè)到有耳機(jī)插上來(lái)的時(shí)候,它會(huì)把音頻系統(tǒng)的路由設(shè)置成均使用該耳機(jī);當(dāng)耳機(jī)被拔下來(lái)后,它會(huì)把音頻系統(tǒng)的路由設(shè)置成缺省配置(即都通過(guò)揚(yáng)聲器)。private synchronized final void update(String newName, int newState) if (newName != mHeadsetName | newState != mHeadsetState) mHeadsetName = newNa
18、me; mHeadsetState = newState;AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);if (mHeadsetState = 1) audioManager.setRouting(AudioManager.MODE_NORMAL,AudioManager.ROUTE_HEADSET,AudioManager.ROUTE_ALL);audioManager.setRouting(AudioManager.MODE_RINGTONE,Audio
19、Manager.ROUTE_HEADSET|AudioManager.ROUTE_SPEAKER,AudioManager.ROUTE_ALL);audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_HEADSET,AudioManager.ROUTE_ALL); else audioManager.setRouting(AudioManager.MODE_NORMAL,AudioManager.ROUTE_SPEAKER,AudioManager.ROUTE_ALL);audioManager.setRou
20、ting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_SPEAKER,AudioManager.ROUTE_ALL);audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_EARPIECE,AudioManager.ROUTE_ALL);sendIntent();PhoneApp 會(huì)接收到一個(gè) ACTION_HEADSET_PLUG 的 Intent,往自身發(fā)送一個(gè)消息,處理如下:只是在沒有藍(lán)牙耳機(jī)或者未使用藍(lán)牙耳機(jī),而且該有線耳機(jī)是被拔掉的情況下,才把路由信
21、息設(shè)置成 MODE_IN_CALL 走 ROUTE_SPEAKER。 case EVENT_WIRED_HEADSET_PLUG:/ Since the presence of a wired headset or bluetooth affects the/ speakerphone, update the speaker state. We ONLY want to do/ this on the wired headset connect / disconnect events for now/ though,sowereonlytriggeringonEVENT_WIRED_HEADS
22、ET_PLUG.if (!isHeadsetPlugged() &(mBtHandsfree = null | !mBtHandsfree.isAudioOn() / is the state is not connected, restore the speaker state. PhoneUtils.restoreSpeakerMode(getApplicationContext();NotificationMgr.getDefault().updateSpeakerNotification(); break;問(wèn)題:假設(shè)耳機(jī)插上來(lái)之前是通過(guò)藍(lán)牙耳機(jī)在接聽電話(或者聽音樂)的,耳機(jī)插上來(lái)的時(shí)
23、候系統(tǒng)就自動(dòng)切換到使用耳機(jī)了,但是 PhoneApp 這個(gè)時(shí)候并不知道,它還以為在繼續(xù)使用藍(lán)牙耳機(jī)。但當(dāng)耳機(jī)拔掉之后,怎么再切換回繼續(xù)使用藍(lán)牙耳機(jī)呢(系統(tǒng)默認(rèn)是切換成EARPIECE)?這個(gè)時(shí)候 PhoneApp 的狀態(tài)應(yīng)該是不對(duì)的。2. 當(dāng)在 Setting 里面把藍(lán)牙耳機(jī)配對(duì)和 RFCOMM 連接上之后,BluetoothHeadsetService 會(huì)負(fù)責(zé)去和藍(lán)牙耳機(jī)建立 SCO 連接,當(dāng)連接完成之后 BluetoothHandsfree 會(huì)調(diào)用AudioManager 的 setBluetoothScoOn 函數(shù)來(lái)通知音頻系統(tǒng)去切換 MODE_IN_CALL 路由信息到使用 ROUTE
24、_BLUETOOTH。/* Sets audio routing to the Bluetooth headset on or off.* param on set true to route SCO (voice) audio to/from Bluetooth* headset; false to route audio to/from phone earpiece*/public void setBluetoothScoOn(boolean on)setRouting(MODE_IN_CALL, on ? ROUTE_BLUETOOTH : ROUTE_EARPIECE, ROUTE_A
25、LL);當(dāng)藍(lán)牙設(shè)備被關(guān)閉或者鏈接斷掉的時(shí)候,BluetoothHeadsetService 會(huì)收到一個(gè) DISABLED_ACTION 的 Intent ,接著 BluetoothHandsfree 會(huì)調(diào)用 AudioManager 的 setBluetoothScoOn 函數(shù)來(lái)通知音頻系統(tǒng)去切換 MODE_IN_CALL 路由信息到ROUTE_EARPIECE。問(wèn)題:setBluetoothScoOn 的實(shí)現(xiàn)在處理藍(lán)牙設(shè)備被關(guān)閉的時(shí)候,是直接把路由信息改成到ROUTE_EARPIECE,并沒有恢復(fù)到使用藍(lán)牙設(shè)備之前的信息狀態(tài)。Ringtone 是否需要在藍(lán)牙耳機(jī)上播放呢?音量控制對(duì)外接口是
26、AudioManager播放音頻系統(tǒng)對(duì)外的播放接口是 AudioTrack,每一路音頻會(huì)對(duì)應(yīng)一個(gè) AudioTrack 的實(shí)例,它會(huì)通過(guò) iBinder 來(lái)遠(yuǎn)程調(diào)用 AudioFlinger 的 createTrack 函數(shù)。/ create the tracksp track = audioFlinger-createTrack(getpid(),streamType, sampleRate, format, channelCount, bufferCount, flags);if (track = 0) LOGE(AudioFlinger could not create track);r
27、eturn NO_INIT;sp cblk = track-getCblk();if (cblk = 0) LOGE(Could not get control block);return NO_INIT;而 AudioFlinger 的 createTrack 又會(huì)在內(nèi)部生成一個(gè) Track 實(shí)例,再將其包裝成 TrackHandle 返回給 AudioTrack。track = new Track(this, client, streamType, sampleRate, format,channelCount,bufferCount,channelCount=1?mMixBufferSi
28、ze1:mMixBufferSize);mTracks.add(track);trackHandle = new TrackHandle(track);return trackHandle;所以 AudioTrack 和 AudioFlinger 實(shí)際操作的都是 Track 實(shí)例,AudioTrack 通過(guò)它來(lái)執(zhí)行控制操作(start/stop)和寫入操作(write),AudioFlinger 則負(fù)責(zé)管理多個(gè) Track(包括調(diào)用 AudioMixer 來(lái)混音)。兩者之間的關(guān)系可以用生產(chǎn)者/消費(fèi)者來(lái)類比,AudioTrack 是生產(chǎn)者, AudioFlinger 則是消費(fèi)者。AudioTra
29、ckAudioTrack 的 start/stop 操作可以理解成一個(gè)開關(guān),控制的是是否將與之對(duì)應(yīng)的 Track 實(shí)例納入 AudioFlinger 的管理中去,下面僅以 start 操作為例。 void AudioTrack:start()LOGV(start);if (mAudioTrackThread != 0) mAudioTrackThread-mLock.lock();if (android_atomic_or(1, &mActive) = 0) setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);mActive =
30、 1;mAudioTrack-start();if (mAudioTrackThread != 0) mAudioTrackThread-run(AudioTrackThread,THREAD_PRIORITY_AUDIO_CLIENT);if (mAudioTrackThread != 0) mAudioTrackThread-mLock.unlock();status_t AudioFlinger:TrackHandle:start() return mTrack-start();status_t AudioFlinger:Track:start()LOGV(start(%d), mNam
31、e);mAudioFlinger-addTrack(this);return NO_ERROR;status_t AudioFlinger:addTrack(const sp& track)Mutex:Autolock _l(mLock);/ here the track could be either new, or restarted/ in both cases unstop the trackif (track-isPaused() track-mState = TrackBase:RESUMING; LOGV(PAUSED = RESUMING (%d), track-name();
32、 else track-mState = TrackBase:ACTIVE;LOGV(? = ACTIVE (%d), track-name();LOGV(mWaitWorkCV.broadcast);mWaitWorkCV.broadcast();if (mActiveTracks.indexOf(track) mFillingUpStatus = Track:FS_FILLING;mActiveTracks.add(track);return NO_ERROR;return ALREADY_EXISTS;AudioTrack 的 write 則是往 audio_track_cblk_t 結(jié)
33、構(gòu)中寫入數(shù)據(jù)。ssize_t AudioTrack:write(const void* buffer, size_t userSize)LOGV(write %d bytes, mActive=%d, userSize, mActive);ssize_t written = 0;do if (mPosition = 0) status_t err = obtainBuffer(&mAudioBuffer, true);if (err 0) / out of buffers, return #bytes writtenif (err = status_t(NO_MORE_BUFFERS)brea
34、k;return ssize_t(err);size_t capacity = mAudioBuffer.size - mPosition;size_t toWrite = userSize capacity ? userSize : capacity;memcpy(mAudioBuffer.i8 + mPosition, buffer, toWrite);buffer = static_cast(buffer) + toWrite;mPosition += toWrite;userSize -= toWrite;capacity -= toWrite;written += toWrite;i
35、f (capacity = 0) mPosition = 0;releaseBuffer(&mAudioBuffer); while (userSize); return written;AudioFlingerAudioFlinger 對(duì) Track 的管理是實(shí)現(xiàn)在 threadLoop 中的。先檢測(cè)進(jìn)入 standby 的超時(shí)是否到了,超時(shí)的話 AudioFlinger 會(huì)調(diào)用 AudioHardwareInterface 的 standby,這個(gè)是為省電考慮的。nsecs_t standbyTime = systemTime();do enabledTracks = 0; / scope
36、 for the lock Mutex:Autolock _l(mLock);const SortedVector wp & activeTracks = mActiveTracks; / put audio hardware into standby after short delayif UNLIKELY(systemTime() standbyTime) / wait until we have something to do.LOGD(Audio hardware entering standbyn); mHardwareStatus = AUDIO_HW_STANDBY; if (!
37、mStandby) mAudioHardware-standby(); mStandby = true;mHardwareStatus = AUDIO_HW_IDLE;/ were about to wait, flush the binder command buffer IPCThreadState:self()-flushCommands(); mWaitWorkCV.wait(mLock);LOGD(Audio hardware exiting standbyn); standbyTime = systemTime() + kStandbyTimeInNsecs;continue;如果
38、未進(jìn) standby,接下來(lái)遍歷所有當(dāng)前 Active 的 Track 實(shí)例。/ find out which tracks need to be processed size_t count = activeTracks.size();for (size_t i=0 ; icount ; i+) sp t = activeTmote(); if (t = 0) continue;Track* const track = t.get();audio_track_cblk_t* cblk = track-cblk();uint32_t u = cblk-user;uint32
39、_t s = cblk-server;/ The first time a track is added we wait/ for all its buffers to be filled before processing it audioMixer().setActiveTrack(track-name();當(dāng)有某個(gè) Track 的數(shù)據(jù)需要處理時(shí)(數(shù)據(jù)存儲(chǔ)在 audio_track_cblk_t 結(jié)構(gòu)中,其 user 域表明當(dāng)前寫入指針在 buffer 中的位置,server 域表明讀取指針在 buffer 中的位置,所以只有當(dāng) user 大于 server 的時(shí)候說(shuō)明有數(shù)據(jù)要處理),先計(jì)
40、算該 Track 的 volume 信息,然后去配置針對(duì)該路 Track 的 Mixer 信息。if (u s) & (track-isReady(u, s) | track-isStopped() & !track-isPaused()/ compute volume for this track/ setup mixer needed information here AudioMixer& mixer(audioMixer(); mixer.setBufferProvider(track); mixer.enable(AudioMixer:MIXING);enabledTracks+;
41、else 最后進(jìn)入真正的混音操作,再把混音過(guò)后的數(shù)據(jù)寫到 AudioHardwareInterface 生成的AudioOutputStream 中,由此整個(gè)音頻輸出完成。if (LIKELY(enabledTracks) / mix buffers.audioMixer().process(curBuf);/ output audio to hardware mLastWriteTime = systemTime(); mInWrite = true; mOutput-write(curBuf, mixBufferSize); mNumWrites+;mInWrite = false;mSt
42、andby = false;nsecs_t temp = systemTime();standbyTime = temp + kStandbyTimeInNsecs;nsecs_t delta = temp - mLastWriteTime;if (delta maxPeriod) LOGW(write blocked for %llu msecs, ns2ms(delta); mNumDelayedWrites+;sleepTime = kBufferRecoveryInUsecs; else 當(dāng)所有 Active 的 Track 都沒有數(shù)據(jù)需要處理的時(shí)候,AudioFlinger 會(huì) us
43、leep 一段時(shí)間從而進(jìn)入 standby。/ There was nothing to mix this round, which means all/ active tracks were late. Sleep a little bit to give/ them another chance. If were too late, the audio/ hardware will zero-fill for us.LOGV(no buffers - usleep(%lu), sleepTime);usleep(sleepTime);if (sleepTime kMaxBufferReco
44、veryInUsecs) sleepTime += kBufferRecoveryInUsecs;錄制音頻系統(tǒng)對(duì)外的錄制接口是 AudioRecord,它會(huì)通過(guò) iBinder 來(lái)遠(yuǎn)程調(diào)用 AudioFlinger 的 openRecord 函數(shù)。/ open record channelsp record = audioFlinger-openRecord(getpid(), streamType, sampleRate, format, channelCount, bufferCount, flags);if (record = 0) return NO_INIT;sp cblk = re
45、cord-getCblk();if (cblk = 0) return NO_INIT;if (cbf != 0) mClientRecordThread = new ClientRecordThread(*this); if (mClientRecordThread = 0) return NO_INIT;而 AudioFlinger 的 openRecord 又會(huì)在內(nèi)部先生成一個(gè) AudioRecordThread 并且拿到AudioStreamIn,/ Create audio thread - take mutex to prevent race conditionMutex:Auto
46、lock _l(mLock);if (mAudioRecordThread != 0) LOGE(Record channel already open); goto Exit;thread = new AudioRecordThread(this); mAudioRecordThread = thread;/ Its safe to release the mutex here since the client doesnt get a/ handle until we return from this call/ open driver, initialize h/winput = mAu
47、dioHardware-openInputStream(AudioSystem:PCM_16_BIT, channelCount, sampleRate);再生成一個(gè) RecordTrack 實(shí)例,將其包裝成 RecordTrackHandle 返回給 AudioRecord。 / create new record track and pass to record threadrecordTrack = new RecordTrack(this, client, streamType, sampleRate, format, channelCount, bufferCount, input-bufferSize();/ spin up record threadthread-open(recordTrack, input);thread-run(AudioRecordThread, PRIORITY_URGENT_AUDIO);/ return to handle to clientrecordHandle = new RecordHandle(recordTrack);所以 AudioRecord 和 AudioFlinger
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 球囊擴(kuò)張椎體成形術(shù)的操作要點(diǎn)
- 泰康保險(xiǎn)法律事務(wù)部經(jīng)理面試題及答案解析
- 深度解析(2026)《GBT 19324-2003涂附磨具 帶除塵孔砂頁(yè)》
- OLED液晶顯示模塊項(xiàng)目可行性分析報(bào)告范文
- 酒店業(yè)面試技巧及常見問(wèn)題解析
- 能源企業(yè)福利政策制定面試要點(diǎn)及答案
- 交通運(yùn)輸行業(yè)安全管理專員的專業(yè)面試題
- 現(xiàn)場(chǎng)改善與問(wèn)題解決能力提升
- 湖南省懷化市通道縣2025-2026學(xué)年七年級(jí)上學(xué)期期中考試歷史試題解析版
- 行政助理面試全攻略與參考答案
- 北京林業(yè)大學(xué)《線性系統(tǒng)理論基礎(chǔ)》2025-2026學(xué)年第一學(xué)期期末試卷
- 2025四川廣元旺蒼縣旺泰人力資源服務(wù)有限公司代理部分縣屬國(guó)有企業(yè)面向社會(huì)考試招聘工作人員19人考試筆試備考試題及答案解析
- 描繪自強(qiáng)人生課件
- 25秋國(guó)家開放大學(xué)《理工英語(yǔ)3》形考任務(wù)參考答案
- 2025-2026學(xué)年安徽省合肥一中高一(上)期中英語(yǔ)試卷
- 企業(yè)雙重預(yù)防體系建設(shè)管理手冊(cè)
- 銀行內(nèi)部控制合規(guī)性檢查報(bào)告
- 2025春季學(xué)期國(guó)開電大本科《理工英語(yǔ)4》一平臺(tái)機(jī)考真題及答案(第一套)
- 偉大的《紅樓夢(mèng)》智慧樹知到期末考試答案章節(jié)答案2024年北京大學(xué)
- GB/T 3521-2023石墨化學(xué)分析方法
- 三維動(dòng)畫及特效制作智慧樹知到課后章節(jié)答案2023年下吉林電子信息職業(yè)技術(shù)學(xué)院
評(píng)論
0/150
提交評(píng)論