GetSourceOffset * * Gets the current read offset for the given Source, in the appropriate format * (Bytes, Samples or Seconds). The offset is relative to the start of the * queue (not the start of the current buffer). */
| 280 | * queue (not the start of the current buffer). |
| 281 | */ |
| 282 | ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) |
| 283 | { |
| 284 | ALCdevice *device{context->mDevice.get()}; |
| 285 | const ALbufferlistitem *Current; |
| 286 | ALuint readPos; |
| 287 | ALuint readPosFrac; |
| 288 | ALuint refcount; |
| 289 | ALvoice *voice; |
| 290 | |
| 291 | do { |
| 292 | Current = nullptr; |
| 293 | readPos = readPosFrac = 0; |
| 294 | while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) |
| 295 | std::this_thread::yield(); |
| 296 | voice = GetSourceVoice(Source, context); |
| 297 | if(voice) |
| 298 | { |
| 299 | Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); |
| 300 | |
| 301 | readPos = voice->mPosition.load(std::memory_order_relaxed); |
| 302 | readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed); |
| 303 | } |
| 304 | std::atomic_thread_fence(std::memory_order_acquire); |
| 305 | } while(refcount != device->MixCount.load(std::memory_order_relaxed)); |
| 306 | |
| 307 | ALdouble offset{0.0}; |
| 308 | if(!voice) return offset; |
| 309 | |
| 310 | const ALbufferlistitem *BufferList{Source->queue}; |
| 311 | const ALbuffer *BufferFmt{nullptr}; |
| 312 | ALuint totalBufferLen{0u}; |
| 313 | bool readFin{false}; |
| 314 | |
| 315 | while(BufferList) |
| 316 | { |
| 317 | if(!BufferFmt) BufferFmt = BufferList->mBuffer; |
| 318 | |
| 319 | readFin |= (BufferList == Current); |
| 320 | totalBufferLen += BufferList->mSampleLen; |
| 321 | if(!readFin) readPos += BufferList->mSampleLen; |
| 322 | |
| 323 | BufferList = BufferList->mNext.load(std::memory_order_relaxed); |
| 324 | } |
| 325 | assert(BufferFmt != nullptr); |
| 326 | |
| 327 | if(Source->Looping) |
| 328 | readPos %= totalBufferLen; |
| 329 | else |
| 330 | { |
| 331 | /* Wrap back to 0 */ |
| 332 | if(readPos >= totalBufferLen) |
| 333 | readPos = readPosFrac = 0; |
| 334 | } |
| 335 | |
| 336 | switch(name) |
| 337 | { |
| 338 | case AL_SEC_OFFSET: |
| 339 | offset = (readPos + static_cast<ALdouble>(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; |
no test coverage detected