Ejemplo n.º 1
0
        // should be called in Update thread
        public void Service()
        {
            if (this.started)
            {
                lock (frameQueue)
                {
                    while (frameQueue.Count > 0)
                    {
                        var frame = frameQueue.Dequeue();
                        this.source.clip.SetData(frame, this.inputSamplePos % this.bufferSamples);
                        this.inputSamplePos += frame.Length / this.channels;
                        framePool.Release(frame);
                    }
                }


                // loop detection (pcmsetpositioncallback not called when clip loops)
                if (this.source.isPlaying)
                {
                    if (this.source.timeSamples < sourceTimeSamplesPrev)
                    {
                        playLoopCount++;
                    }
                    sourceTimeSamplesPrev = this.source.timeSamples;
                }
            }
        }
Ejemplo n.º 2
0
        // should be called in Update thread
        public void Service()
        {
            if (this.started)
            {
                lock (this.frameQueue)
                {
                    while (frameQueue.Count > 0)
                    {
                        var frame = frameQueue.Dequeue();
                        this.source.clip.SetData(frame, this.clipWriteSamplePos % this.bufferSamples);
                        this.clipWriteSamplePos += frame.Length / this.channels;
                        framePool.Release(frame);
                    }
                }
                // loop detection (pcmsetpositioncallback not called when clip loops)
                if (this.source.isPlaying)
                {
                    if (this.source.timeSamples < sourceTimeSamplesPrev)
                    {
                        playLoopCount++;
                    }
                    sourceTimeSamplesPrev = this.source.timeSamples;
                }

                var playSamplesPos = this.playSamplePos;
                var lagSamples     = this.clipWriteSamplePos - playSamplesPos;
                if (lagSamples > targetPlayDelaySamples + maxDevPlayDelaySamples)
                {
                    this.source.UnPause();
                    this.playSamplePos = this.clipWriteSamplePos - targetPlayDelaySamples;
                    if (this.debugInfo)
                    {
                        this.logger.LogWarning("{0} UnityAudioOut overrun {1} {2} {3} {4} {5}", this.logPrefix, targetPlayDelaySamples - maxDevPlayDelaySamples, targetPlayDelaySamples + maxDevPlayDelaySamples, lagSamples, this.clipWriteSamplePos, playSamplesPos);
                    }
                }
                else if (lagSamples < targetPlayDelaySamples - maxDevPlayDelaySamples)
                {
                    //this.playSamplePos = this.clipWriteSamplePos - targetPlayDelaySamples;
                    if (this.source.isPlaying)
                    {
                        this.source.Pause();
                        if (this.debugInfo)
                        {
                            this.logger.LogWarning("{0} UnityAudioOut underrun {1} {2} {3} {4} {5}", this.logPrefix, targetPlayDelaySamples - maxDevPlayDelaySamples, targetPlayDelaySamples + maxDevPlayDelaySamples, lagSamples, this.clipWriteSamplePos, playSamplesPos);
                        }
                    }
                }
                else
                {
                    this.source.UnPause();
                }
            }
        }
Ejemplo n.º 3
0
 internal static void Play()
 {
     while (!playThreadShouldTerminate)
     {
         if (frameBuf != null)
         {
             float[] frameMix = null;
             lock (locker)
             {
                 foreach (var it in frameBuf)
                 {
                     if (it.Value.Count >= GRANULARITY * 2)
                     {
                         if (frameMix == null)
                         {
                             frameMix = staticFramePool.AcquireOrCreate();
                             for (int i = 0; i < GRANULARITY * 2; ++i)
                             {
                                 frameMix[i] = it.Value.Dequeue();
                             }
                         }
                         else
                         {
                             for (int i = 0; i < GRANULARITY * 2; ++i)
                             {
                                 frameMix[i] += it.Value.Dequeue();
                             }
                         }
                         it.Key.IsPlaying = true;
                     }
                 }
             }
             if (frameMix != null)
             {
                 unsafe
                 {
                     fixed(float *pArray = frameMix)
                     egpvplay(pPhotonVoiceAudioOutput, new IntPtr(pArray));
                 }
                 staticFramePool.Release(frameMix);
                 lock (locker)
                     foreach (var it in frameBuf)
                     {
                         it.Key.IsPlaying = false;
                     }
             }
         }
     }
 }
Ejemplo n.º 4
0
        // should be called in Update thread
        public void Service()
        {
            if (this.started)
            {
                // cache source.timeSamples
                int sourceTimeSamples = source.timeSamples;
                // loop detection (pcmsetpositioncallback not called when clip loops)
                if (sourceTimeSamples < sourceTimeSamplesPrev)
                {
                    playLoopCount++;
                }
                sourceTimeSamplesPrev = sourceTimeSamples;


                var playSamplePos = this.playLoopCount * this.bufferSamples + sourceTimeSamples;

                var lagSamples = this.clipWriteSamplePos - playSamplePos;
                if (!this.flushed)
                {
                    if (lagSamples > maxDelaySamples)
                    {
                        if (this.debugInfo)
                        {
                            this.logger.LogWarning("{0} UnityAudioOut overrun {1} {2} {3} {4} {5} {6}", this.logPrefix, lowerTargetDelaySamples, upperTargetDelaySamples, lagSamples, playSamplePos, this.clipWriteSamplePos, playSamplePos + targetDelaySamples);
                        }
                        this.clipWriteSamplePos = playSamplePos + maxDelaySamples;
                        lagSamples = maxDelaySamples;
                    }
                    else if (lagSamples < lowerTargetDelaySamples)
                    {
                        if (this.debugInfo)
                        {
                            this.logger.LogWarning("{0} UnityAudioOut underrun {1} {2} {3} {4} {5} {6}", this.logPrefix, lowerTargetDelaySamples, upperTargetDelaySamples, lagSamples, playSamplePos, this.clipWriteSamplePos, playSamplePos + targetDelaySamples);
                        }
                        this.clipWriteSamplePos = playSamplePos + targetDelaySamples;
                        lagSamples = targetDelaySamples;
                    }
                }

                lock (this.frameQueue)
                {
                    while (frameQueue.Count > 0)
                    {
                        var frame = frameQueue.Dequeue();
                        if (frame == null) // flush signalled
                        {
                            this.flushed = true;
                            if (catchingUp)
                            {
                                catchingUp = false;
                                this.logger.LogWarning("{0} UnityAudioOut stream sync reset {1} {2} {3} {4} {5} {6}", this.logPrefix, lowerTargetDelaySamples, upperTargetDelaySamples, lagSamples, playSamplePos, this.clipWriteSamplePos, playSamplePos + targetDelaySamples);
                            }
                            return;
                        }
                        else
                        {
                            if (this.flushed)
                            {
                                this.clipWriteSamplePos = playSamplePos + targetDelaySamples;
                                lagSamples   = targetDelaySamples;
                                this.flushed = false;
                            }
                        }

                        if (lagSamples > upperTargetDelaySamples && !catchingUp)
                        {
                            catchingUp = true;
                            this.logger.LogWarning("{0} UnityAudioOut stream sync started {1} {2} {3} {4} {5} {6}", this.logPrefix, lowerTargetDelaySamples, upperTargetDelaySamples, lagSamples, playSamplePos, this.clipWriteSamplePos, playSamplePos + targetDelaySamples);
                        }

                        if (lagSamples <= targetDelaySamples && catchingUp)
                        {
                            catchingUp = false;
                            this.logger.LogWarning("{0} UnityAudioOut stream sync finished {1} {2} {3} {4} {5} {6}", this.logPrefix, lowerTargetDelaySamples, upperTargetDelaySamples, lagSamples, playSamplePos, this.clipWriteSamplePos, playSamplePos + targetDelaySamples);
                        }

                        if (catchingUp)
                        {
                            const int STEPS        = 3;
                            int       resampledLen = frame.Length;
                            int       k            = STEPS * (lagSamples - targetDelaySamples) / (resampleRampEndDelaySamples - targetDelaySamples);
                            if (k >= STEPS)
                            {
                                k = STEPS - 1;
                            }
                            if (k >= 0)
                            {
                                resampledLen = frame.Length * (100 - 5 * (k + 1)) / 100;
                            }

                            AudioUtil.Resample(frame, resampledFrame, resampledLen, channels);

                            // zero not used part of the buffer because SetData applies entire frame
                            // if this frame is the last, grabage may be played back
                            for (int i = resampledLen; i < resampledFrame.Length; i++)
                            {
                                resampledFrame[i] = 0;
                            }
                            this.source.clip.SetData(resampledFrame, this.clipWriteSamplePos % this.bufferSamples);
                            this.clipWriteSamplePos += resampledLen / this.channels;
                            lagSamples -= resampledLen / this.channels;
                        }
                        else
                        {
                            this.source.clip.SetData(frame, this.clipWriteSamplePos % this.bufferSamples);
                            this.clipWriteSamplePos += frame.Length / this.channels;
                        }
                        framePool.Release(frame);
                    }
                }

                // clear played back buffer segment
                var clearStart = this.playSamplePosPrev;
                var clearMin   = playSamplePos - this.bufferSamples;
                if (clearStart < clearMin)
                {
                    clearStart = clearMin;
                }
                // round up
                var framesToClear = (playSamplePos - clearStart - 1) / this.frameSamples + 1;
                for (var offset = playSamplePos - framesToClear * this.frameSamples; offset < playSamplePos; offset += this.frameSamples)
                {
                    var o = offset % this.bufferSamples;
                    if (o < 0)
                    {
                        o += this.bufferSamples;
                    }
                    this.source.clip.SetData(this.zeroFrame, o);
                }
                this.playSamplePosPrev = playSamplePos;
            }
        }
Ejemplo n.º 5
0
    // should be called in Update thread
    public void Service()
    {
        if (this.source.clip != null)
        {
            lock (frameQueue)
            {
                while (frameQueue.Count > 0)
                {
                    var frame = frameQueue.Dequeue();
                    this.source.clip.SetData(frame, this.streamSamplePos % this.bufferSamples);
                    framePool.Release(frame);
                    this.streamSamplePos += frame.Length / this.channels;
                }
            }
            // loop detection (pcmsetpositioncallback not called when clip loops)
            if (this.source.isPlaying)
            {
                if (this.source.timeSamples < sourceTimeSamplesPrev)
                {
                    playLoopCount++;
                }
                sourceTimeSamplesPrev = this.source.timeSamples;
            }

            var playPos = this.playSamplePos; // cache calculated value

            // average jittering value
            this.CurrentBufferLag = (this.CurrentBufferLag * 39 + (this.streamSamplePos - playPos)) / 40;

            // calc jitter-free stream position based on clock-driven player position and average lag
            this.streamSamplePosAvg = playPos + this.CurrentBufferLag;
            if (this.streamSamplePosAvg > this.streamSamplePos)
            {
                this.streamSamplePosAvg = this.streamSamplePos;
            }

            // start with given delay or when stream position is ok after overrun pause
            if (playPos < this.streamSamplePos - this.playDelaySamples)
            {
                if (!this.source.isPlaying)
                {
                    this.source.UnPause();
                }
            }

            if (playPos > this.streamSamplePos - frameSamples)
            {
                if (this.source.isPlaying)
                {
                    if (this.debugInfo)
                    {
                        Debug.LogWarningFormat("{0} player overrun: {1}/{2}({3}) = {4}", this.logPrefix, playPos, streamSamplePos, streamSamplePosAvg, streamSamplePos - playPos);
                    }

                    // when nothing to play:
                    // pause player  (useful in case if stream is stopped for good) ...
                    this.source.Pause();

                    // ... and rewind to proper position
                    playPos               = this.streamSamplePos;
                    this.playSamplePos    = playPos;
                    this.CurrentBufferLag = this.playDelaySamples;
                }
            }
            if (this.source.isPlaying)
            {
                var lowerBound = this.streamSamplePos - this.playDelaySamples - maxPlayLagSamples;
                if (playPos < lowerBound)
                {
                    if (this.debugInfo)
                    {
                        Debug.LogWarningFormat("{0} player underrun: {1}/{2}({3}) = {4}", this.logPrefix, playPos, streamSamplePos, streamSamplePosAvg, streamSamplePos - playPos);
                    }

                    // if lag exceeds max allowable, fast forward to proper position
                    playPos               = this.streamSamplePos - this.playDelaySamples;
                    this.playSamplePos    = playPos;
                    this.CurrentBufferLag = this.playDelaySamples;
                }
            }
        }
    }