⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 265280 in webkit


Ignore:
Timestamp:
Aug 5, 2020, 1:11:50 AM (6 years ago)
Author:
youenn@apple.com
Message:

Update AudioSampleDataSource offset computation
https://bugs.webkit.org/show_bug.cgi?id=215127
<rdar://problem/65938265>

Reviewed by Eric Carlson.

As per logs, it sometimes happens that the offset is so big that the timestamp is below the start of the window.
In that case, our logic is not able to catch up and reduce the offset.
To handle this, we special case if the timestamp is below the start frame and do as if we were starting from scratch.
Otherwise, we continue our logic to fine tune the offset by slowly making it bigger to not hit the end of the window but still be close to it.
Updated logging to help further debugging this issue if needed.

  • platform/audio/mac/AudioSampleDataSource.h:
  • platform/audio/mac/AudioSampleDataSource.mm:

(WebCore::AudioSampleDataSource::pushSamplesInternal):
(WebCore::computeOffsetDelay):
(WebCore::AudioSampleDataSource::pullSamplesInternal):
(WebCore::AudioSampleDataSource::pullAvalaibleSamplesAsChunks):

  • platform/mediastream/mac/RealtimeIncomingAudioSourceCocoa.cpp:

(WebCore::RealtimeIncomingAudioSourceCocoa::OnData):

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r265278 r265280  
     12020-08-05  Youenn Fablet  <youenn@apple.com>
     2
     3        Update AudioSampleDataSource offset computation
     4        https://bugs.webkit.org/show_bug.cgi?id=215127
     5        <rdar://problem/65938265>
     6
     7        Reviewed by Eric Carlson.
     8
     9        As per logs, it sometimes happens that the offset is so big that the timestamp is below the start of the window.
     10        In that case, our logic is not able to catch up and reduce the offset.
     11        To handle this, we special case if the timestamp is below the start frame and do as if we were starting from scratch.
     12        Otherwise, we continue our logic to fine tune the offset by slowly making it bigger to not hit the end of the window but still be close to it.
     13        Updated logging to help further debugging this issue if needed.
     14
     15        * platform/audio/mac/AudioSampleDataSource.h:
     16        * platform/audio/mac/AudioSampleDataSource.mm:
     17        (WebCore::AudioSampleDataSource::pushSamplesInternal):
     18        (WebCore::computeOffsetDelay):
     19        (WebCore::AudioSampleDataSource::pullSamplesInternal):
     20        (WebCore::AudioSampleDataSource::pullAvalaibleSamplesAsChunks):
     21        * platform/mediastream/mac/RealtimeIncomingAudioSourceCocoa.cpp:
     22        (WebCore::RealtimeIncomingAudioSourceCocoa::OnData):
     23
    1242020-08-05  Eric Liang  <ericliang@apple.com>
    225
  • trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.h

    r265244 r265280  
    114114    float m_volume { 1.0 };
    115115    bool m_muted { false };
    116     bool m_transitioningFromPaused { true };
     116    bool m_shouldComputeOutputSampleOffset { true };
    117117
    118118#if !RELEASE_LOG_DISABLED
  • trunk/Source/WebCore/platform/audio/mac/AudioSampleDataSource.mm

    r265244 r265280  
    164164    if (m_inputSampleOffset == MediaTime::invalidTime()) {
    165165        m_inputSampleOffset = MediaTime(1 - sampleTime.timeValue(), sampleTime.timeScale());
    166         dispatch_async(dispatch_get_main_queue(), [inputSampleOffset = m_inputSampleOffset.timeValue(), maximumSampleCount = m_maximumSampleCount, this, protectedThis = makeRefPtr(*this)] {
    167             ERROR_LOG("pushSamples: input sample offset is ", inputSampleOffset, ", maximumSampleCount = ", maximumSampleCount);
     166        dispatch_async(dispatch_get_main_queue(), [logIdentifier = LOGIDENTIFIER, inputSampleOffset = m_inputSampleOffset.timeValue(), maximumSampleCount = m_maximumSampleCount, this, protectedThis = makeRefPtr(*this)] {
     167            ALWAYS_LOG(logIdentifier, "input sample offset is ", inputSampleOffset, ", maximumSampleCount is ", maximumSampleCount);
    168168        });
    169169    }
     
    178178    m_ringBuffer->store(sampleBufferList, sampleCount, sampleTime.timeValue());
    179179    m_lastPushedSampleCount = sampleCount;
    180 
    181 #if !LOG_DISABLED
    182     uint64_t startFrame2 = 0;
    183     uint64_t endFrame2 = 0;
    184     m_ringBuffer->getCurrentFrameBounds(startFrame2, endFrame2);
    185     dispatch_async(dispatch_get_main_queue(), [sampleCount, sampleTime, presentationTime, absoluteTime = mach_absolute_time(), startFrame1, endFrame1, startFrame2, endFrame2] {
    186         LOG(MediaCaptureSamples, "@@ pushSamples: added %ld samples for time = %s (was %s), mach time = %lld", sampleCount, toString(sampleTime).utf8().data(), toString(presentationTime).utf8().data(), absoluteTime);
    187         LOG(MediaCaptureSamples, "@@ pushSamples: buffered range was [%lld .. %lld], is [%lld .. %lld]", startFrame1, endFrame1, startFrame2, endFrame2);
    188     });
    189 #endif
    190180}
    191181
     
    205195}
    206196
     197static inline int64_t computeOffsetDelay(double sampleRate, uint64_t lastPushedSampleCount)
     198{
     199    const double twentyMS = .02;
     200    const double tenMS = .01;
     201    const double fiveMS = .005;
     202
     203    if (lastPushedSampleCount > sampleRate * twentyMS)
     204        return sampleRate * twentyMS;
     205    if (lastPushedSampleCount > sampleRate * tenMS)
     206        return sampleRate * tenMS;
     207    if (lastPushedSampleCount > sampleRate * fiveMS)
     208        return sampleRate * fiveMS;
     209    return 0;
     210}
     211
    207212bool AudioSampleDataSource::pullSamplesInternal(AudioBufferList& buffer, size_t& sampleCount, uint64_t timeStamp, double /*hostTime*/, PullMode mode)
    208213{
     
    226231    m_ringBuffer->getCurrentFrameBounds(startFrame, endFrame);
    227232
    228     if (m_transitioningFromPaused) {
     233    if (m_shouldComputeOutputSampleOffset) {
    229234        uint64_t buffered = endFrame - startFrame;
    230235        if (buffered < sampleCount * 2) {
     
    234239        }
    235240
    236         const double twentyMS = .02;
    237         const double tenMS = .01;
    238         const double fiveMS = .005;
    239         double sampleRate = m_outputDescription->sampleRate();
     241        m_shouldComputeOutputSampleOffset = false;
     242
    240243        m_outputSampleOffset = (endFrame - sampleCount) - timeStamp;
    241         if (m_lastPushedSampleCount > sampleRate * twentyMS)
    242             m_outputSampleOffset -= sampleRate * twentyMS;
    243         else if (m_lastPushedSampleCount > sampleRate * tenMS)
    244             m_outputSampleOffset -= sampleRate * tenMS;
    245         else if (m_lastPushedSampleCount > sampleRate * fiveMS)
    246             m_outputSampleOffset -= sampleRate * fiveMS;
    247 
    248         m_transitioningFromPaused = false;
     244        m_outputSampleOffset -= computeOffsetDelay(m_outputDescription->sampleRate(), m_lastPushedSampleCount);
     245        dispatch_async(dispatch_get_main_queue(), [logIdentifier = LOGIDENTIFIER, outputSampleOffset = m_outputSampleOffset, this, protectedThis = makeRefPtr(*this)] {
     246            ALWAYS_LOG(logIdentifier, "setting new offset to ", outputSampleOffset);
     247        });
    249248    }
    250249
    251250    timeStamp += m_outputSampleOffset;
    252251
    253 #if !LOG_DISABLED
    254     dispatch_async(dispatch_get_main_queue(), [sampleCount, timeStamp, sampleOffset = m_outputSampleOffset] {
    255         LOG(MediaCaptureSamples, "** pullSamplesInternal: asking for %ld samples at time = %lld (was %lld)", sampleCount, timeStamp, timeStamp - sampleOffset);
    256     });
    257 #endif
    258 
    259     uint64_t framesAvailable = sampleCount;
    260252    if (timeStamp < startFrame || timeStamp + sampleCount > endFrame) {
    261         if (timeStamp + sampleCount < startFrame || timeStamp >= endFrame)
    262             framesAvailable = 0;
    263         else if (timeStamp < startFrame)
    264             framesAvailable = timeStamp + sampleCount - startFrame;
    265         else
    266             framesAvailable = timeStamp + sampleCount - endFrame;
    267 
    268 #if !RELEASE_LOG_DISABLED
    269         dispatch_async(dispatch_get_main_queue(), [timeStamp, startFrame, endFrame, framesAvailable, sampleCount, this, protectedThis = makeRefPtr(*this)] {
    270             ALWAYS_LOG("sample ", timeStamp, " is not completely in range [", startFrame, " .. ", endFrame, "], returning ", framesAvailable, " frames");
    271             if (framesAvailable < sampleCount)
    272                 ERROR_LOG("not enough data available, returning zeroes");
     253        dispatch_async(dispatch_get_main_queue(), [logIdentifier = LOGIDENTIFIER, timeStamp, startFrame, endFrame, sampleCount, outputSampleOffset = m_outputSampleOffset, this, protectedThis = makeRefPtr(*this)] {
     254            ERROR_LOG(logIdentifier, "not enough data, sample ", timeStamp, " with offset ", outputSampleOffset, ", trying to get ", sampleCount, " samples, but not completely in range [", startFrame, " .. ", endFrame, "]");
    273255        });
    274 #endif
    275 
    276         if (framesAvailable < sampleCount) {
     256
     257        if (timeStamp < startFrame || timeStamp >= endFrame) {
     258            // We are out of the window, let's restart the offset computation.
     259            m_shouldComputeOutputSampleOffset = true;
     260        } else {
     261            // We are too close from endFrame, let's back up a little bit.
     262            uint64_t framesAvailable = endFrame - timeStamp;
    277263            m_outputSampleOffset -= sampleCount - framesAvailable;
    278             AudioSampleBufferList::zeroABL(buffer, byteCount);
    279             return false;
     264            dispatch_async(dispatch_get_main_queue(), [logIdentifier = LOGIDENTIFIER, outputSampleOffset = m_outputSampleOffset, this, protectedThis = makeRefPtr(*this)] {
     265                ALWAYS_LOG(logIdentifier, "updating offset to ", outputSampleOffset);
     266            });
    280267        }
     268        AudioSampleBufferList::zeroABL(buffer, byteCount);
     269        return false;
    281270    }
    282271
     
    316305    uint64_t endFrame = 0;
    317306    m_ringBuffer->getCurrentFrameBounds(startFrame, endFrame);
    318     if (m_transitioningFromPaused) {
     307    if (m_shouldComputeOutputSampleOffset) {
    319308        m_outputSampleOffset = timeStamp + (endFrame - sampleCountPerChunk);
    320         m_transitioningFromPaused = false;
     309        m_shouldComputeOutputSampleOffset = false;
    321310    }
    322311
  • trunk/Source/WebCore/platform/mediastream/mac/RealtimeIncomingAudioSourceCocoa.cpp

    r259632 r265280  
    7676#endif
    7777
    78     CMTime startTime = CMTimeMake(m_numberOfFrames, sampleRate);
    79     auto mediaTime = PAL::toMediaTime(startTime);
    80     m_numberOfFrames += numberOfFrames;
    81 
    8278    if (!m_audioBufferList || m_sampleRate != sampleRate || m_numberOfChannels != numberOfChannels) {
    8379        callOnMainThread([identifier = LOGIDENTIFIER, this, protectedThis = makeRef(*this), sampleRate, numberOfChannels] {
     
    8985        m_streamDescription = streamDescription(sampleRate, numberOfChannels);
    9086        m_audioBufferList = makeUnique<WebAudioBufferList>(m_streamDescription);
     87        if (m_sampleRate && m_numberOfFrames)
     88            m_numberOfFrames = m_numberOfFrames * sampleRate / m_sampleRate;
     89        else
     90            m_numberOfFrames = 0;
    9191    }
     92
     93    CMTime startTime = CMTimeMake(m_numberOfFrames, sampleRate);
     94    auto mediaTime = PAL::toMediaTime(startTime);
     95    m_numberOfFrames += numberOfFrames;
    9296
    9397    auto& bufferList = *m_audioBufferList->buffer(0);
Note: See TracChangeset for help on using the changeset viewer.