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

Changeset 267443 in webkit


Ignore:
Timestamp:
Sep 22, 2020, 3:52:42 PM (6 years ago)
Author:
Chris Dumez
Message:

Merge AudioBufferSourceNode loop fixes from Blink
https://bugs.webkit.org/show_bug.cgi?id=216849

Reviewed by Eric Carlson.

Source/WebCore:

Merge AudioBufferSourceNode loop fixes from Blink, the following one in particular:

This allows us to pass all the checks in:
webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html.

No new tests, rebaselined existing test.

  • Modules/webaudio/AudioBufferSourceNode.cpp:

(WebCore::AudioBufferSourceNode::renderFromBuffer):
(WebCore::AudioBufferSourceNode::adjustGrainParameters):
Merge loop fixes from Blink.

  • Modules/webaudio/AudioScheduledSourceNode.cpp:

(WebCore::AudioScheduledSourceNode::stopLater):
Stop throwing when m_endTime is already set. Our behavior did not match
Chrome and Firefox here. This was causing some existing tests to start
failing now that providing a grain duration when calling start() would
set m_endTime if loop() returns true.

LayoutTests:

  • webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive-expected.txt:

Rebaseline test that is now passing.

  • webaudio/Oscillator/oscillator-basic-expected.txt:
  • webaudio/dom-exceptions-expected.txt:

Rebaseline tests because the exception message was improved.

  • webaudio/audiobuffersource-exception-expected.txt:
  • webaudio/audiobuffersource-exception.html:

Stop expecting an exception to be thrown when AudioBufferSourceNode.stop() gets called
more than once. I have verified that Chrome and Firefox do not throw in this case.

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r267442 r267443  
     12020-09-22  Chris Dumez  <cdumez@apple.com>
     2
     3        Merge AudioBufferSourceNode loop fixes from Blink
     4        https://bugs.webkit.org/show_bug.cgi?id=216849
     5
     6        Reviewed by Eric Carlson.
     7
     8        * webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive-expected.txt:
     9        Rebaseline test that is now passing.
     10
     11        * webaudio/Oscillator/oscillator-basic-expected.txt:
     12        * webaudio/dom-exceptions-expected.txt:
     13        Rebaseline tests because the exception message was improved.
     14
     15        * webaudio/audiobuffersource-exception-expected.txt:
     16        * webaudio/audiobuffersource-exception.html:
     17        Stop expecting an exception to be thrown when AudioBufferSourceNode.stop() gets called
     18        more than once. I have verified that Chrome and Firefox do not throw in this case.
     19
    1202020-09-22  Hector Lopez  <hector_i_lopez@apple.com>
    221
  • trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic-expected.txt

    r265256 r267443  
    77PASS   start(Infinity) threw TypeError: "The provided value is non-finite".
    88PASS   start(-Infinity) threw TypeError: "The provided value is non-finite".
    9 PASS   Calling stop() before start() threw InvalidStateError: "The object is in an invalid state.".
     9PASS   Calling stop() before start() threw InvalidStateError: "cannot call stop without calling start first.".
    1010PASS   start(-1) threw RangeError: "when value should be positive".
    1111PASS   start(0,-1) threw RangeError: "offset value should be positive".
  • trunk/LayoutTests/imported/w3c/web-platform-tests/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic-expected.txt

    r265689 r267443  
    3535PASS   start(Infinity) threw TypeError: "The provided value is non-finite".
    3636PASS   start(-Infinity) threw TypeError: "The provided value is non-finite".
    37 PASS   Calling stop() before start() threw InvalidStateError: "The object is in an invalid state.".
     37PASS   Calling stop() before start() threw InvalidStateError: "cannot call stop without calling start first.".
    3838PASS   start(-1) threw RangeError: "when value should be positive".
    3939PASS   Calling start() twice threw InvalidStateError: "The object is in an invalid state.".
  • trunk/LayoutTests/webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive-expected.txt

    r267245 r267443  
    2121PASS   Case 7: loop from 4 -> 6 with playbackRate of 1.5 is identical to the array [0,1.5,3,4.5,4,5.5,5,4.5,4,5.5,5,4.5,4,5.5,5,4.5...].
    2222PASS   Case 7: loop from 4 -> 6 with playbackRate of 1.5: tail contains only the constant 0.
    23 FAIL X Case 8: loop from 2 -> 5 with offset 6 expected to be equal to the array [2,3,4,2,3,4,2,3,4,2,3,4,2,3,4,2...] but differs in 16 places:
    24         Index   Actual                  Expected
    25         [0]     3.0000000000000000e+0   2.0000000000000000e+0
    26         [1]     4.0000000000000000e+0   3.0000000000000000e+0
    27         [2]     2.0000000000000000e+0   4.0000000000000000e+0
    28         [3]     3.0000000000000000e+0   2.0000000000000000e+0
    29         ...and 12 more errors. assert_true: expected true got false
     23PASS   Case 8: loop from 2 -> 5 with offset 6 is identical to the array [2,3,4,2,3,4,2,3,4,2,3,4,2,3,4,2...].
    3024PASS   Case 8: loop from 2 -> 5 with offset 6: tail contains only the constant 0.
    3125PASS   Case 9: loop from 3 -> 6 with offset 1 is identical to the array [1,2,3,4,5,3,4,5,3,4,5,3,4,5,3,4...].
     
    4337PASS   Case 15: illegal loop: loopEndFrame > bufferLength is identical to the array [0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7...].
    4438PASS   Case 15: illegal loop: loopEndFrame > bufferLength: tail contains only the constant 0.
    45 FAIL X Case 16: loop from 3 -> 6 with offset 1 for 20 frames expected to be equal to the array [1,2,3,4,5,3,4,5,3,4,5,3,4,5,3,4...] but differs in 10 places:
    46         Index   Actual                  Expected
    47         [20]    3.0000000000000000e+0   0.0000000000000000e+0
    48         [21]    4.0000000000000000e+0   0.0000000000000000e+0
    49         [22]    5.0000000000000000e+0   0.0000000000000000e+0
    50         [23]    3.0000000000000000e+0   0.0000000000000000e+0
    51         ...and 6 more errors. assert_true: expected true got false
    52 FAIL X Case 16: loop from 3 -> 6 with offset 1 for 20 frames: tail: Expected 0 for all values but found 2 unexpected values:
    53         Index   Actual
    54         [0]     4
    55         [1]     5 assert_true: expected true got false
    56 FAIL X Case 17: loop from 3 -> 8 with offset 1 for 3 frames expected to be equal to the array [1,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0...] but differs in 30 places:
    57         Index   Actual                  Expected
    58         [0]     4.0000000000000000e+0   1.0000000000000000e+0
    59         [1]     6.0000000000000000e+0   2.0000000000000000e+0
    60         [2]     8.0000000000000000e+0   3.0000000000000000e+0
    61         [3]     6.0000000000000000e+0   0.0000000000000000e+0
    62         ...and 26 more errors. assert_true: expected true got false
    63 FAIL X Case 17: loop from 3 -> 8 with offset 1 for 3 frames: tail: Expected 0 for all values but found 2 unexpected values:
    64         Index   Actual
    65         [0]     6
    66         [1]     7 assert_true: expected true got false
    67 FAIL X Case 18: loop from 3 -> 8 with offset 7 for 3 frames expected to be equal to the array [7,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0...] but differs in 30 places:
    68         Index   Actual                  Expected
    69         [0]     1.5000000000000000e+1   7.0000000000000000e+0
    70         [1]     9.0000000000000000e+0   3.0000000000000000e+0
    71         [2]     1.1000000000000000e+1   4.0000000000000000e+0
    72         [3]     1.3000000000000000e+1   0.0000000000000000e+0
    73         ...and 26 more errors. assert_true: expected true got false
    74 FAIL X Case 18: loop from 3 -> 8 with offset 7 for 3 frames: tail: Expected 0 for all values but found 2 unexpected values:
    75         Index   Actual
    76         [0]     15
    77         [1]     9 assert_true: expected true got false
    78 FAIL < [AudioBufferSource looping test] 7 out of 39 assertions were failed. assert_true: expected true got false
    79 FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed. assert_true: expected true got false
     39PASS   Case 16: loop from 3 -> 6 with offset 1 for 20 frames is identical to the array [1,2,3,4,5,3,4,5,3,4,5,3,4,5,3,4...].
     40PASS   Case 16: loop from 3 -> 6 with offset 1 for 20 frames: tail contains only the constant 0.
     41PASS   Case 17: loop from 3 -> 8 with offset 1 for 3 frames is identical to the array [1,2,3,0,0,0,0,0,0,0,0,0,0,0,0,0...].
     42PASS   Case 17: loop from 3 -> 8 with offset 1 for 3 frames: tail contains only the constant 0.
     43PASS   Case 18: loop from 3 -> 8 with offset 7 for 3 frames is identical to the array [7,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0...].
     44PASS   Case 18: loop from 3 -> 8 with offset 7 for 3 frames: tail contains only the constant 0.
     45PASS < [AudioBufferSource looping test] All assertions passed. (total 39 assertions)
     46PASS # AUDIT TASK RUNNER FINISHED: 1 tasks ran successfully.
    8047
  • trunk/LayoutTests/webaudio/Oscillator/oscillator-basic-expected.txt

    r267144 r267443  
    1919PASS   start(Infinity) threw TypeError: "The provided value is non-finite".
    2020PASS   start(-Infinity) threw TypeError: "The provided value is non-finite".
    21 PASS   Calling stop() before start() threw InvalidStateError: "The object is in an invalid state.".
     21PASS   Calling stop() before start() threw InvalidStateError: "cannot call stop without calling start first.".
    2222PASS   start(-1) threw RangeError: "when value should be positive".
    2323PASS   Calling start() twice threw InvalidStateError: "The object is in an invalid state.".
  • trunk/LayoutTests/webaudio/audiobuffersource-exception-expected.txt

    r265256 r267443  
    33On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
    44
    5 PASS bufferSource.stop(0) threw exception InvalidStateError: The object is in an invalid state..
     5PASS bufferSource.stop(0) threw exception InvalidStateError: cannot call stop without calling start first..
    66PASS bufferSource.start(0) threw exception InvalidStateError: Cannot call start more than once..
    7 PASS bufferSource.stop(0) threw exception InvalidStateError: The object is in an invalid state..
     7PASS InvalidStateError did not throw exception.
    88PASS successfullyParsed is true
    99
  • trunk/LayoutTests/webaudio/audiobuffersource-exception.html

    r219663 r267443  
    2323    var sampleRate = 44100.0;
    2424    var numberOfFrames = 32;
    25     var context = new webkitOfflineAudioContext(1, numberOfFrames, sampleRate);
     25    var context = new OfflineAudioContext(1, numberOfFrames, sampleRate);
    2626    bufferSource = context.createBufferSource();
    2727    bufferSource.buffer = createTestBuffer(context, numberOfFrames);
     
    3636    bufferSource.stop(0);
    3737
    38     // 'stop' should be called only once.
    39     shouldThrowErrorName("bufferSource.stop(0)", "InvalidStateError");
     38    shouldNotThrow("bufferSource.stop(0)", "InvalidStateError");
    4039
    4140    context.oncomplete = finishJSTest;
  • trunk/LayoutTests/webaudio/dom-exceptions-expected.txt

    r267376 r267443  
    190190PASS   source5 = context.createBufferSource() did not throw an exception.
    191191PASS   source5.buffer = buffer did not throw an exception.
    192 PASS   source5.stop() threw InvalidStateError: "The object is in an invalid state.".
     192PASS   source5.stop() threw InvalidStateError: "cannot call stop without calling start first.".
    193193PASS   source6 = context.createBufferSource() did not throw an exception.
    194194PASS   source6.buffer = buffer did not throw an exception.
     
    213213PASS   source8.stop() did not throw an exception.
    214214PASS   osc = context.createOscillator() did not throw an exception.
    215 PASS   osc.stop() threw InvalidStateError: "The object is in an invalid state.".
     215PASS   osc.stop() threw InvalidStateError: "cannot call stop without calling start first.".
    216216PASS   osc1 = context.createOscillator() did not throw an exception.
    217217PASS   osc1.start() did not throw an exception.
  • trunk/Source/WebCore/ChangeLog

    r267439 r267443  
     12020-09-22  Chris Dumez  <cdumez@apple.com>
     2
     3        Merge AudioBufferSourceNode loop fixes from Blink
     4        https://bugs.webkit.org/show_bug.cgi?id=216849
     5
     6        Reviewed by Eric Carlson.
     7
     8        Merge AudioBufferSourceNode loop fixes from Blink, the following one in particular:
     9        - https://codereview.chromium.org/723823002
     10
     11        This allows us to pass all the checks in:
     12        webaudio/AudioBufferSource/audiobuffersource-loop-comprehensive.html.
     13
     14        No new tests, rebaselined existing test.
     15
     16        * Modules/webaudio/AudioBufferSourceNode.cpp:
     17        (WebCore::AudioBufferSourceNode::renderFromBuffer):
     18        (WebCore::AudioBufferSourceNode::adjustGrainParameters):
     19        Merge loop fixes from Blink.
     20
     21        * Modules/webaudio/AudioScheduledSourceNode.cpp:
     22        (WebCore::AudioScheduledSourceNode::stopLater):
     23        Stop throwing when m_endTime is already set. Our behavior did not match
     24        Chrome and Firefox here. This was causing some existing tests to start
     25        failing now that providing a grain duration when calling start() would
     26        set m_endTime if loop() returns true.
     27
    1282020-09-22  Sihui Liu  <sihui_liu@apple.com>
    229
  • trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp

    r267386 r267443  
    243243    }
    244244
     245    // If we're looping and the offset (virtualReadIndex) is past the end of the loop, wrap back to the
     246    // beginning of the loop. For other cases, nothing needs to be done.
     247    if (loop() && m_virtualReadIndex >= virtualMaxFrame) {
     248        m_virtualReadIndex = (m_loopStart < 0) ? 0 : (m_loopStart * buffer()->sampleRate());
     249        m_virtualReadIndex = std::min(m_virtualReadIndex, static_cast<double>(bufferLength - 1));
     250    }
     251
    245252    // Sanity check that our playback rate isn't larger than the loop size.
    246253    if (std::abs(pitchRate) > virtualDeltaFrames)
     
    517524    m_grainOffset = std::min(bufferDuration, m_grainOffset);
    518525
    519     double maxDuration = bufferDuration - m_grainOffset;
    520 
    521     if (m_wasGrainDurationGiven)
    522         m_grainDuration = std::min(m_grainDuration, maxDuration);
    523     else
    524         m_grainDuration = maxDuration;
     526    if (!m_wasGrainDurationGiven)
     527        m_grainDuration = bufferDuration - m_grainOffset;
     528
     529    if (m_wasGrainDurationGiven && loop()) {
     530        // We're looping a grain with a grain duration specified. Schedule the loop
     531        // to stop after grainDuration seconds after starting, possibly running the
     532        // loop multiple times if grainDuration is larger than the buffer duration.
     533        // The net effect is as if the user called stop(when + grainDuration).
     534        m_grainDuration = clampTo(m_grainDuration, 0.0, std::numeric_limits<double>::infinity());
     535        m_endTime = m_startTime + m_grainDuration;
     536    } else
     537        m_grainDuration = clampTo(m_grainDuration, 0.0,  bufferDuration - m_grainOffset);
    525538
    526539    // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
  • trunk/Source/WebCore/Modules/webaudio/AudioScheduledSourceNode.cpp

    r266835 r267443  
    175175    ALWAYS_LOG(LOGIDENTIFIER, when);
    176176
    177     if (m_playbackState == UNSCHEDULED_STATE || m_endTime != UnknownTime)
    178         return Exception { InvalidStateError };
     177    if (m_playbackState == UNSCHEDULED_STATE)
     178        return Exception { InvalidStateError, "cannot call stop without calling start first."_s };
    179179
    180180    if (!std::isfinite(when) || when < 0)
Note: See TracChangeset for help on using the changeset viewer.