音訊驅動程式的用戶端會使用 KSPROPERTY_AUDIO_POSITION 屬性來取得和設定音訊資料流程中的目前位置。 屬性會使用 KSAUDIO_POSITION 結構來描述目前位置。 結構包含兩個成員: PlayOffset 和 WriteOffset。
PlayOffset 和 WriteOffset 成員會定義用戶端緩衝區區域的界限,該區域目前保留給音訊裝置獨佔使用。 用戶端必須假設裝置目前可能正在存取此區域中包含的任何資料。 因此,用戶端必須只存取位於此區域之外的緩衝區部分。 區域的邊界會隨著溪流的前進而移動。
如果用戶端緩衝區是迴圈的(也就是資料流程類型為KSINTERFACE_STANDARD_LOOPED_STREAMING),則PlayOffset和WriteOffset是緩衝區相對位移。 也就是說,它們會指定為迴圈用戶端緩衝區開頭的位元組位移。 當任一位移遞增至緩衝區結尾時,它會循環至緩衝區的開頭。 (緩衝區開頭的位移為零。因此,任何位移都不會超過緩衝區大小。
如果用戶端緩衝區是非迴圈的 (,也就是資料流程類型為 KSINTERFACE_STANDARD_STREAMING) , PlayOffset 和 WriteOffset 是資料流程相對位移。 也就是說,它們會指定為從數據流開頭的位元組位移。 這些位移可以視為理想化緩衝區的位移,其中包含整個資料流,而且從頭到尾都是連續的。
在轉譯資料流程的情況下, PlayOffset 成員會指定資料流程的播放位置,而 WriteOffset 成員會指定資料流程的寫入位置。 下圖顯示用戶端緩衝區中的播放和寫入位置。
播放位置是目前正在播放的樣本的位元組偏移量 (也就是,鎖定在數位類比轉換器或 DAC 輸入處的樣本) 。 寫入位置是用戶端可以安全地寫入緩衝區的位置。 當串流播放時,播放和寫入位置會在上圖中從左向右移動。 客戶端的寫入必須保持在寫入位置的前面。 此外,如果緩衝區循環,用戶端的寫入絕不能超過播放位置。
雖然 WaveCyclic 或 WavePci 埠驅動程式依賴迷你埠驅動程式來追蹤播放位置,但埠驅動程式會追蹤寫入位置。 WaveCyclic 和 WavePci 埠驅動程式會更新寫入位置,如下所示:
波浪循環
每次 WaveCyclic 埠驅動程式呼叫 IDmaChannel::CopyTo 將新的資料區塊複製到循環緩衝區 (從用戶端緩衝區) 時,寫入位置會前進至資料區塊中最後一個位元組的位置 (用戶端緩衝區) 。
WavePci
根據預設,每次 WavePci 迷你埠驅動程式呼叫 IPortWavePciStream::GetMapping 以取得用戶端緩衝區一部分的新對應 (,且呼叫成功) 時,寫入位置會前進至新對應中最後一個位元組的位置 (用戶端緩衝區) 。
如果 WavePci 迷你埠驅動程式透過向埠驅動程式設定預取位移來覆蓋預設行為,則目前的寫入位置總是等於目前的播放位置和預取位移的總和。 如需詳細資訊,請參閱 預取位移。
在擷取資料流程的情況下, PlayOffset 成員會指定資料流程的記錄位置,而 WriteOffset 成員會指定資料流程的讀取位置。 下圖顯示用戶端緩衝區中的記錄和讀取位置。
記錄位置是最新樣本在類比數位轉換器(ADC)輸出端鎖存的位元組偏移。 (此位置會指定音訊裝置的 DMA 引擎最終會寫入範例的緩衝區位置。讀取位置是用戶端無法從緩衝區安全地讀取的位置。 隨著串流的記錄進行,讀取和記錄位置會在前圖中從左到右前進。 用戶端的讀取必須追蹤讀取位置。 此外,如果緩衝區是循環的,用戶端的讀取操作必須保持在記錄位置之前。
雖然 WaveCyclic 或 WavePci 埠驅動程式依賴迷你埠驅動程式來追蹤記錄位置,但埠驅動程式會追蹤讀取位置。 WaveCyclic 和 WavePci 埠驅動程式會更新讀取位置,如下所示:
波浪循環
每次 WaveCyclic 埠驅動程式呼叫 IDmaChannel::CopyFrom 將新的數據區塊從循環緩衝區複製到用戶端緩衝區 (時) ,讀取位置會前進至數據區塊中最後一個位元組的位置 (用戶端緩衝區) 。
WavePci
每次 WavePci 迷你埠驅動程式呼叫 IPortWavePciStream::ReleaseMapping 來釋放先前取得的對應 (用戶端緩衝區的一部分) 時,讀取位置會前進至已釋放對應中最後一個位元組的位置 (用戶端緩衝區) 。
迷你埠驅動程式不需要實作KSPROPERTY_AUDIO_POSITION屬性要求的處理常式。 相反地,WaveCyclic 和 WavePci 埠驅動程式會代表迷你埠驅動程式處理這些要求。 處理 get-property 要求時,WaveCyclic 或 WavePci 埠驅動程式已經具有計算 WriteOffset 值所需的所有資訊,但仍需要迷你埠驅動程式的資訊來計算 PlayOffset 值。 若要取得這項資訊,埠驅動程式會呼叫迷你埠驅動程式的 IMiniportWaveCyclicStream::GetPosition 或 IMiniportWavePciStream::GetPosition 方法。
針對轉譯資料流程, GetPosition 方法會擷取播放位置 - 目前透過 DAC 播放之範例的位元組位移。 針對擷取資料流程,GetPosition 方法會取得記錄位置,即 ADC 最近要擷取的範例的位元組偏移。
請注意, GetPosition 呼叫所擷取的位移值是對應至目前透過喇叭插孔傳輸之訊號的播放位置,或對應至目前透過麥克風插孔接收之訊號的記錄位置。 這不是 DMA 的立場。 (DMA 位置是音訊裝置中的 DMA 引擎目前將 DMA 緩衝區傳輸至或從 DMA 緩衝區傳輸的範例位元組位移。
某些音訊硬體包含位置暫存器,用於追蹤目前在每個 DAC 或 ADC 中取樣的位元組位移。在此情況下,GetPosition 方法只會擷取適當音訊串流的位置暫存器內容。 其他音訊硬體只能為驅動程式提供 DMA 位置,在此情況下, GetPosition 方法必須考量目前的 DMA 位置和裝置內部的緩衝延遲,以提供 DAC 或 ADC 中樣本位元組位移的最佳估計值。
雖然 WaveCyclic 或 WavePci 埠驅動程式中的屬性處理常式必須區分迴圈和非迴圈緩衝區,以判斷是否要提供資料流程相對或緩衝區相對位元組位移,但此詳細數據 (也就是緩衝區是迴圈還是非迴圈) 對迷你埠驅動程式是透明的。
IMiniportWaveCyclicStream::GetPosition 方法一律會報告緩衝區相對播放或記錄位置,不論用戶端緩衝區是迴圈或非迴圈。 如果用戶端緩衝區迴圈,屬性處理常式會將迷你埠驅動程式所報告的緩衝區相對位置 (表示為循環緩衝區的位移) 轉換成用戶端緩衝區的位移,然後處理常式會將其寫入 PlayOffset 成員。 如果用戶端緩衝區未迴圈,屬性處理常式會先將緩衝區相對播放位置轉換成串流相對播放位置,再將它寫入 PlayOffset 成員。
IMiniportWavePciStream::GetPosition 方法一律會報告串流相對的播放或錄製位置,不論用戶端快取記憶體是迴圈還是非迴圈。 如果用戶端緩衝區是在迴圈中運作,則屬性處理常式會在寫入屬性要求的 KSAUDIO_POSITION 結構中的 PlayOffset 成員之前,將資料流相對播放位置轉換成相對於用戶端緩衝區的位移位置。 如果用戶端緩衝區未迴圈,屬性處理常式會將資料流程相對位置寫入 PlayOffset 成員。
在資料串流初始化之後,播放或紀錄的位置立即歸零。 轉換至KSSTATE_STOP狀態 (請參閱 KSSTATE) 會將位置重設為零。 當數據流因從KSSTATE_RUN轉換至KSSTATE_PAUSE或KSSTATE_ACQUIRE而停止時,位置會凍結。 當數據流從KSSTATE_PAUSE或KSSTATE_ACQUIRE轉換回KSSTATE_RUN時,它會解除凍結。
如需 WaveCyclic 和 WavePci 迷你埠驅動程式的 GetPosition 方法實作範例,請參閱 Windows 驅動程式套件 (WDK) 中的範例音訊驅動程式。