void AudioBufferSourceHandler::handleStoppableSourceNode()
{
    // If the source node is not looping, and we have a buffer, we can determine when the source
    // would stop playing.  This is intended to handle the (uncommon) scenario where start() has
    // been called but is never connected to the destination (directly or indirectly).  By stopping
    // the node, the node can be collected.  Otherwise, the node will never get collected, leaking
    // memory.
    //
    // If looping was ever done (m_didSetLooping = true), give up.  We can't easily determine how
    // long we looped so we don't know the actual duration thus far, so don't try to do anything
    // fancy.
    if (!m_didSetLooping && buffer() && isPlayingOrScheduled() && m_minPlaybackRate > 0) {
        // Adjust the duration to include the playback rate. Only need to account for rate < 1
        // which makes the sound last longer.  For rate >= 1, the source stops sooner, but that's
        // ok.
        double actualDuration = buffer()->duration() / m_minPlaybackRate;

        double stopTime = m_startTime + actualDuration;

        // See crbug.com/478301. If a source node is started via start(), the source may not start
        // at that time but one quantum (128 frames) later.  But we compute the stop time based on
        // the start time and the duration, so we end up stopping one quantum early.  Thus, add a
        // little extra time; we just need to stop the source sometime after it should have stopped
        // if it hadn't already.  We don't need to be super precise on when to stop.
        double extraStopTime = kExtraStopFrames / static_cast<double>(context()->sampleRate());

        stopTime += extraStopTime;
        if (context()->currentTime() > stopTime) {
            // The context time has passed the time when the source nodes should have stopped
            // playing. Stop the node now and deref it. (But don't run the onEnded event because the
            // source never actually played.)
            finishWithoutOnEnded();
        }
    }
}
bool AudioBufferSourceNode::propagatesSilence() const
{
    return !isPlayingOrScheduled() || hasFinished() || !m_buffer;
}