Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- private long GetPublishBufferDelay()
- {
- ulong readSamples = delayMicrophone.ReadSamples;
- int nBytesPerSample = (int)Math.Round(((double)waveIn.WaveFormat.BitsPerSample / 8.0));
- long nBytesPerMs = (long)Math.Round(((double)nBytesPerSample * (double)waveIn.WaveFormat.SampleRate) / 1000.0);
- int nSamplePerMs = (int)Math.Round(waveIn.WaveFormat.SampleRate / 1000.0);
- ulong recSamples = (ulong)((double)waveIn.GetPosition() / (double)nBytesPerSample);
- int delayNAudio = (int)waveIn.BufferedDuration.TotalMilliseconds;
- long recDifference = (long)(delayMicrophone.OldRecSamples - recSamples);
- if (recDifference > 64000)
- {
- logger(null, FLV_LogLevel.DEBUG, String.Format("WRAP 1 (recDifference ={0})", recDifference));
- // If the sound cards number-of-recorded-samples variable wraps around before
- // read_sampels wraps around this needs to be adjusted. This can happen on
- // sound cards that uses less than 32 bits to keep track of number of played out
- // sampels. To avoid being fooled by sound cards that sometimes produces false
- // output we compare old value minus the new value with a large value. This is
- // neccessary because some SC:s produce an output like 153, 198, 175, 230 which
- // would trigger the wrap-around function if we didn't compare with a large value.
- // The value 64000 is chosen because 2^16=65536 so we allow wrap around at 16 bits.
- //
- int i = 31;
- while ((delayMicrophone.OldRecSamples <= (ulong)Math.Pow(2, i)) && (i > 14))
- i--;
- if ((i < 31) && (i > 14))
- {
- // Avoid adjusting when there is 32-bit wrap-around since that is
- // somethying neccessary.
- //
- delayMicrophone.ReadSamples = delayMicrophone.ReadSamples - (ulong)Math.Pow(2, i + 1);
- readSamples = delayMicrophone.ReadSamples;
- delayMicrophone.WrapCounter++;
- }
- else
- {
- logger(null, FLV_LogLevel.DEBUG, String.Format("AEC (_rec_samples_old {0} recSamples {1})", delayMicrophone.OldRecSamples, recSamples));
- }
- }
- if ((delayMicrophone.WrapCounter > 200))
- {
- // Do nothing, handled later
- }
- else if ((delayMicrophone.OldRecSamples > (ulong)Math.Pow(2, 31)) && (recSamples < 96000))
- {
- logger(null, FLV_LogLevel.DEBUG, String.Format("WRAP 2 (_rec_samples_old {0} recSamples {1})", delayMicrophone.OldRecSamples, recSamples));
- // Wrap around as expected after having used all 32 bits.
- delayMicrophone.OldReadSamples = readSamples;
- delayMicrophone.OldRecSamples = recSamples;
- delayMicrophone.WrapCounter++;
- int delay = (int) ((double) (recSamples + (ulong) Math.Pow(2, 32) - readSamples) / (double) nSamplePerMs);
- logger(null, FLV_LogLevel.DEBUG, String.Format("[AEC]GetPublishBufferDelay(0) delayInbuffer({0}) BuiltIn({1}) NAudio({2}) wrapCounter({3})", delay + delayNAudio, delay, delayNAudio, delayMicrophone.WrapCounter));
- return delay;
- }
- else if ((recSamples < 96000) && (readSamples > Math.Pow(2, 31)))
- {
- logger(null, FLV_LogLevel.DEBUG, String.Format("WRAP 3 (readSamples {0} recSamples {1})", readSamples, recSamples));
- // Wrap around has, as expected, happened for rec_sampels before
- // readSampels so we have to adjust for this until also readSampels
- // has had wrap around.
- delayMicrophone.OldReadSamples = readSamples;
- delayMicrophone.OldRecSamples = recSamples;
- delayMicrophone.WrapCounter++;
- int delay = (int)((double)(recSamples + Math.Pow(2, 32) - readSamples) / (double)nSamplePerMs);
- logger(null, FLV_LogLevel.DEBUG, String.Format("[AEC]GetPublishBufferDelay(1) delayInbuffer({0}) BuiltIn({1}) NAudio({2}) wrapCounter({3})", delay + delayNAudio, delay, delayNAudio, delayMicrophone.WrapCounter));
- return delay;
- }
- delayMicrophone.OldReadSamples = delayMicrophone.ReadSamples;
- delayMicrophone.OldRecSamples = recSamples;
- int res = (int)Math.Round((double)(delayMicrophone.OldRecSamples - delayMicrophone.OldReadSamples) / (double)nSamplePerMs);
- if ((res > 2000) || (res < 0) || (delayMicrophone.WrapCounter > 200))
- {
- // Reset everything
- logger(null, FLV_LogLevel.DEBUG, String.Format("msec_read error (res {0} wrapCounter {1})", res, delayMicrophone.WrapCounter));
- ulong getSamp = (ulong)((double)waveIn.GetPosition() / (double)nBytesPerSample);
- //ulong getSamp = (ulong) ((waveIn.BufferMilliseconds - 10) * nSamplePerMs);
- delayMicrophone.ReadSamples = getSamp;
- delayMicrophone.OldReadSamples = delayMicrophone.ReadSamples;
- delayMicrophone.OldRecSamples = getSamp;
- // Guess a decent value
- res = 20;
- }
- delayMicrophone.WrapCounter = 0;
- logger(null, FLV_LogLevel.DEBUG, String.Format("[AEC]GetPublishBufferDelay(2) delayInbuffer({0}) BuiltIn({1}) NAudio({2}) wrapCounter({3})", res + delayNAudio, res, delayNAudio, delayMicrophone.WrapCounter));
- return res;
- }
- private long GetPlayBufferDelay(long bufferLength)
- {
- if (waveOut == null || waveStream == null) return 0;
- ulong writtenSamples = delaySpeaker.WrittenSamples;
- int nBytesPerSample = (int)Math.Round(((double)waveOut.OutputWaveFormat.BitsPerSample / 8.0));
- long nBytesPerMs = (long)Math.Round(((double)nBytesPerSample * (double)waveOut.OutputWaveFormat.SampleRate) / 1000.0);
- int nSamplePerMs = (int)Math.Round(waveOut.OutputWaveFormat.SampleRate / 1000.0);
- int addedLatency = waveOut.DesiredLatency;
- if (delaySpeaker.IsFirstFrame)
- {
- delaySpeaker.SampleFirstPos = (ulong)((double)waveOut.GetPosition() / (double)nBytesPerSample);
- delaySpeaker.IsFirstFrame = false;
- }
- ulong playedSamples = (ulong)((double)waveOut.GetPosition() / (double)nBytesPerSample);
- playedSamples -= delaySpeaker.SampleFirstPos; // remove the offset
- if (delaySpeaker.WrittenSamples < playedSamples)
- // we got a problem here, we can't have played more sample than we writted.
- {
- delaySpeaker.WrittenSamples = playedSamples;
- delaySpeaker.OldWrittenSamples = playedSamples;
- writtenSamples = playedSamples;
- logger(null, FLV_LogLevel.DEBUG,
- String.Format("[AEC]============================================= Resync"));
- }
- long delayMsInBuffer = (long)(((double)((long)delaySpeaker.WrittenSamples - (long)playedSamples) / (double)nSamplePerMs)); // calc the time hardware buffer
- long playedDifference = ((long)delaySpeaker.OldPlayedSamples - (long)playedSamples);
- int i = 0;
- if (playedDifference > 64000)
- {
- // If the sound cards number-of-played-out-samples variable wraps around before
- // written_sampels wraps around this needs to be adjusted. This can happen on
- // sound cards that uses less than 32 bits to keep track of number of played out
- // sampels. To avoid being fooled by sound cards that sometimes produces false
- // output we compare old value minus the new value with a large value. This is
- // neccessary because some SC:s produce an output like 153, 198, 175, 230 which
- // would trigger the wrap-around function if we didn't compare with a large value.
- // The value 64000 is chosen because 2^16=65536 so we allow wrap around at 16 bits.
- i = 31;
- while (delaySpeaker.OldPlayedSamples <= (ulong)Math.Pow(2, i) && (i > 14))
- {
- i--;
- }
- if ((i < 31) && (i > 14))
- {
- // Avoid adjusting when there is 32-bit wrap-around since that is
- // something neccessary.
- //
- logger(null, FLV_LogLevel.DEBUG, String.Format("msecleft() => wrap around occured: {0} bits used by sound card)", (i + 1)));
- delaySpeaker.WrittenSamples = delaySpeaker.WrittenSamples - (ulong)(Math.Pow(2, i + 1));
- writtenSamples = delaySpeaker.WrittenSamples;
- delayMsInBuffer = (int)(((double)((long)writtenSamples - (long)playedSamples) / (double)nSamplePerMs));
- }
- }
- else if ((delaySpeaker.WrittenSamples > Math.Pow(2, 31)) && ((long)writtenSamples < 96000))
- {
- // Wrap around as expected after having used all 32 bits. (But we still
- // test if the wrap around happened earlier which it should not)
- i = 31;
- while (delaySpeaker.OldWrittenSamples <= (ulong)Math.Pow(2, i))
- {
- i--;
- }
- logger(null, FLV_LogLevel.DEBUG, " msecleft() (wrap around occured after having used all 32 bits)");
- delaySpeaker.OldWrittenSamples = writtenSamples;
- delaySpeaker.OldPlayedSamples = playedSamples;
- delayMsInBuffer = (int)((double)(writtenSamples + Math.Pow(2, i + 1) - playedSamples) / (double)nSamplePerMs);
- }
- else if ((writtenSamples < (ulong)96000) && (playedSamples > Math.Pow(2, 31)))
- {
- // Wrap around has, as expected, happened for written_sampels before
- // playedSampels so we have to adjust for this until also playedSampels
- // has had wrap around.
- logger(null, FLV_LogLevel.DEBUG, " msecleft() (wrap around occured: correction of output is done)");
- delaySpeaker.OldWrittenSamples = writtenSamples;
- delaySpeaker.OldPlayedSamples = playedSamples;
- delayMsInBuffer = (int)((double)((long)writtenSamples + Math.Pow(2, 32) - (long)playedSamples) / (double)nSamplePerMs);
- }
- delaySpeaker.OldWrittenSamples = writtenSamples;
- delaySpeaker.OldPlayedSamples = playedSamples;
- //delayMsInBuffer += (long)((double)bufferLength / (double)nBytesPerMs); // add the actual ms
- long diff, y;
- long time = delaySpeaker.SpeakerStopwatch.ElapsedMilliseconds;
- delaySpeaker.SpeakerStopwatch.Reset();
- delaySpeaker.SpeakerStopwatch.Start();
- if ((delayMsInBuffer < 20) || (time - delaySpeaker.DelayControlPrevTime > 40))
- {
- delaySpeaker.DelayControlPenaltyCounter = 100;
- }
- if ((playedSamples != 0))
- {
- y = (long)playedSamples / 48 - time;
- if ((delaySpeaker.DelayControlYPrev != 0) && (delaySpeaker.DelayControlPenaltyCounter == 0))
- {
- diff = y - delaySpeaker.DelayControlYPrev;
- delaySpeaker.DelayControlDiffMean = (990 * delaySpeaker.DelayControlDiffMean) / 1000 + 10 * diff;
- }
- delaySpeaker.DelayControlYPrev = y;
- }
- if (delaySpeaker.DelayControlPenaltyCounter > 0)
- {
- delaySpeaker.DelayControlPenaltyCounter--;
- }
- if (delaySpeaker.DelayControlDiffMean < -200)
- {
- // Always reset the filter
- delaySpeaker.DelayControlDiffMean = 0;
- // Problem is detected. Switch delay method and set min buffer to 80.
- // Reset the filter and keep monitoring the filter output.
- // If issue is detected a second time, increase min buffer to 100.
- // If that does not help, we must modify this scheme further.
- UseDelayHeader++;
- if (UseDelayHeader == 1)
- {
- delaySpeaker.MinPlayBufDelay = 80;
- logger(null, FLV_LogLevel.DEBUG, String.Format("Modification #1: _useHeader = {0}, _minPlayBufDelay = {1}", UseDelayHeader, delaySpeaker.MinPlayBufDelay));
- }
- else if (UseDelayHeader == 2)
- {
- delaySpeaker.MinPlayBufDelay = 100; // add some more safety
- logger(null, FLV_LogLevel.DEBUG, String.Format("Modification #2: _useHeader = {0}, _minPlayBufDelay = {1}", UseDelayHeader, delaySpeaker.MinPlayBufDelay));
- }
- else
- {
- // This state should not be entered... (HA)
- logger(null, FLV_LogLevel.DEBUG, "further actions are required!");
- }
- logger(null, FLV_LogLevel.DEBUG, "kPlayoutWarning message posted: switching to alternative playout delay method");
- }
- delaySpeaker.DelayControlPrevTime = time;
- delaySpeaker.DelayControlPrevPlay = playedSamples;
- // Try a very rough method of looking at how many buffers are still playing
- //int ms_Header = (int)waveOut.HardwareBufferedDuration.TotalMilliseconds;
- int ms_Header = (int)waveStream.BufferedDuration.TotalMilliseconds;
- // If this is true we have had a problem with the playout
- if (UseDelayHeader > 0)
- {
- logger(null, FLV_LogLevel.DEBUG, String.Format("[AEC]GetPlayBufferDelay(0) delayInbuffer({0}) msHeader({1}) useHeader({2})", delayMsInBuffer, ms_Header, UseDelayHeader));
- return (ms_Header + addedLatency /*+ (int)waveStream.BufferedDuration.TotalMilliseconds*/);
- }
- if (ms_Header < delayMsInBuffer)
- {
- ms_Header -= 6; // Round off as we only have 10ms resolution + Header info is usually slightly delayed compared to GetPosition
- if (ms_Header < 0)
- ms_Header = 0;
- logger(null, FLV_LogLevel.DEBUG, String.Format("[AEC]GetPlayBufferDelay(1) delayInbuffer({0}) msHeader({1}) useHeader({2})", delayMsInBuffer, ms_Header, UseDelayHeader));
- return (ms_Header + addedLatency /*+ (int)waveStream.BufferedDuration.TotalMilliseconds*/);
- }
- else
- {
- logger(null, FLV_LogLevel.DEBUG, String.Format("[AEC]GetPlayBufferDelay(2) delayInbuffer({0}) msHeader({1}) useHeader({2})", delayMsInBuffer, ms_Header, UseDelayHeader));
- return (delayMsInBuffer + addedLatency /*+ (int)waveStream.BufferedDuration.TotalMilliseconds*/);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement