Skip to content

Commit 08bfd3f

Browse files
committed
[GStreamer][WebAudio][Quirks] Fix initial WebAudio cut on Raspberry Pi
https://bugs.webkit.org/show_bug.cgi?id=285030 Reviewed by Philippe Normand. WebAudio playback eats up a portion of the start of a sound after a silence on Raspberry Pi when using OpenMAX. This is because the silence buffers are marked with the GAP flag by WebKitWebAudioSourceGStreamer and that causes them not to be rendered by the audio sink. This, in turn, causes OpenMAX (the platform media framework used on Raspbery Pi 32 bit) to cool down and when the first audible buffer arrives, it takes a fraction of a second to warm up again and play audio back. This patch avoids marking the buffers as GAP on these platforms, fixing the issue. Inserting non-gap buffers periodically (even with a frequency of one non-gap per every gap) is not enough to solve the problem, so the only alternative is to avoid gap buffers completely. * Source/WebCore/platform/SourcesGStreamer.txt: Added new GStreamerQuirkOpenMAX.cpp file. * Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp: (webKitWebAudioSrcRenderAndPushFrames): Resort to quirks to process the buffers (marking them as gap and drop there or not). Do it in-place if quirks are disabled. * Source/WebCore/platform/gstreamer/GStreamerQuirkOpenMAX.cpp: Added. (WebCore::GStreamerQuirkOpenMAX::GStreamerQuirkOpenMAX): Constructor. Initialize debug category. (WebCore::GStreamerQuirkOpenMAX::processWebAudioSilentBuffer const): Mark the buffers as no gap and no drop. * Source/WebCore/platform/gstreamer/GStreamerQuirkOpenMAX.h: Added. * Source/WebCore/platform/gstreamer/GStreamerQuirks.cpp: (WebCore::GStreamerQuirksManager::GStreamerQuirksManager): Initialize OpenMAX quirk backend. (WebCore::GStreamerQuirksManager::processWebAudioSilentBuffer const): Ask all backends to process the buffers. The backends will return true if they consider themselves as preferred, avoiding remaining backends after them to be queried. * Source/WebCore/platform/gstreamer/GStreamerQuirks.h: (WebCore::GStreamerQuirk::processWebAudioSilentBuffer const): Added default implementation that marks the buffers as gap and drop. Canonical link: https://commits.webkit.org/288713@main
1 parent 680d0af commit 08bfd3f

6 files changed

Lines changed: 128 additions & 3 deletions

File tree

Source/WebCore/platform/GStreamer.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ if (ENABLE_VIDEO OR ENABLE_WEB_AUDIO)
7474
platform/gstreamer/GStreamerQuirkBcmNexus.cpp
7575
platform/gstreamer/GStreamerQuirkBroadcom.cpp
7676
platform/gstreamer/GStreamerQuirkBroadcomBase.cpp
77+
platform/gstreamer/GStreamerQuirkOpenMAX.cpp
7778
platform/gstreamer/GStreamerQuirkRealtek.cpp
7879
platform/gstreamer/GStreamerQuirkRialto.cpp
7980
platform/gstreamer/GStreamerQuirkWesteros.cpp

Source/WebCore/platform/audio/gstreamer/WebKitWebAudioSourceGStreamer.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "AudioIOCallback.h"
2929
#include "AudioUtilities.h"
3030
#include "GStreamerCommon.h"
31+
#include "GStreamerQuirks.h"
3132
#include <gst/app/gstappsrc.h>
3233
#include <gst/audio/audio-info.h>
3334
#include <gst/pbutils/missing-plugins.h>
@@ -363,8 +364,15 @@ static void webKitWebAudioSrcRenderAndPushFrames(const GRefPtr<GstElement>& elem
363364
GST_BUFFER_TIMESTAMP(buffer.get()) = outputTimestamp.position.nanoseconds();
364365
GST_BUFFER_DURATION(buffer.get()) = duration;
365366

366-
if (priv->bus->isSilent())
367-
GST_BUFFER_FLAG_SET(buffer.get(), GST_BUFFER_FLAG_GAP);
367+
if (priv->bus->isSilent()) {
368+
auto& quirksManager = GStreamerQuirksManager::singleton();
369+
if (quirksManager.isEnabled())
370+
quirksManager.processWebAudioSilentBuffer(buffer.get());
371+
else {
372+
GST_BUFFER_FLAG_SET(buffer.get(), GST_BUFFER_FLAG_GAP);
373+
GST_BUFFER_FLAG_SET(buffer.get(), GST_BUFFER_FLAG_DROPPABLE);
374+
}
375+
}
368376

369377
// Leak the buffer ref, because gst_app_src_push_buffer steals it.
370378
GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(priv->source.get()), buffer.leakRef());
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2024 RDK Management
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
* THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#include "config.h"
27+
#include "GStreamerQuirkOpenMAX.h"
28+
29+
#if USE(GSTREAMER)
30+
31+
#include "GStreamerCommon.h"
32+
33+
namespace WebCore {
34+
35+
GST_DEBUG_CATEGORY_STATIC(webkit_openmax_quirks_debug);
36+
#define GST_CAT_DEFAULT webkit_openmax_quirks_debug
37+
38+
GStreamerQuirkOpenMAX::GStreamerQuirkOpenMAX()
39+
{
40+
GST_DEBUG_CATEGORY_INIT(webkit_openmax_quirks_debug, "webkitquirksopenmax", 0, "WebKit OpenMAX Quirks");
41+
}
42+
43+
bool GStreamerQuirkOpenMAX::processWebAudioSilentBuffer(GstBuffer* buffer) const
44+
{
45+
GST_TRACE("Force disabling GAP buffer flag");
46+
GST_BUFFER_FLAG_UNSET(buffer, GST_BUFFER_FLAG_GAP);
47+
GST_BUFFER_FLAG_UNSET(buffer, GST_BUFFER_FLAG_DROPPABLE);
48+
return true;
49+
}
50+
51+
#undef GST_CAT_DEFAULT
52+
53+
} // namespace WebCore
54+
55+
#endif // USE(GSTREAMER)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (C) 2024 Igalia S.L
3+
* Copyright (C) 2024 Metrological Group B.V.
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Library General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 2 of the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Library General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Library General Public License
16+
* aint with this library; see the file COPYING.LIB. If not, write to
17+
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18+
* Boston, MA 02110-1301, USA.
19+
*/
20+
21+
#pragma once
22+
23+
#if USE(GSTREAMER)
24+
25+
#include "GStreamerQuirks.h"
26+
27+
namespace WebCore {
28+
29+
class GStreamerQuirkOpenMAX final : public GStreamerQuirk {
30+
public:
31+
GStreamerQuirkOpenMAX();
32+
const ASCIILiteral identifier() const final { return "OpenMAX"_s; }
33+
34+
bool processWebAudioSilentBuffer(GstBuffer*) const final;
35+
};
36+
37+
} // namespace WebCore
38+
39+
#endif // USE(GSTREAMER)

Source/WebCore/platform/gstreamer/GStreamerQuirks.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "GStreamerQuirkBcmNexus.h"
3333
#include "GStreamerQuirkBroadcom.h"
3434
#include "GStreamerQuirkRealtek.h"
35+
#include "GStreamerQuirkOpenMAX.h"
3536
#include "GStreamerQuirkRialto.h"
3637
#include "GStreamerQuirkWesteros.h"
3738
#include <wtf/NeverDestroyed.h>
@@ -81,6 +82,9 @@ GStreamerQuirksManager::GStreamerQuirksManager(bool isForTesting, bool loadQuirk
8182
#if PLATFORM(BCM_NEXUS)
8283
quirksListBuilder.append("bcmnexus,");
8384
#endif
85+
#if PLATFORM(RPI) && CPU(ARM) && !CPU(ARM64)
86+
quirksListBuilder.append("openmax,");
87+
#endif
8488
#if PLATFORM(REALTEK)
8589
quirksListBuilder.append("realtek,");
8690
#endif
@@ -92,7 +96,7 @@ GStreamerQuirksManager::GStreamerQuirksManager(bool isForTesting, bool loadQuirk
9296
GST_DEBUG("Attempting to parse requested quirks: %s", quirks.ascii().data());
9397
if (!quirks.isEmpty()) {
9498
if (WTF::equalLettersIgnoringASCIICase(quirks, "help"_s)) {
95-
WTFLogAlways("Supported quirks for WEBKIT_GST_QUIRKS are: amlogic, broadcom, bcmnexus, realtek, westeros");
99+
WTFLogAlways("Supported quirks for WEBKIT_GST_QUIRKS are: amlogic, broadcom, bcmnexus, openmax, realtek, westeros");
96100
return;
97101
}
98102

@@ -104,6 +108,8 @@ GStreamerQuirksManager::GStreamerQuirksManager(bool isForTesting, bool loadQuirk
104108
quirk = WTF::makeUnique<GStreamerQuirkBroadcom>();
105109
else if (WTF::equalLettersIgnoringASCIICase(identifier, "bcmnexus"_s))
106110
quirk = WTF::makeUnique<GStreamerQuirkBcmNexus>();
111+
else if (WTF::equalLettersIgnoringASCIICase(identifier, "openmax"_s))
112+
quirk = WTF::makeUnique<GStreamerQuirkOpenMAX>();
107113
else if (WTF::equalLettersIgnoringASCIICase(identifier, "realtek"_s))
108114
quirk = WTF::makeUnique<GStreamerQuirkRealtek>();
109115
else if (WTF::equalLettersIgnoringASCIICase(identifier, "rialto"_s))
@@ -367,6 +373,13 @@ void GStreamerQuirksManager::setupBufferingPercentageCorrection(MediaPlayerPriva
367373
}
368374
}
369375

376+
void GStreamerQuirksManager::processWebAudioSilentBuffer(GstBuffer* buffer) const
377+
{
378+
for (const auto& quirk : m_quirks)
379+
if (quirk->processWebAudioSilentBuffer(buffer))
380+
break;
381+
}
382+
370383
#undef GST_CAT_DEFAULT
371384

372385
} // namespace WebCore

Source/WebCore/platform/gstreamer/GStreamerQuirks.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ class GStreamerQuirk : public GStreamerQuirkBase {
8686
virtual int correctBufferingPercentage(MediaPlayerPrivateGStreamer*, int originalBufferingPercentage, GstBufferingMode) const { return originalBufferingPercentage; }
8787
virtual void resetBufferingPercentage(MediaPlayerPrivateGStreamer*, int) const { };
8888
virtual void setupBufferingPercentageCorrection(MediaPlayerPrivateGStreamer*, GstState, GstState, GRefPtr<GstElement>&&) const { }
89+
90+
// Subclass must return true if it wants to override the default behaviour of sibling platforms.
91+
virtual bool processWebAudioSilentBuffer(GstBuffer* buffer) const
92+
{
93+
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_GAP);
94+
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DROPPABLE);
95+
return false;
96+
}
8997
};
9098

9199
class GStreamerHolePunchQuirk : public GStreamerQuirkBase {
@@ -138,6 +146,7 @@ class GStreamerQuirksManager : public RefCounted<GStreamerQuirksManager> {
138146
void resetBufferingPercentage(MediaPlayerPrivateGStreamer*, int bufferingPercentage) const;
139147
void setupBufferingPercentageCorrection(MediaPlayerPrivateGStreamer*, GstState currentState, GstState newState, GRefPtr<GstElement>&&) const;
140148

149+
void processWebAudioSilentBuffer(GstBuffer*) const;
141150
private:
142151
GStreamerQuirksManager(bool, bool);
143152

0 commit comments

Comments
 (0)