summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--ffvpx.patch9589
-rw-r--r--firefox-testing.patch35
-rw-r--r--firefox-tests-reftest.patch287
-rw-r--r--firefox-tests-xpcshell.patch70
-rw-r--r--firefox-vaapi-extra-frames.patch12
-rw-r--r--firefox.spec43
-rw-r--r--mozilla-1667096.patch30
-rw-r--r--mozilla-1678680.patch73
-rw-r--r--mozilla-1680505.patch34
-rw-r--r--mozilla-1687931.patch28
-rw-r--r--pgo.patch58
-rw-r--r--pw1.patch78
-rw-r--r--pw2.patch901
-rw-r--r--pw3.patch183
-rw-r--r--pw4.patch18928
-rw-r--r--pw5.patch53
-rw-r--r--pw6.patch163
-rw-r--r--sources4
19 files changed, 270 insertions, 30301 deletions
diff --git a/.gitignore b/.gitignore
index 66d5c6b..120cbfe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -443,3 +443,5 @@ firefox-3.6.4.source.tar.bz2
/firefox-langpacks-84.0.1-20201222.tar.xz
/firefox-84.0.2.source.tar.xz
/firefox-langpacks-84.0.2-20210106.tar.xz
+/firefox-85.0.source.tar.xz
+/firefox-langpacks-85.0-20210120.tar.xz
diff --git a/ffvpx.patch b/ffvpx.patch
deleted file mode 100644
index 73c2f57..0000000
--- a/ffvpx.patch
+++ /dev/null
@@ -1,9589 +0,0 @@
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/ffmpeg58/moz.build.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/ffmpeg58/moz.build
---- firefox-84.0/dom/media/platforms/ffmpeg/ffmpeg58/moz.build.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/ffmpeg58/moz.build 2020-12-10 20:36:08.398441034 +0100
-@@ -27,8 +27,6 @@ if CONFIG['CC_TYPE'] == 'gcc':
- ]
- if CONFIG['MOZ_WAYLAND']:
- CXXFLAGS += CONFIG['TK_CFLAGS']
-- CXXFLAGS += CONFIG['MOZ_WAYLAND_CFLAGS']
- DEFINES['MOZ_WAYLAND_USE_VAAPI'] = 1
-- include('/ipc/chromium/chromium-config.mozbuild')
-
- FINAL_LIBRARY = 'xul'
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
---- firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp 2020-12-10 20:40:53.388541336 +0100
-@@ -11,6 +11,10 @@
- #include "mozilla/Types.h"
- #include "PlatformDecoderModule.h"
- #include "prlink.h"
-+#ifdef MOZ_WAYLAND
-+# include "mozilla/widget/DMABufLibWrapper.h"
-+# include "mozilla/StaticPrefs_media.h"
-+#endif
-
- #define AV_LOG_DEBUG 48
- #define AV_LOG_INFO 32
-@@ -254,6 +258,46 @@ void FFmpegLibWrapper::Unlink() {
- }
-
- #ifdef MOZ_WAYLAND
-+void FFmpegLibWrapper::LinkVAAPILibs() {
-+ if (widget::GetDMABufDevice()->IsDMABufVAAPIEnabled()) {
-+ PRLibSpec lspec;
-+ lspec.type = PR_LibSpec_Pathname;
-+ const char* libDrm = "libva-drm.so.2";
-+ lspec.value.pathname = libDrm;
-+ mVALibDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-+ if (!mVALibDrm) {
-+ FFMPEG_LOG("VA-API support: Missing or old %s library.\n", libDrm);
-+ }
-+
-+ if (!StaticPrefs::media_ffmpeg_vaapi_drm_display_enabled()) {
-+ const char* libWayland = "libva-wayland.so.2";
-+ lspec.value.pathname = libWayland;
-+ mVALibWayland = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-+ if (!mVALibWayland) {
-+ FFMPEG_LOG("VA-API support: Missing or old %s library.\n", libWayland);
-+ }
-+ }
-+
-+ if (mVALibWayland || mVALibDrm) {
-+ const char* lib = "libva.so.2";
-+ lspec.value.pathname = lib;
-+ mVALib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-+ // Don't use libva when it's missing vaExportSurfaceHandle.
-+ if (mVALib && !PR_FindSymbol(mVALib, "vaExportSurfaceHandle")) {
-+ PR_UnloadLibrary(mVALib);
-+ mVALib = nullptr;
-+ }
-+ if (!mVALib) {
-+ FFMPEG_LOG("VA-API support: Missing or old %s library.\n", lib);
-+ }
-+ }
-+ } else {
-+ FFMPEG_LOG("VA-API FFmpeg is disabled by platform");
-+ }
-+}
-+#endif
-+
-+#ifdef MOZ_WAYLAND
- bool FFmpegLibWrapper::IsVAAPIAvailable() {
- # define VA_FUNC_LOADED(func) (func != nullptr)
- return VA_FUNC_LOADED(avcodec_get_hw_config) &&
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
---- firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h 2020-12-10 20:40:53.388541336 +0100
-@@ -56,6 +56,7 @@ struct MOZ_ONLY_USED_TO_AVOID_STATIC_CON
- #ifdef MOZ_WAYLAND
- // Check if mVALib are available and we can use HW decode.
- bool IsVAAPIAvailable();
-+ void LinkVAAPILibs();
- #endif
-
- // indicate the version of libavcodec linked to.
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
---- firefox-84.0/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp 2020-12-10 20:40:53.388541336 +0100
-@@ -9,10 +9,6 @@
- #include "mozilla/ArrayUtils.h"
- #include "FFmpegLog.h"
- #include "prlink.h"
--#ifdef MOZ_WAYLAND
--# include "mozilla/widget/DMABufLibWrapper.h"
--# include "mozilla/StaticPrefs_media.h"
--#endif
-
- namespace mozilla {
-
-@@ -58,43 +54,7 @@ bool FFmpegRuntimeLinker::Init() {
- }
-
- #ifdef MOZ_WAYLAND
-- if (widget::GetDMABufDevice()->IsDMABufVAAPIEnabled()) {
-- PRLibSpec lspec;
-- lspec.type = PR_LibSpec_Pathname;
-- const char* libDrm = "libva-drm.so.2";
-- lspec.value.pathname = libDrm;
-- sLibAV.mVALibDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-- if (!sLibAV.mVALibDrm) {
-- FFMPEG_LOG("VA-API support: Missing or old %s library.\n", libDrm);
-- }
--
-- if (!StaticPrefs::media_ffmpeg_vaapi_drm_display_enabled()) {
-- const char* libWayland = "libva-wayland.so.2";
-- lspec.value.pathname = libWayland;
-- sLibAV.mVALibWayland =
-- PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-- if (!sLibAV.mVALibWayland) {
-- FFMPEG_LOG("VA-API support: Missing or old %s library.\n", libWayland);
-- }
-- }
--
-- if (sLibAV.mVALibWayland || sLibAV.mVALibDrm) {
-- const char* lib = "libva.so.2";
-- lspec.value.pathname = lib;
-- sLibAV.mVALib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
-- // Don't use libva when it's missing vaExportSurfaceHandle.
-- if (sLibAV.mVALib &&
-- !PR_FindSymbol(sLibAV.mVALib, "vaExportSurfaceHandle")) {
-- PR_UnloadLibrary(sLibAV.mVALib);
-- sLibAV.mVALib = nullptr;
-- }
-- if (!sLibAV.mVALib) {
-- FFMPEG_LOG("VA-API support: Missing or old %s library.\n", lib);
-- }
-- }
-- } else {
-- FFMPEG_LOG("VA-API FFmpeg is disabled by platform");
-- }
-+ sLibAV.LinkVAAPILibs();
- #endif
-
- // While going through all possible libs, this status will be updated with a
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
---- firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp 2020-12-10 20:40:53.392541452 +0100
-@@ -32,6 +32,8 @@
- # define AV_PIX_FMT_NONE PIX_FMT_NONE
- #endif
- #include "mozilla/PodOperations.h"
-+#include "mozilla/ScopeExit.h"
-+#include "mozilla/StaticPrefs_media.h"
- #include "mozilla/TaskQueue.h"
- #include "nsThreadUtils.h"
- #include "prsystem.h"
-@@ -45,7 +47,7 @@ typedef int VAStatus;
- #endif
-
- // Use some extra HW frames for potential rendering lags.
--#define EXTRA_HW_FRAMES 6
-+#define EXTRA_HW_FRAMES 20
-
- typedef mozilla::layers::Image Image;
- typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
-@@ -124,8 +126,8 @@ static AVPixelFormat ChooseVAAPIPixelFor
- return AV_PIX_FMT_NONE;
- }
-
--DMABufSurfaceWrapper::DMABufSurfaceWrapper(DMABufSurface* aSurface,
-- FFmpegLibWrapper* aLib)
-+DMABufSurfaceWrapper<LIBAV_VER>::DMABufSurfaceWrapper(DMABufSurface* aSurface,
-+ FFmpegLibWrapper* aLib)
- : mSurface(aSurface),
- mLib(aLib),
- mAVHWFramesContext(nullptr),
-@@ -138,8 +140,8 @@ DMABufSurfaceWrapper::DMABufSurfaceWrapp
- mSurface->GetUID());
- }
-
--void DMABufSurfaceWrapper::LockVAAPIData(AVCodecContext* aAVCodecContext,
-- AVFrame* aAVFrame) {
-+void DMABufSurfaceWrapper<LIBAV_VER>::LockVAAPIData(
-+ AVCodecContext* aAVCodecContext, AVFrame* aAVFrame) {
- FFMPEG_LOG("DMABufSurfaceWrapper: VAAPI locking dmabuf surface UID = %d",
- mSurface->GetUID());
- if (aAVCodecContext && aAVFrame) {
-@@ -148,7 +150,7 @@ void DMABufSurfaceWrapper::LockVAAPIData
- }
- }
-
--void DMABufSurfaceWrapper::ReleaseVAAPIData() {
-+void DMABufSurfaceWrapper<LIBAV_VER>::ReleaseVAAPIData() {
- FFMPEG_LOG("DMABufSurfaceWrapper: VAAPI releasing dmabuf surface UID = %d",
- mSurface->GetUID());
- if (mHWAVBuffer && mAVHWFramesContext) {
-@@ -158,7 +160,7 @@ void DMABufSurfaceWrapper::ReleaseVAAPID
- mSurface->ReleaseSurface();
- }
-
--DMABufSurfaceWrapper::~DMABufSurfaceWrapper() {
-+DMABufSurfaceWrapper<LIBAV_VER>::~DMABufSurfaceWrapper() {
- FFMPEG_LOG("DMABufSurfaceWrapper: deleting dmabuf surface UID = %d",
- mSurface->GetUID());
- ReleaseVAAPIData();
-@@ -181,7 +183,14 @@ AVCodec* FFmpegVideoDecoder<LIBAV_VER>::
- return nullptr;
- }
-
--class VAAPIDisplayHolder {
-+template <int V>
-+class VAAPIDisplayHolder {};
-+
-+template <>
-+class VAAPIDisplayHolder<LIBAV_VER>;
-+
-+template <>
-+class VAAPIDisplayHolder<LIBAV_VER> {
- public:
- VAAPIDisplayHolder(FFmpegLibWrapper* aLib, VADisplay aDisplay)
- : mLib(aLib), mDisplay(aDisplay){};
-@@ -193,7 +202,8 @@ class VAAPIDisplayHolder {
- };
-
- static void VAAPIDisplayReleaseCallback(struct AVHWDeviceContext* hwctx) {
-- auto displayHolder = static_cast<VAAPIDisplayHolder*>(hwctx->user_opaque);
-+ auto displayHolder =
-+ static_cast<VAAPIDisplayHolder<LIBAV_VER>*>(hwctx->user_opaque);
- delete displayHolder;
- }
-
-@@ -229,7 +239,7 @@ bool FFmpegVideoDecoder<LIBAV_VER>::Crea
- }
- }
-
-- hwctx->user_opaque = new VAAPIDisplayHolder(mLib, mDisplay);
-+ hwctx->user_opaque = new VAAPIDisplayHolder<LIBAV_VER>(mLib, mDisplay);
- hwctx->free = VAAPIDisplayReleaseCallback;
-
- int major, minor;
-@@ -703,7 +713,7 @@ void FFmpegVideoDecoder<LIBAV_VER>::Rele
- }
- }
-
--DMABufSurfaceWrapper*
-+DMABufSurfaceWrapper<LIBAV_VER>*
- FFmpegVideoDecoder<LIBAV_VER>::GetUnusedDMABufSurfaceWrapper() {
- int len = mDMABufSurfaces.Length();
- for (int i = 0; i < len; i++) {
-@@ -769,7 +779,8 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER
-
- RefPtr<DMABufSurfaceYUV> surface;
-
-- DMABufSurfaceWrapper* surfaceWrapper = GetUnusedDMABufSurfaceWrapper();
-+ DMABufSurfaceWrapper<LIBAV_VER>* surfaceWrapper =
-+ GetUnusedDMABufSurfaceWrapper();
- if (!surfaceWrapper) {
- if (mVAAPIDeviceContext) {
- surface = DMABufSurfaceYUV::CreateYUVSurface(vaDesc);
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h
---- firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h 2020-12-10 20:40:53.388541336 +0100
-@@ -55,7 +55,14 @@ namespace mozilla {
- // We own the DMABufSurface underlying GPU data and we use it for
- // repeated rendering of video frames.
- //
--class DMABufSurfaceWrapper final {
-+template <int V>
-+class DMABufSurfaceWrapper {};
-+
-+template <>
-+class DMABufSurfaceWrapper<LIBAV_VER>;
-+
-+template <>
-+class DMABufSurfaceWrapper<LIBAV_VER> final {
- public:
- DMABufSurfaceWrapper(DMABufSurface* aSurface, FFmpegLibWrapper* aLib);
- ~DMABufSurfaceWrapper();
-@@ -162,7 +169,7 @@ class FFmpegVideoDecoder<LIBAV_VER>
- MediaDataDecoder::DecodedData& aResults);
-
- void ReleaseUnusedVAAPIFrames();
-- DMABufSurfaceWrapper* GetUnusedDMABufSurfaceWrapper();
-+ DMABufSurfaceWrapper<LIBAV_VER>* GetUnusedDMABufSurfaceWrapper();
- void ReleaseDMABufSurfaces();
- #endif
-
-@@ -180,7 +187,7 @@ class FFmpegVideoDecoder<LIBAV_VER>
- const bool mDisableHardwareDecoding;
- VADisplay mDisplay;
- bool mUseDMABufSurfaces;
-- nsTArray<DMABufSurfaceWrapper> mDMABufSurfaces;
-+ nsTArray<DMABufSurfaceWrapper<LIBAV_VER>> mDMABufSurfaces;
- #endif
- RefPtr<KnowsCompositor> mImageAllocator;
- RefPtr<ImageContainer> mImageContainer;
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
---- firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp 2020-12-10 20:40:53.388541336 +0100
-@@ -64,6 +64,10 @@ bool FFVPXRuntimeLinker::Init() {
- MOZ_ASSERT(NS_IsMainThread());
- sLinkStatus = LinkStatus_FAILED;
-
-+#ifdef MOZ_WAYLAND
-+ sFFVPXLib.LinkVAAPILibs();
-+#endif
-+
- // We retrieve the path of the lgpllibs library as this is where mozavcodec
- // and mozavutil libs are located.
- PathString lgpllibsname = GetLibraryName(nullptr, "lgpllibs");
-diff -up firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/moz.build.ffvpx firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/moz.build
---- firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/moz.build.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/platforms/ffmpeg/ffvpx/moz.build 2020-12-10 20:36:08.431441959 +0100
-@@ -36,4 +36,8 @@ if CONFIG["CC_TYPE"] == "gcc":
- DEFINES["FFVPX_VERSION"] = 46465650
- DEFINES["USING_MOZFFVPX"] = True
-
-+if CONFIG["MOZ_WAYLAND"]:
-+ CXXFLAGS += CONFIG["TK_CFLAGS"]
-+ DEFINES["MOZ_WAYLAND_USE_VAAPI"] = 1
-+
- FINAL_LIBRARY = "xul"
-diff -up firefox-84.0/gfx/layers/DMABUFSurfaceImage.cpp.ffvpx firefox-84.0/gfx/layers/DMABUFSurfaceImage.cpp
---- firefox-84.0/gfx/layers/DMABUFSurfaceImage.cpp.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/gfx/layers/DMABUFSurfaceImage.cpp 2020-12-10 20:36:08.308438509 +0100
-@@ -5,16 +5,23 @@
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- #include "DMABUFSurfaceImage.h"
--#include "gfxPlatform.h"
-+#include "mozilla/widget/DMABufSurface.h"
- #include "mozilla/layers/CompositableClient.h"
- #include "mozilla/layers/CompositableForwarder.h"
- #include "mozilla/layers/DMABUFTextureClientOGL.h"
--#include "mozilla/UniquePtr.h"
-+#include "mozilla/layers/TextureForwarder.h"
-
- using namespace mozilla;
- using namespace mozilla::layers;
- using namespace mozilla::gfx;
-
-+DMABUFSurfaceImage::DMABUFSurfaceImage(DMABufSurface* aSurface)
-+ : Image(nullptr, ImageFormat::DMABUF), mSurface(aSurface) {
-+ mSurface->GlobalRefAdd();
-+}
-+
-+DMABUFSurfaceImage::~DMABUFSurfaceImage() { mSurface->GlobalRefRelease(); }
-+
- TextureClient* DMABUFSurfaceImage::GetTextureClient(
- KnowsCompositor* aKnowsCompositor) {
- if (!mTextureClient) {
-@@ -25,3 +32,7 @@ TextureClient* DMABUFSurfaceImage::GetTe
- }
- return mTextureClient;
- }
-+
-+gfx::IntSize DMABUFSurfaceImage::GetSize() const {
-+ return gfx::IntSize::Truncate(mSurface->GetWidth(), mSurface->GetHeight());
-+}
-diff -up firefox-84.0/gfx/layers/DMABUFSurfaceImage.h.ffvpx firefox-84.0/gfx/layers/DMABUFSurfaceImage.h
---- firefox-84.0/gfx/layers/DMABUFSurfaceImage.h.ffvpx 2020-12-10 20:53:45.300792876 +0100
-+++ firefox-84.0/gfx/layers/DMABUFSurfaceImage.h 2020-12-10 20:36:08.279437696 +0100
-@@ -8,32 +8,24 @@
- #define SURFACE_DMABUF_H
-
- #include "ImageContainer.h"
--#include "mozilla/widget/DMABufSurface.h"
--#include "mozilla/gfx/Point.h"
--#include "mozilla/layers/TextureClient.h"
-+
-+class DMABufSurface;
-
- namespace mozilla {
- namespace layers {
-
-+class TextureClient;
-+
- class DMABUFSurfaceImage : public Image {
- public:
-- explicit DMABUFSurfaceImage(DMABufSurface* aSurface)
-- : Image(nullptr, ImageFormat::DMABUF), mSurface(aSurface) {
-- mSurface->GlobalRefAdd();
-- }
--
-- ~DMABUFSurfaceImage() { mSurface->GlobalRefRelease(); }
-+ explicit DMABUFSurfaceImage(DMABufSurface* aSurface);
-+ ~DMABUFSurfaceImage();
-
- DMABufSurface* GetSurface() { return mSurface; }
--
-- gfx::IntSize GetSize() const override {
-- return gfx::IntSize::Truncate(mSurface->GetWidth(), mSurface->GetHeight());
-- }
--
-+ gfx::IntSize GetSize() const override;
- already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override {
- return nullptr;
- }
--
- TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) override;
-
- private:
-diff -up firefox-84.0/media/ffvpx/changes.patch.ffvpx firefox-84.0/media/ffvpx/changes.patch
---- firefox-84.0/media/ffvpx/changes.patch.ffvpx 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/media/ffvpx/changes.patch 2020-12-10 20:40:53.388541336 +0100
-@@ -50,3 +50,27 @@ index 9fb8d0a..97ad3b9 100644
- rgba_color[0] = rgba >> 24;
- rgba_color[1] = rgba >> 16;
- rgba_color[2] = rgba >> 8;
-+diff --git a/media/ffvpx/libavutil/hwcontext_vaapi.c b/media/ffvpx/libavutil/hwcontext_vaapi.c
-+--- a/media/ffvpx/libavutil/hwcontext_vaapi.c
-++++ b/media/ffvpx/libavutil/hwcontext_vaapi.c
-+@@ -39,17 +39,19 @@
-+ # include <unistd.h>
-+ #endif
-+
-+
-+ #include "avassert.h"
-+ #include "buffer.h"
-+ #include "common.h"
-+ #include "hwcontext.h"
-++#if CONFIG_LIBDRM
-+ #include "hwcontext_drm.h"
-++#endif
-+ #include "hwcontext_internal.h"
-+ #include "hwcontext_vaapi.h"
-+ #include "mem.h"
-+ #include "pixdesc.h"
-+ #include "pixfmt.h"
-+
-+
-+ typedef struct VAAPIDevicePriv {
-+
-diff -up firefox-84.0/media/ffvpx/config_common.h.ffvpx firefox-84.0/media/ffvpx/config_common.h
---- firefox-84.0/media/ffvpx/config_common.h.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/config_common.h 2020-12-10 20:40:53.388541336 +0100
-@@ -18,4 +18,13 @@
- #define CONFIG_RDFT 1
- #endif
-
-+#ifdef MOZ_WAYLAND
-+#undef CONFIG_VAAPI
-+#undef CONFIG_VP8_VAAPI_HWACCEL
-+#undef CONFIG_VP9_VAAPI_HWACCEL
-+#define CONFIG_VAAPI 1
-+#define CONFIG_VP8_VAAPI_HWACCEL 1
-+#define CONFIG_VP9_VAAPI_HWACCEL 1
-+#endif
-+
- #endif
-diff -up firefox-84.0/media/ffvpx/FILES.ffvpx firefox-84.0/media/ffvpx/FILES
---- firefox-84.0/media/ffvpx/FILES.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/FILES 2020-12-10 20:40:53.388541336 +0100
-@@ -131,6 +131,11 @@
- ./libavcodec/thread.h
- ./libavcodec/unary.h
- ./libavcodec/utils.c
-+./libavcodec/vaapi.h
-+./libavcodec/vaapi_decode.h
-+./libavcodec/vaapi_decode.c
-+./libavcodec/vaapi_vp8.c
-+./libavcodec/vaapi_vp9.c
- ./libavcodec/version.h
- ./libavcodec/videodsp.c
- ./libavcodec/videodsp.h
-@@ -264,6 +269,8 @@
- ./libavutil/hwcontext.c
- ./libavutil/hwcontext.h
- ./libavutil/hwcontext_internal.h
-+./libavutil/hwcontext_vaapi.h
-+./libavutil/hwcontext_vaapi.c
- ./libavutil/imgutils.c
- ./libavutil/imgutils.h
- ./libavutil/imgutils_internal.h
-diff -up firefox-84.0/media/ffvpx/libavcodec/avcodec.symbols.ffvpx firefox-84.0/media/ffvpx/libavcodec/avcodec.symbols
---- firefox-84.0/media/ffvpx/libavcodec/avcodec.symbols.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/avcodec.symbols 2020-12-10 20:40:53.389541365 +0100
-@@ -28,6 +28,11 @@ av_get_pcm_codec
- av_get_profile_name
- av_grow_packet
- av_hwaccel_next
-+av_hwdevice_ctx_init
-+av_hwdevice_ctx_alloc
-+av_hwdevice_ctx_create_derived
-+av_hwframe_transfer_get_formats
-+av_hwframe_ctx_alloc
- av_init_packet
- av_lockmgr_register
- av_new_packet
-@@ -93,6 +98,7 @@ avcodec_free_context
- avcodec_get_class
- avcodec_get_context_defaults3
- avcodec_get_frame_class
-+avcodec_get_hw_config
- avcodec_get_name
- avcodec_get_subtitle_rect_class
- avcodec_get_type
-diff -up firefox-84.0/media/ffvpx/libavcodec/moz.build.ffvpx firefox-84.0/media/ffvpx/libavcodec/moz.build
---- firefox-84.0/media/ffvpx/libavcodec/moz.build.ffvpx 2020-12-10 20:40:53.383541192 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/moz.build 2020-12-10 20:40:53.389541365 +0100
-@@ -96,6 +96,13 @@ if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
- 'vp9prob.c',
- 'vp9recon.c'
- ]
-+ if CONFIG['MOZ_WAYLAND']:
-+ SOURCES += [
-+ 'vaapi_decode.c',
-+ 'vaapi_vp8.c',
-+ 'vaapi_vp9.c',
-+ ]
-+ USE_LIBS += ['mozva']
-
- if CONFIG['MOZ_FDK_AAC']:
- SOURCES += [
-diff -up firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.c.ffvpx firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.c
---- firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.c.ffvpx 2020-12-10 20:40:53.389541365 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.c 2020-12-10 20:40:53.389541365 +0100
-@@ -0,0 +1,732 @@
-+/*
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "libavutil/avassert.h"
-+#include "libavutil/common.h"
-+#include "libavutil/pixdesc.h"
-+
-+#include "avcodec.h"
-+#include "decode.h"
-+#include "internal.h"
-+#include "vaapi_decode.h"
-+
-+
-+int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic,
-+ int type,
-+ const void *data,
-+ size_t size)
-+{
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ VAStatus vas;
-+ VABufferID buffer;
-+
-+ av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS);
-+
-+ vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
-+ type, size, 1, (void*)data, &buffer);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create parameter "
-+ "buffer (type %d): %d (%s).\n",
-+ type, vas, vaErrorStr(vas));
-+ return AVERROR(EIO);
-+ }
-+
-+ pic->param_buffers[pic->nb_param_buffers++] = buffer;
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes) "
-+ "is %#x.\n", type, size, buffer);
-+ return 0;
-+}
-+
-+
-+int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic,
-+ const void *params_data,
-+ size_t params_size,
-+ const void *slice_data,
-+ size_t slice_size)
-+{
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ VAStatus vas;
-+ int index;
-+
-+ av_assert0(pic->nb_slices <= pic->slices_allocated);
-+ if (pic->nb_slices == pic->slices_allocated) {
-+ if (pic->slices_allocated > 0)
-+ pic->slices_allocated *= 2;
-+ else
-+ pic->slices_allocated = 64;
-+
-+ pic->slice_buffers =
-+ av_realloc_array(pic->slice_buffers,
-+ pic->slices_allocated,
-+ 2 * sizeof(*pic->slice_buffers));
-+ if (!pic->slice_buffers)
-+ return AVERROR(ENOMEM);
-+ }
-+ av_assert0(pic->nb_slices + 1 <= pic->slices_allocated);
-+
-+ index = 2 * pic->nb_slices;
-+
-+ vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
-+ VASliceParameterBufferType,
-+ params_size, 1, (void*)params_data,
-+ &pic->slice_buffers[index]);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
-+ "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas));
-+ return AVERROR(EIO);
-+ }
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Slice %d param buffer (%zu bytes) "
-+ "is %#x.\n", pic->nb_slices, params_size,
-+ pic->slice_buffers[index]);
-+
-+ vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
-+ VASliceDataBufferType,
-+ slice_size, 1, (void*)slice_data,
-+ &pic->slice_buffers[index + 1]);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create slice "
-+ "data buffer (size %zu): %d (%s).\n",
-+ slice_size, vas, vaErrorStr(vas));
-+ vaDestroyBuffer(ctx->hwctx->display,
-+ pic->slice_buffers[index]);
-+ return AVERROR(EIO);
-+ }
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Slice %d data buffer (%zu bytes) "
-+ "is %#x.\n", pic->nb_slices, slice_size,
-+ pic->slice_buffers[index + 1]);
-+
-+ ++pic->nb_slices;
-+ return 0;
-+}
-+
-+static void ff_vaapi_decode_destroy_buffers(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic)
-+{
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ VAStatus vas;
-+ int i;
-+
-+ for (i = 0; i < pic->nb_param_buffers; i++) {
-+ vas = vaDestroyBuffer(ctx->hwctx->display,
-+ pic->param_buffers[i]);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy "
-+ "parameter buffer %#x: %d (%s).\n",
-+ pic->param_buffers[i], vas, vaErrorStr(vas));
-+ }
-+ }
-+
-+ for (i = 0; i < 2 * pic->nb_slices; i++) {
-+ vas = vaDestroyBuffer(ctx->hwctx->display,
-+ pic->slice_buffers[i]);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy slice "
-+ "slice buffer %#x: %d (%s).\n",
-+ pic->slice_buffers[i], vas, vaErrorStr(vas));
-+ }
-+ }
-+}
-+
-+int ff_vaapi_decode_issue(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic)
-+{
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ VAStatus vas;
-+ int err;
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n",
-+ pic->output_surface);
-+
-+ vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context,
-+ pic->output_surface);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to begin picture decode "
-+ "issue: %d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail_with_picture;
-+ }
-+
-+ vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
-+ pic->param_buffers, pic->nb_param_buffers);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to upload decode "
-+ "parameters: %d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail_with_picture;
-+ }
-+
-+ vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
-+ pic->slice_buffers, 2 * pic->nb_slices);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to upload slices: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail_with_picture;
-+ }
-+
-+ vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
-+ "issue: %d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
-+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
-+ goto fail;
-+ else
-+ goto fail_at_end;
-+ }
-+
-+ if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks &
-+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS)
-+ ff_vaapi_decode_destroy_buffers(avctx, pic);
-+
-+ err = 0;
-+ goto exit;
-+
-+fail_with_picture:
-+ vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to end picture decode "
-+ "after error: %d (%s).\n", vas, vaErrorStr(vas));
-+ }
-+fail:
-+ ff_vaapi_decode_destroy_buffers(avctx, pic);
-+fail_at_end:
-+exit:
-+ pic->nb_param_buffers = 0;
-+ pic->nb_slices = 0;
-+ pic->slices_allocated = 0;
-+ av_freep(&pic->slice_buffers);
-+
-+ return err;
-+}
-+
-+int ff_vaapi_decode_cancel(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic)
-+{
-+ ff_vaapi_decode_destroy_buffers(avctx, pic);
-+
-+ pic->nb_param_buffers = 0;
-+ pic->nb_slices = 0;
-+ pic->slices_allocated = 0;
-+ av_freep(&pic->slice_buffers);
-+
-+ return 0;
-+}
-+
-+static const struct {
-+ uint32_t fourcc;
-+ enum AVPixelFormat pix_fmt;
-+} vaapi_format_map[] = {
-+#define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av }
-+ // 4:0:0
-+ MAP(Y800, GRAY8),
-+ // 4:2:0
-+ MAP(NV12, NV12),
-+ MAP(YV12, YUV420P),
-+ MAP(IYUV, YUV420P),
-+#ifdef VA_FOURCC_I420
-+ MAP(I420, YUV420P),
-+#endif
-+ MAP(IMC3, YUV420P),
-+ // 4:1:1
-+ MAP(411P, YUV411P),
-+ // 4:2:2
-+ MAP(422H, YUV422P),
-+#ifdef VA_FOURCC_YV16
-+ MAP(YV16, YUV422P),
-+#endif
-+ // 4:4:0
-+ MAP(422V, YUV440P),
-+ // 4:4:4
-+ MAP(444P, YUV444P),
-+ // 4:2:0 10-bit
-+#ifdef VA_FOURCC_P010
-+ MAP(P010, P010),
-+#endif
-+#ifdef VA_FOURCC_I010
-+ MAP(I010, YUV420P10),
-+#endif
-+#undef MAP
-+};
-+
-+static int vaapi_decode_find_best_format(AVCodecContext *avctx,
-+ AVHWDeviceContext *device,
-+ VAConfigID config_id,
-+ AVHWFramesContext *frames)
-+{
-+ AVVAAPIDeviceContext *hwctx = device->hwctx;
-+ VAStatus vas;
-+ VASurfaceAttrib *attr;
-+ enum AVPixelFormat source_format, best_format, format;
-+ uint32_t best_fourcc, fourcc;
-+ int i, j, nb_attr;
-+
-+ source_format = avctx->sw_pix_fmt;
-+ av_assert0(source_format != AV_PIX_FMT_NONE);
-+
-+ vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
-+ NULL, &nb_attr);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ return AVERROR(ENOSYS);
-+ }
-+
-+ attr = av_malloc_array(nb_attr, sizeof(*attr));
-+ if (!attr)
-+ return AVERROR(ENOMEM);
-+
-+ vas = vaQuerySurfaceAttributes(hwctx->display, config_id,
-+ attr, &nb_attr);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ av_freep(&attr);
-+ return AVERROR(ENOSYS);
-+ }
-+
-+ best_format = AV_PIX_FMT_NONE;
-+
-+ for (i = 0; i < nb_attr; i++) {
-+ if (attr[i].type != VASurfaceAttribPixelFormat)
-+ continue;
-+
-+ fourcc = attr[i].value.value.i;
-+ for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) {
-+ if (fourcc == vaapi_format_map[j].fourcc)
-+ break;
-+ }
-+ if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) {
-+ av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n",
-+ fourcc);
-+ continue;
-+ }
-+ format = vaapi_format_map[j].pix_fmt;
-+ av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n",
-+ fourcc, av_get_pix_fmt_name(format));
-+
-+ best_format = av_find_best_pix_fmt_of_2(format, best_format,
-+ source_format, 0, NULL);
-+ if (format == best_format)
-+ best_fourcc = fourcc;
-+ }
-+
-+ av_freep(&attr);
-+
-+ if (best_format == AV_PIX_FMT_NONE) {
-+ av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n",
-+ av_get_pix_fmt_name(best_format), best_fourcc,
-+ av_get_pix_fmt_name(source_format));
-+
-+ frames->sw_format = best_format;
-+ if (avctx->internal->hwaccel_priv_data) {
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ AVVAAPIFramesContext *avfc = frames->hwctx;
-+
-+ ctx->pixel_format_attribute = (VASurfaceAttrib) {
-+ .type = VASurfaceAttribPixelFormat,
-+ .value.value.i = best_fourcc,
-+ };
-+
-+ avfc->attributes = &ctx->pixel_format_attribute;
-+ avfc->nb_attributes = 1;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct {
-+ enum AVCodecID codec_id;
-+ int codec_profile;
-+ VAProfile va_profile;
-+} vaapi_profile_map[] = {
-+#define MAP(c, p, v) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, VAProfile ## v }
-+ MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple ),
-+ MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main ),
-+ MAP(H263, UNKNOWN, H263Baseline),
-+ MAP(MPEG4, MPEG4_SIMPLE, MPEG4Simple ),
-+ MAP(MPEG4, MPEG4_ADVANCED_SIMPLE,
-+ MPEG4AdvancedSimple),
-+ MAP(MPEG4, MPEG4_MAIN, MPEG4Main ),
-+ MAP(H264, H264_CONSTRAINED_BASELINE,
-+ H264ConstrainedBaseline),
-+ MAP(H264, H264_MAIN, H264Main ),
-+ MAP(H264, H264_HIGH, H264High ),
-+#if VA_CHECK_VERSION(0, 37, 0)
-+ MAP(HEVC, HEVC_MAIN, HEVCMain ),
-+ MAP(HEVC, HEVC_MAIN_10, HEVCMain10 ),
-+#endif
-+ MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT,
-+ JPEGBaseline),
-+ MAP(WMV3, VC1_SIMPLE, VC1Simple ),
-+ MAP(WMV3, VC1_MAIN, VC1Main ),
-+ MAP(WMV3, VC1_COMPLEX, VC1Advanced ),
-+ MAP(WMV3, VC1_ADVANCED, VC1Advanced ),
-+ MAP(VC1, VC1_SIMPLE, VC1Simple ),
-+ MAP(VC1, VC1_MAIN, VC1Main ),
-+ MAP(VC1, VC1_COMPLEX, VC1Advanced ),
-+ MAP(VC1, VC1_ADVANCED, VC1Advanced ),
-+ MAP(VP8, UNKNOWN, VP8Version0_3 ),
-+#if VA_CHECK_VERSION(0, 38, 0)
-+ MAP(VP9, VP9_0, VP9Profile0 ),
-+#endif
-+#if VA_CHECK_VERSION(0, 39, 0)
-+ MAP(VP9, VP9_2, VP9Profile2 ),
-+#endif
-+#undef MAP
-+};
-+
-+/*
-+ * Set *va_config and the frames_ref fields from the current codec parameters
-+ * in avctx.
-+ */
-+static int vaapi_decode_make_config(AVCodecContext *avctx,
-+ AVBufferRef *device_ref,
-+ VAConfigID *va_config,
-+ AVBufferRef *frames_ref)
-+{
-+ AVVAAPIHWConfig *hwconfig = NULL;
-+ AVHWFramesConstraints *constraints = NULL;
-+ VAStatus vas;
-+ int err, i, j;
-+ const AVCodecDescriptor *codec_desc;
-+ VAProfile *profile_list = NULL, matched_va_profile;
-+ int profile_count, exact_match, matched_ff_profile;
-+
-+ AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data;
-+ AVVAAPIDeviceContext *hwctx = device->hwctx;
-+
-+ codec_desc = avcodec_descriptor_get(avctx->codec_id);
-+ if (!codec_desc) {
-+ err = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+
-+ profile_count = vaMaxNumProfiles(hwctx->display);
-+ profile_list = av_malloc_array(profile_count,
-+ sizeof(VAProfile));
-+ if (!profile_list) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ vas = vaQueryConfigProfiles(hwctx->display,
-+ profile_list, &profile_count);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(ENOSYS);
-+ goto fail;
-+ }
-+
-+ matched_va_profile = VAProfileNone;
-+ exact_match = 0;
-+
-+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
-+ int profile_match = 0;
-+ if (avctx->codec_id != vaapi_profile_map[i].codec_id)
-+ continue;
-+ if (avctx->profile == vaapi_profile_map[i].codec_profile ||
-+ vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN)
-+ profile_match = 1;
-+ for (j = 0; j < profile_count; j++) {
-+ if (vaapi_profile_map[i].va_profile == profile_list[j]) {
-+ exact_match = profile_match;
-+ break;
-+ }
-+ }
-+ if (j < profile_count) {
-+ matched_va_profile = vaapi_profile_map[i].va_profile;
-+ matched_ff_profile = vaapi_profile_map[i].codec_profile;
-+ if (exact_match)
-+ break;
-+ }
-+ }
-+ av_freep(&profile_list);
-+
-+ if (matched_va_profile == VAProfileNone) {
-+ av_log(avctx, AV_LOG_ERROR, "No support for codec %s "
-+ "profile %d.\n", codec_desc->name, avctx->profile);
-+ err = AVERROR(ENOSYS);
-+ goto fail;
-+ }
-+ if (!exact_match) {
-+ if (avctx->hwaccel_flags &
-+ AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) {
-+ av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
-+ "supported for hardware decode.\n",
-+ codec_desc->name, avctx->profile);
-+ av_log(avctx, AV_LOG_WARNING, "Using possibly-"
-+ "incompatible profile %d instead.\n",
-+ matched_ff_profile);
-+ } else {
-+ av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not "
-+ "supported for hardware decode.\n",
-+ codec_desc->name, avctx->profile);
-+ err = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+ }
-+
-+ vas = vaCreateConfig(hwctx->display, matched_va_profile,
-+ VAEntrypointVLD, NULL, 0,
-+ va_config);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
-+ "configuration: %d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+
-+ hwconfig = av_hwdevice_hwconfig_alloc(device_ref);
-+ if (!hwconfig) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ hwconfig->config_id = *va_config;
-+
-+ constraints =
-+ av_hwdevice_get_hwframe_constraints(device_ref, hwconfig);
-+ if (!constraints) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ if (avctx->coded_width < constraints->min_width ||
-+ avctx->coded_height < constraints->min_height ||
-+ avctx->coded_width > constraints->max_width ||
-+ avctx->coded_height > constraints->max_height) {
-+ av_log(avctx, AV_LOG_ERROR, "Hardware does not support image "
-+ "size %dx%d (constraints: width %d-%d height %d-%d).\n",
-+ avctx->coded_width, avctx->coded_height,
-+ constraints->min_width, constraints->max_width,
-+ constraints->min_height, constraints->max_height);
-+ err = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+ if (!constraints->valid_sw_formats ||
-+ constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) {
-+ av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any "
-+ "usable surface formats.\n");
-+ err = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+
-+ if (frames_ref) {
-+ AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data;
-+
-+ frames->format = AV_PIX_FMT_VAAPI;
-+ frames->width = avctx->coded_width;
-+ frames->height = avctx->coded_height;
-+
-+ err = vaapi_decode_find_best_format(avctx, device,
-+ *va_config, frames);
-+ if (err < 0)
-+ goto fail;
-+
-+ frames->initial_pool_size = 1;
-+ // Add per-codec number of surfaces used for storing reference frames.
-+ switch (avctx->codec_id) {
-+ case AV_CODEC_ID_H264:
-+ case AV_CODEC_ID_HEVC:
-+ frames->initial_pool_size += 16;
-+ break;
-+ case AV_CODEC_ID_VP9:
-+ frames->initial_pool_size += 8;
-+ break;
-+ case AV_CODEC_ID_VP8:
-+ frames->initial_pool_size += 3;
-+ break;
-+ default:
-+ frames->initial_pool_size += 2;
-+ }
-+ }
-+
-+ av_hwframe_constraints_free(&constraints);
-+ av_freep(&hwconfig);
-+
-+ return 0;
-+
-+fail:
-+ av_hwframe_constraints_free(&constraints);
-+ av_freep(&hwconfig);
-+ if (*va_config != VA_INVALID_ID) {
-+ vaDestroyConfig(hwctx->display, *va_config);
-+ *va_config = VA_INVALID_ID;
-+ }
-+ av_freep(&profile_list);
-+ return err;
-+}
-+
-+int ff_vaapi_common_frame_params(AVCodecContext *avctx,
-+ AVBufferRef *hw_frames_ctx)
-+{
-+ AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data;
-+ AVHWDeviceContext *device_ctx = hw_frames->device_ctx;
-+ AVVAAPIDeviceContext *hwctx;
-+ VAConfigID va_config = VA_INVALID_ID;
-+ int err;
-+
-+ if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI)
-+ return AVERROR(EINVAL);
-+ hwctx = device_ctx->hwctx;
-+
-+ err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config,
-+ hw_frames_ctx);
-+ if (err)
-+ return err;
-+
-+ if (va_config != VA_INVALID_ID)
-+ vaDestroyConfig(hwctx->display, va_config);
-+
-+ return 0;
-+}
-+
-+int ff_vaapi_decode_init(AVCodecContext *avctx)
-+{
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ VAStatus vas;
-+ int err;
-+
-+ ctx->va_config = VA_INVALID_ID;
-+ ctx->va_context = VA_INVALID_ID;
-+
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+ if (avctx->hwaccel_context) {
-+ av_log(avctx, AV_LOG_WARNING, "Using deprecated struct "
-+ "vaapi_context in decode.\n");
-+
-+ ctx->have_old_context = 1;
-+ ctx->old_context = avctx->hwaccel_context;
-+
-+ // Really we only want the VAAPI device context, but this
-+ // allocates a whole generic device context because we don't
-+ // have any other way to determine how big it should be.
-+ ctx->device_ref =
-+ av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
-+ if (!ctx->device_ref) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
-+ ctx->hwctx = ctx->device->hwctx;
-+
-+ ctx->hwctx->display = ctx->old_context->display;
-+
-+ // The old VAAPI decode setup assumed this quirk was always
-+ // present, so set it here to avoid the behaviour changing.
-+ ctx->hwctx->driver_quirks =
-+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS;
-+
-+ }
-+#endif
-+
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+ if (ctx->have_old_context) {
-+ ctx->va_config = ctx->old_context->config_id;
-+ ctx->va_context = ctx->old_context->context_id;
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Using user-supplied decoder "
-+ "context: %#x/%#x.\n", ctx->va_config, ctx->va_context);
-+ } else {
-+#endif
-+
-+ err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI);
-+ if (err < 0)
-+ goto fail;
-+
-+ ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
-+ ctx->hwfc = ctx->frames->hwctx;
-+ ctx->device = ctx->frames->device_ctx;
-+ ctx->hwctx = ctx->device->hwctx;
-+
-+ err = vaapi_decode_make_config(avctx, ctx->frames->device_ref,
-+ &ctx->va_config, avctx->hw_frames_ctx);
-+ if (err)
-+ goto fail;
-+
-+ vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
-+ avctx->coded_width, avctx->coded_height,
-+ VA_PROGRESSIVE,
-+ ctx->hwfc->surface_ids,
-+ ctx->hwfc->nb_surfaces,
-+ &ctx->va_context);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to create decode "
-+ "context: %d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+
-+ av_log(avctx, AV_LOG_DEBUG, "Decode context initialised: "
-+ "%#x/%#x.\n", ctx->va_config, ctx->va_context);
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+ }
-+#endif
-+
-+ return 0;
-+
-+fail:
-+ ff_vaapi_decode_uninit(avctx);
-+ return err;
-+}
-+
-+int ff_vaapi_decode_uninit(AVCodecContext *avctx)
-+{
-+ VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data;
-+ VAStatus vas;
-+
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+ if (ctx->have_old_context) {
-+ av_buffer_unref(&ctx->device_ref);
-+ } else {
-+#endif
-+
-+ if (ctx->va_context != VA_INVALID_ID) {
-+ vas = vaDestroyContext(ctx->hwctx->display, ctx->va_context);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
-+ "context %#x: %d (%s).\n",
-+ ctx->va_context, vas, vaErrorStr(vas));
-+ }
-+ }
-+ if (ctx->va_config != VA_INVALID_ID) {
-+ vas = vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(avctx, AV_LOG_ERROR, "Failed to destroy decode "
-+ "configuration %#x: %d (%s).\n",
-+ ctx->va_config, vas, vaErrorStr(vas));
-+ }
-+ }
-+
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+ }
-+#endif
-+
-+ return 0;
-+}
-diff -up firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.h.ffvpx firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.h
---- firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.h.ffvpx 2020-12-10 20:40:53.389541365 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/vaapi_decode.h 2020-12-10 20:40:53.389541365 +0100
-@@ -0,0 +1,105 @@
-+/*
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#ifndef AVCODEC_VAAPI_DECODE_H
-+#define AVCODEC_VAAPI_DECODE_H
-+
-+#include <va/va.h>
-+#include <va/va_dec_vp9.h>
-+
-+#include "libavutil/frame.h"
-+#include "libavutil/hwcontext.h"
-+#include "libavutil/hwcontext_vaapi.h"
-+
-+#include "avcodec.h"
-+
-+#include "version.h"
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+#include "vaapi.h"
-+#endif
-+
-+static inline VASurfaceID ff_vaapi_get_surface_id(AVFrame *pic)
-+{
-+ return (uintptr_t)pic->data[3];
-+}
-+
-+enum {
-+ MAX_PARAM_BUFFERS = 16,
-+};
-+
-+typedef struct VAAPIDecodePicture {
-+ VASurfaceID output_surface;
-+
-+ int nb_param_buffers;
-+ VABufferID param_buffers[MAX_PARAM_BUFFERS];
-+
-+ int nb_slices;
-+ VABufferID *slice_buffers;
-+ int slices_allocated;
-+} VAAPIDecodePicture;
-+
-+typedef struct VAAPIDecodeContext {
-+ VAConfigID va_config;
-+ VAContextID va_context;
-+
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+FF_DISABLE_DEPRECATION_WARNINGS
-+ int have_old_context;
-+ struct vaapi_context *old_context;
-+ AVBufferRef *device_ref;
-+FF_ENABLE_DEPRECATION_WARNINGS
-+#endif
-+
-+ AVHWDeviceContext *device;
-+ AVVAAPIDeviceContext *hwctx;
-+
-+ AVHWFramesContext *frames;
-+ AVVAAPIFramesContext *hwfc;
-+
-+ enum AVPixelFormat surface_format;
-+ int surface_count;
-+
-+ VASurfaceAttrib pixel_format_attribute;
-+} VAAPIDecodeContext;
-+
-+
-+int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic,
-+ int type,
-+ const void *data,
-+ size_t size);
-+
-+int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic,
-+ const void *params_data,
-+ size_t params_size,
-+ const void *slice_data,
-+ size_t slice_size);
-+
-+int ff_vaapi_decode_issue(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic);
-+int ff_vaapi_decode_cancel(AVCodecContext *avctx,
-+ VAAPIDecodePicture *pic);
-+
-+int ff_vaapi_decode_init(AVCodecContext *avctx);
-+int ff_vaapi_decode_uninit(AVCodecContext *avctx);
-+
-+int ff_vaapi_common_frame_params(AVCodecContext *avctx,
-+ AVBufferRef *hw_frames_ctx);
-+
-+#endif /* AVCODEC_VAAPI_DECODE_H */
-diff -up firefox-84.0/media/ffvpx/libavcodec/vaapi.h.ffvpx firefox-84.0/media/ffvpx/libavcodec/vaapi.h
---- firefox-84.0/media/ffvpx/libavcodec/vaapi.h.ffvpx 2020-12-10 20:40:53.389541365 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/vaapi.h 2020-12-10 20:40:53.389541365 +0100
-@@ -0,0 +1,86 @@
-+/*
-+ * Video Acceleration API (shared data between FFmpeg and the video player)
-+ * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1
-+ *
-+ * Copyright (C) 2008-2009 Splitted-Desktop Systems
-+ *
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#ifndef AVCODEC_VAAPI_H
-+#define AVCODEC_VAAPI_H
-+
-+/**
-+ * @file
-+ * @ingroup lavc_codec_hwaccel_vaapi
-+ * Public libavcodec VA API header.
-+ */
-+
-+#include <stdint.h>
-+#include "libavutil/attributes.h"
-+#include "version.h"
-+
-+#if FF_API_STRUCT_VAAPI_CONTEXT
-+
-+/**
-+ * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding
-+ * @ingroup lavc_codec_hwaccel
-+ * @{
-+ */
-+
-+/**
-+ * This structure is used to share data between the FFmpeg library and
-+ * the client video application.
-+ * This shall be zero-allocated and available as
-+ * AVCodecContext.hwaccel_context. All user members can be set once
-+ * during initialization or through each AVCodecContext.get_buffer()
-+ * function call. In any case, they must be valid prior to calling
-+ * decoding functions.
-+ *
-+ * Deprecated: use AVCodecContext.hw_frames_ctx instead.
-+ */
-+struct attribute_deprecated vaapi_context {
-+ /**
-+ * Window system dependent data
-+ *
-+ * - encoding: unused
-+ * - decoding: Set by user
-+ */
-+ void *display;
-+
-+ /**
-+ * Configuration ID
-+ *
-+ * - encoding: unused
-+ * - decoding: Set by user
-+ */
-+ uint32_t config_id;
-+
-+ /**
-+ * Context ID (video decode pipeline)
-+ *
-+ * - encoding: unused
-+ * - decoding: Set by user
-+ */
-+ uint32_t context_id;
-+};
-+
-+/* @} */
-+
-+#endif /* FF_API_STRUCT_VAAPI_CONTEXT */
-+
-+#endif /* AVCODEC_VAAPI_H */
-diff -up firefox-84.0/media/ffvpx/libavcodec/vaapi_vp8.c.ffvpx firefox-84.0/media/ffvpx/libavcodec/vaapi_vp8.c
---- firefox-84.0/media/ffvpx/libavcodec/vaapi_vp8.c.ffvpx 2020-12-10 20:40:53.389541365 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/vaapi_vp8.c 2020-12-10 20:40:53.389541365 +0100
-@@ -0,0 +1,237 @@
-+/*
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <va/va.h>
-+#include <va/va_dec_vp8.h>
-+
-+#include "hwaccel.h"
-+#include "vaapi_decode.h"
-+#include "vp8.h"
-+
-+static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf)
-+{
-+ if (vf)
-+ return ff_vaapi_get_surface_id(vf->tf.f);
-+ else
-+ return VA_INVALID_SURFACE;
-+}
-+
-+static int vaapi_vp8_start_frame(AVCodecContext *avctx,
-+ av_unused const uint8_t *buffer,
-+ av_unused uint32_t size)
-+{
-+ const VP8Context *s = avctx->priv_data;
-+ VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private;
-+ VAPictureParameterBufferVP8 pp;
-+ VAProbabilityDataBufferVP8 prob;
-+ VAIQMatrixBufferVP8 quant;
-+ int err, i, j, k;
-+
-+ pic->output_surface = vaapi_vp8_surface_id(s->framep[VP56_FRAME_CURRENT]);
-+
-+ pp = (VAPictureParameterBufferVP8) {
-+ .frame_width = avctx->width,
-+ .frame_height = avctx->height,
-+
-+ .last_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_PREVIOUS]),
-+ .golden_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN]),
-+ .alt_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN2]),
-+ .out_of_loop_frame = VA_INVALID_SURFACE,
-+
-+ .pic_fields.bits = {
-+ .key_frame = !s->keyframe,
-+ .version = s->profile,
-+
-+ .segmentation_enabled = s->segmentation.enabled,
-+ .update_mb_segmentation_map = s->segmentation.update_map,
-+ .update_segment_feature_data = s->segmentation.update_feature_data,
-+
-+ .filter_type = s->filter.simple,
-+ .sharpness_level = s->filter.sharpness,
-+
-+ .loop_filter_adj_enable = s->lf_delta.enabled,
-+ .mode_ref_lf_delta_update = s->lf_delta.update,
-+
-+ .sign_bias_golden = s->sign_bias[VP56_FRAME_GOLDEN],
-+ .sign_bias_alternate = s->sign_bias[VP56_FRAME_GOLDEN2],
-+
-+ .mb_no_coeff_skip = s->mbskip_enabled,
-+ .loop_filter_disable = s->filter.level == 0,
-+ },
-+
-+ .prob_skip_false = s->prob->mbskip,
-+ .prob_intra = s->prob->intra,
-+ .prob_last = s->prob->last,
-+ .prob_gf = s->prob->golden,
-+ };
-+
-+ for (i = 0; i < 3; i++)
-+ pp.mb_segment_tree_probs[i] = s->prob->segmentid[i];
-+
-+ for (i = 0; i < 4; i++) {
-+ if (s->segmentation.enabled) {
-+ pp.loop_filter_level[i] = s->segmentation.filter_level[i];
-+ if (!s->segmentation.absolute_vals)
-+ pp.loop_filter_level[i] += s->filter.level;
-+ } else {
-+ pp.loop_filter_level[i] = s->filter.level;
-+ }
-+ pp.loop_filter_level[i] = av_clip_uintp2(pp.loop_filter_level[i], 6);
-+ }
-+
-+ for (i = 0; i < 4; i++) {
-+ pp.loop_filter_deltas_ref_frame[i] = s->lf_delta.ref[i];
-+ pp.loop_filter_deltas_mode[i] = s->lf_delta.mode[i + 4];
-+ }
-+
-+ if (s->keyframe) {
-+ static const uint8_t keyframe_y_mode_probs[4] = {
-+ 145, 156, 163, 128
-+ };
-+ static const uint8_t keyframe_uv_mode_probs[3] = {
-+ 142, 114, 183
-+ };
-+ memcpy(pp.y_mode_probs, keyframe_y_mode_probs, 4);
-+ memcpy(pp.uv_mode_probs, keyframe_uv_mode_probs, 3);
-+ } else {
-+ for (i = 0; i < 4; i++)
-+ pp.y_mode_probs[i] = s->prob->pred16x16[i];
-+ for (i = 0; i < 3; i++)
-+ pp.uv_mode_probs[i] = s->prob->pred8x8c[i];
-+ }
-+ for (i = 0; i < 2; i++)
-+ for (j = 0; j < 19; j++)
-+ pp.mv_probs[i][j] = s->prob->mvc[i][j];
-+
-+ pp.bool_coder_ctx.range = s->coder_state_at_header_end.range;
-+ pp.bool_coder_ctx.value = s->coder_state_at_header_end.value;
-+ pp.bool_coder_ctx.count = s->coder_state_at_header_end.bit_count;
-+
-+ err = ff_vaapi_decode_make_param_buffer(avctx, pic,
-+ VAPictureParameterBufferType,
-+ &pp, sizeof(pp));
-+ if (err < 0)
-+ goto fail;
-+
-+ for (i = 0; i < 4; i++) {
-+ for (j = 0; j < 8; j++) {
-+ static const int coeff_bands_inverse[8] = {
-+ 0, 1, 2, 3, 5, 6, 4, 15
-+ };
-+ int coeff_pos = coeff_bands_inverse[j];
-+
-+ for (k = 0; k < 3; k++) {
-+ memcpy(prob.dct_coeff_probs[i][j][k],
-+ s->prob->token[i][coeff_pos][k], 11);
-+ }
-+ }
-+ }
-+
-+ err = ff_vaapi_decode_make_param_buffer(avctx, pic,
-+ VAProbabilityBufferType,
-+ &prob, sizeof(prob));
-+ if (err < 0)
-+ goto fail;
-+
-+ for (i = 0; i < 4; i++) {
-+ int base_qi = s->segmentation.base_quant[i];
-+ if (!s->segmentation.absolute_vals)
-+ base_qi += s->quant.yac_qi;
-+
-+ quant.quantization_index[i][0] = av_clip_uintp2(base_qi, 7);
-+ quant.quantization_index[i][1] = av_clip_uintp2(base_qi + s->quant.ydc_delta, 7);
-+ quant.quantization_index[i][2] = av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7);
-+ quant.quantization_index[i][3] = av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7);
-+ quant.quantization_index[i][4] = av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7);
-+ quant.quantization_index[i][5] = av_clip_uintp2(base_qi + s->quant.uvac_delta, 7);
-+ }
-+
-+ err = ff_vaapi_decode_make_param_buffer(avctx, pic,
-+ VAIQMatrixBufferType,
-+ &quant, sizeof(quant));
-+ if (err < 0)
-+ goto fail;
-+
-+ return 0;
-+
-+fail:
-+ ff_vaapi_decode_cancel(avctx, pic);
-+ return err;
-+}
-+
-+static int vaapi_vp8_end_frame(AVCodecContext *avctx)
-+{
-+ const VP8Context *s = avctx->priv_data;
-+ VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private;
-+
-+ return ff_vaapi_decode_issue(avctx, pic);
-+}
-+
-+static int vaapi_vp8_decode_slice(AVCodecContext *avctx,
-+ const uint8_t *buffer,
-+ uint32_t size)
-+{
-+ const VP8Context *s = avctx->priv_data;
-+ VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private;
-+ VASliceParameterBufferVP8 sp;
-+ int err, i;
-+
-+ unsigned int header_size = 3 + 7 * s->keyframe;
-+ const uint8_t *data = buffer + header_size;
-+ unsigned int data_size = size - header_size;
-+
-+ sp = (VASliceParameterBufferVP8) {
-+ .slice_data_size = data_size,
-+ .slice_data_offset = 0,
-+ .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
-+
-+ .macroblock_offset = (8 * (s->coder_state_at_header_end.input - data) -
-+ s->coder_state_at_header_end.bit_count - 8),
-+ .num_of_partitions = s->num_coeff_partitions + 1,
-+ };
-+
-+ sp.partition_size[0] = s->header_partition_size - ((sp.macroblock_offset + 7) / 8);
-+ for (i = 0; i < 8; i++)
-+ sp.partition_size[i+1] = s->coeff_partition_size[i];
-+
-+ err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), data, data_size);
-+ if (err)
-+ goto fail;
-+
-+ return 0;
-+
-+fail:
-+ ff_vaapi_decode_cancel(avctx, pic);
-+ return err;
-+}
-+
-+const AVHWAccel ff_vp8_vaapi_hwaccel = {
-+ .name = "vp8_vaapi",
-+ .type = AVMEDIA_TYPE_VIDEO,
-+ .id = AV_CODEC_ID_VP8,
-+ .pix_fmt = AV_PIX_FMT_VAAPI,
-+ .start_frame = &vaapi_vp8_start_frame,
-+ .end_frame = &vaapi_vp8_end_frame,
-+ .decode_slice = &vaapi_vp8_decode_slice,
-+ .frame_priv_data_size = sizeof(VAAPIDecodePicture),
-+ .init = &ff_vaapi_decode_init,
-+ .uninit = &ff_vaapi_decode_uninit,
-+ .frame_params = &ff_vaapi_common_frame_params,
-+ .priv_data_size = sizeof(VAAPIDecodeContext),
-+ .caps_internal = HWACCEL_CAP_ASYNC_SAFE,
-+};
-diff -up firefox-84.0/media/ffvpx/libavcodec/vaapi_vp9.c.ffvpx firefox-84.0/media/ffvpx/libavcodec/vaapi_vp9.c
---- firefox-84.0/media/ffvpx/libavcodec/vaapi_vp9.c.ffvpx 2020-12-10 20:40:53.389541365 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/vaapi_vp9.c 2020-12-10 20:40:53.389541365 +0100
-@@ -0,0 +1,185 @@
-+/*
-+ * VP9 HW decode acceleration through VA API
-+ *
-+ * Copyright (C) 2015 Timo Rothenpieler <timo@rothenpieler.org>
-+ *
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "libavutil/pixdesc.h"
-+
-+#include "hwaccel.h"
-+#include "vaapi_decode.h"
-+#include "vp9shared.h"
-+
-+static VASurfaceID vaapi_vp9_surface_id(const VP9Frame *vf)
-+{
-+ if (vf)
-+ return ff_vaapi_get_surface_id(vf->tf.f);
-+ else
-+ return VA_INVALID_SURFACE;
-+}
-+
-+static int vaapi_vp9_start_frame(AVCodecContext *avctx,
-+ av_unused const uint8_t *buffer,
-+ av_unused uint32_t size)
-+{
-+ const VP9SharedContext *h = avctx->priv_data;
-+ VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private;
-+ VADecPictureParameterBufferVP9 pic_param;
-+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
-+ int err, i;
-+
-+ pic->output_surface = vaapi_vp9_surface_id(&h->frames[CUR_FRAME]);
-+
-+ pic_param = (VADecPictureParameterBufferVP9) {
-+ .frame_width = avctx->width,
-+ .frame_height = avctx->height,
-+
-+ .pic_fields.bits = {
-+ .subsampling_x = pixdesc->log2_chroma_w,
-+ .subsampling_y = pixdesc->log2_chroma_h,
-+ .frame_type = !h->h.keyframe,
-+ .show_frame = !h->h.invisible,
-+ .error_resilient_mode = h->h.errorres,
-+ .intra_only = h->h.intraonly,
-+ .allow_high_precision_mv = h->h.keyframe ? 0 : h->h.highprecisionmvs,
-+ .mcomp_filter_type = h->h.filtermode ^ (h->h.filtermode <= 1),
-+ .frame_parallel_decoding_mode = h->h.parallelmode,
-+ .reset_frame_context = h->h.resetctx,
-+ .refresh_frame_context = h->h.refreshctx,
-+ .frame_context_idx = h->h.framectxid,
-+
-+ .segmentation_enabled = h->h.segmentation.enabled,
-+ .segmentation_temporal_update = h->h.segmentation.temporal,
-+ .segmentation_update_map = h->h.segmentation.update_map,
-+
-+ .last_ref_frame = h->h.refidx[0],
-+ .last_ref_frame_sign_bias = h->h.signbias[0],
-+ .golden_ref_frame = h->h.refidx[1],
-+ .golden_ref_frame_sign_bias = h->h.signbias[1],
-+ .alt_ref_frame = h->h.refidx[2],
-+ .alt_ref_frame_sign_bias = h->h.signbias[2],
-+ .lossless_flag = h->h.lossless,
-+ },
-+
-+ .filter_level = h->h.filter.level,
-+ .sharpness_level = h->h.filter.sharpness,
-+ .log2_tile_rows = h->h.tiling.log2_tile_rows,
-+ .log2_tile_columns = h->h.tiling.log2_tile_cols,
-+
-+ .frame_header_length_in_bytes = h->h.uncompressed_header_size,
-+ .first_partition_size = h->h.compressed_header_size,
-+
-+ .profile = h->h.profile,
-+ .bit_depth = h->h.bpp,
-+ };
-+
-+ for (i = 0; i < 7; i++)
-+ pic_param.mb_segment_tree_probs[i] = h->h.segmentation.prob[i];
-+
-+ if (h->h.segmentation.temporal) {
-+ for (i = 0; i < 3; i++)
-+ pic_param.segment_pred_probs[i] = h->h.segmentation.pred_prob[i];
-+ } else {
-+ memset(pic_param.segment_pred_probs, 255, sizeof(pic_param.segment_pred_probs));
-+ }
-+
-+ for (i = 0; i < 8; i++) {
-+ if (h->refs[i].f->buf[0])
-+ pic_param.reference_frames[i] = ff_vaapi_get_surface_id(h->refs[i].f);
-+ else
-+ pic_param.reference_frames[i] = VA_INVALID_ID;
-+ }
-+
-+ err = ff_vaapi_decode_make_param_buffer(avctx, pic,
-+ VAPictureParameterBufferType,
-+ &pic_param, sizeof(pic_param));
-+ if (err < 0) {
-+ ff_vaapi_decode_cancel(avctx, pic);
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+static int vaapi_vp9_end_frame(AVCodecContext *avctx)
-+{
-+ const VP9SharedContext *h = avctx->priv_data;
-+ VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private;
-+
-+ return ff_vaapi_decode_issue(avctx, pic);
-+}
-+
-+static int vaapi_vp9_decode_slice(AVCodecContext *avctx,
-+ const uint8_t *buffer,
-+ uint32_t size)
-+{
-+ const VP9SharedContext *h = avctx->priv_data;
-+ VAAPIDecodePicture *pic = h->frames[CUR_FRAME].hwaccel_picture_private;
-+ VASliceParameterBufferVP9 slice_param;
-+ int err, i;
-+
-+ slice_param = (VASliceParameterBufferVP9) {
-+ .slice_data_size = size,
-+ .slice_data_offset = 0,
-+ .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
-+ };
-+
-+ for (i = 0; i < 8; i++) {
-+ slice_param.seg_param[i] = (VASegmentParameterVP9) {
-+ .segment_flags.fields = {
-+ .segment_reference_enabled = h->h.segmentation.feat[i].ref_enabled,
-+ .segment_reference = h->h.segmentation.feat[i].ref_val,
-+ .segment_reference_skipped = h->h.segmentation.feat[i].skip_enabled,
-+ },
-+
-+ .luma_dc_quant_scale = h->h.segmentation.feat[i].qmul[0][0],
-+ .luma_ac_quant_scale = h->h.segmentation.feat[i].qmul[0][1],
-+ .chroma_dc_quant_scale = h->h.segmentation.feat[i].qmul[1][0],
-+ .chroma_ac_quant_scale = h->h.segmentation.feat[i].qmul[1][1],
-+ };
-+
-+ memcpy(slice_param.seg_param[i].filter_level, h->h.segmentation.feat[i].lflvl, sizeof(slice_param.seg_param[i].filter_level));
-+ }
-+
-+ err = ff_vaapi_decode_make_slice_buffer(avctx, pic,
-+ &slice_param, sizeof(slice_param),
-+ buffer, size);
-+ if (err) {
-+ ff_vaapi_decode_cancel(avctx, pic);
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+const AVHWAccel ff_vp9_vaapi_hwaccel = {
-+ .name = "vp9_vaapi",
-+ .type = AVMEDIA_TYPE_VIDEO,
-+ .id = AV_CODEC_ID_VP9,
-+ .pix_fmt = AV_PIX_FMT_VAAPI,
-+ .start_frame = vaapi_vp9_start_frame,
-+ .end_frame = vaapi_vp9_end_frame,
-+ .decode_slice = vaapi_vp9_decode_slice,
-+ .frame_priv_data_size = sizeof(VAAPIDecodePicture),
-+ .init = ff_vaapi_decode_init,
-+ .uninit = ff_vaapi_decode_uninit,
-+ .frame_params = ff_vaapi_common_frame_params,
-+ .priv_data_size = sizeof(VAAPIDecodeContext),
-+ .caps_internal = HWACCEL_CAP_ASYNC_SAFE,
-+};
-diff -up firefox-84.0/media/ffvpx/libavutil/avutil.symbols.ffvpx firefox-84.0/media/ffvpx/libavutil/avutil.symbols
---- firefox-84.0/media/ffvpx/libavutil/avutil.symbols.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/libavutil/avutil.symbols 2020-12-10 20:40:53.389541365 +0100
-@@ -158,6 +158,9 @@ av_get_token
- av_gettime
- av_gettime_relative
- av_gettime_relative_is_monotonic
-+av_hwdevice_get_hwframe_constraints
-+av_hwdevice_hwconfig_alloc
-+av_hwframe_constraints_free
- av_hwframe_get_buffer
- av_image_alloc
- av_image_check_sar
-@@ -320,5 +323,9 @@ avpriv_slicethread_free
- av_hwdevice_get_type_name
- av_hwframe_ctx_alloc
- av_hwframe_ctx_init
-+av_hwdevice_ctx_alloc
-+av_hwdevice_ctx_init
-+av_hwframe_transfer_get_formats
-+av_hwdevice_ctx_create_derived
- av_malloc_array
- av_mallocz_array
-diff -up firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.c.ffvpx firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.c
---- firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.c.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.c 2020-12-10 20:40:53.389541365 +0100
-@@ -0,0 +1,1691 @@
-+/*
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "config.h"
-+
-+#if HAVE_VAAPI_X11
-+# include <va/va_x11.h>
-+#endif
-+#if HAVE_VAAPI_DRM
-+# include <va/va_drm.h>
-+#endif
-+
-+#if CONFIG_LIBDRM
-+# include <va/va_drmcommon.h>
-+# include <xf86drm.h>
-+# include <drm_fourcc.h>
-+# ifndef DRM_FORMAT_MOD_INVALID
-+# define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
-+# endif
-+#endif
-+
-+#include <fcntl.h>
-+#if HAVE_UNISTD_H
-+# include <unistd.h>
-+#endif
-+
-+
-+#include "avassert.h"
-+#include "buffer.h"
-+#include "common.h"
-+#include "hwcontext.h"
-+#if CONFIG_LIBDRM
-+#include "hwcontext_drm.h"
-+#endif
-+#include "hwcontext_internal.h"
-+#include "hwcontext_vaapi.h"
-+#include "mem.h"
-+#include "pixdesc.h"
-+#include "pixfmt.h"
-+
-+
-+typedef struct VAAPIDevicePriv {
-+#if HAVE_VAAPI_X11
-+ Display *x11_display;
-+#endif
-+
-+ int drm_fd;
-+} VAAPIDevicePriv;
-+
-+typedef struct VAAPISurfaceFormat {
-+ enum AVPixelFormat pix_fmt;
-+ VAImageFormat image_format;
-+} VAAPISurfaceFormat;
-+
-+typedef struct VAAPIDeviceContext {
-+ // Surface formats which can be used with this device.
-+ VAAPISurfaceFormat *formats;
-+ int nb_formats;
-+} VAAPIDeviceContext;
-+
-+typedef struct VAAPIFramesContext {
-+ // Surface attributes set at create time.
-+ VASurfaceAttrib *attributes;
-+ int nb_attributes;
-+ // RT format of the underlying surface (Intel driver ignores this anyway).
-+ unsigned int rt_format;
-+ // Whether vaDeriveImage works.
-+ int derive_works;
-+} VAAPIFramesContext;
-+
-+typedef struct VAAPIMapping {
-+ // Handle to the derived or copied image which is mapped.
-+ VAImage image;
-+ // The mapping flags actually used.
-+ int flags;
-+} VAAPIMapping;
-+
-+typedef struct VAAPIFormat {
-+ unsigned int fourcc;
-+ unsigned int rt_format;
-+ enum AVPixelFormat pix_fmt;
-+ int chroma_planes_swapped;
-+} VAAPIFormatDescriptor;
-+
-+#define MAP(va, rt, av, swap_uv) { \
-+ VA_FOURCC_ ## va, \
-+ VA_RT_FORMAT_ ## rt, \
-+ AV_PIX_FMT_ ## av, \
-+ swap_uv, \
-+ }
-+// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
-+// plane swap cases. The frame handling below tries to hide these.
-+static const VAAPIFormatDescriptor vaapi_format_map[] = {
-+ MAP(NV12, YUV420, NV12, 0),
-+#ifdef VA_FOURCC_I420
-+ MAP(I420, YUV420, YUV420P, 0),
-+#endif
-+ MAP(YV12, YUV420, YUV420P, 1),
-+ MAP(IYUV, YUV420, YUV420P, 0),
-+ MAP(422H, YUV422, YUV422P, 0),
-+#ifdef VA_FOURCC_YV16
-+ MAP(YV16, YUV422, YUV422P, 1),
-+#endif
-+ MAP(UYVY, YUV422, UYVY422, 0),
-+ MAP(YUY2, YUV422, YUYV422, 0),
-+ MAP(411P, YUV411, YUV411P, 0),
-+ MAP(422V, YUV422, YUV440P, 0),
-+ MAP(444P, YUV444, YUV444P, 0),
-+ MAP(Y800, YUV400, GRAY8, 0),
-+#ifdef VA_FOURCC_P010
-+ MAP(P010, YUV420_10BPP, P010, 0),
-+#endif
-+ MAP(BGRA, RGB32, BGRA, 0),
-+ MAP(BGRX, RGB32, BGR0, 0),
-+ MAP(RGBA, RGB32, RGBA, 0),
-+ MAP(RGBX, RGB32, RGB0, 0),
-+#ifdef VA_FOURCC_ABGR
-+ MAP(ABGR, RGB32, ABGR, 0),
-+ MAP(XBGR, RGB32, 0BGR, 0),
-+#endif
-+ MAP(ARGB, RGB32, ARGB, 0),
-+ MAP(XRGB, RGB32, 0RGB, 0),
-+};
-+#undef MAP
-+
-+static const VAAPIFormatDescriptor *
-+ vaapi_format_from_fourcc(unsigned int fourcc)
-+{
-+ int i;
-+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
-+ if (vaapi_format_map[i].fourcc == fourcc)
-+ return &vaapi_format_map[i];
-+ return NULL;
-+}
-+
-+static const VAAPIFormatDescriptor *
-+ vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt)
-+{
-+ int i;
-+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
-+ if (vaapi_format_map[i].pix_fmt == pix_fmt)
-+ return &vaapi_format_map[i];
-+ return NULL;
-+}
-+
-+static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
-+{
-+ const VAAPIFormatDescriptor *desc;
-+ desc = vaapi_format_from_fourcc(fourcc);
-+ if (desc)
-+ return desc->pix_fmt;
-+ else
-+ return AV_PIX_FMT_NONE;
-+}
-+
-+static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
-+ enum AVPixelFormat pix_fmt,
-+ VAImageFormat **image_format)
-+{
-+ VAAPIDeviceContext *ctx = hwdev->internal->priv;
-+ int i;
-+
-+ for (i = 0; i < ctx->nb_formats; i++) {
-+ if (ctx->formats[i].pix_fmt == pix_fmt) {
-+ if (image_format)
-+ *image_format = &ctx->formats[i].image_format;
-+ return 0;
-+ }
-+ }
-+ return AVERROR(EINVAL);
-+}
-+
-+static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
-+ const void *hwconfig,
-+ AVHWFramesConstraints *constraints)
-+{
-+ AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
-+ const AVVAAPIHWConfig *config = hwconfig;
-+ VAAPIDeviceContext *ctx = hwdev->internal->priv;
-+ VASurfaceAttrib *attr_list = NULL;
-+ VAStatus vas;
-+ enum AVPixelFormat pix_fmt;
-+ unsigned int fourcc;
-+ int err, i, j, attr_count, pix_fmt_count;
-+
-+ if (config &&
-+ !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
-+ attr_count = 0;
-+ vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
-+ 0, &attr_count);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(ENOSYS);
-+ goto fail;
-+ }
-+
-+ attr_list = av_malloc(attr_count * sizeof(*attr_list));
-+ if (!attr_list) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
-+ attr_list, &attr_count);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ err = AVERROR(ENOSYS);
-+ goto fail;
-+ }
-+
-+ pix_fmt_count = 0;
-+ for (i = 0; i < attr_count; i++) {
-+ switch (attr_list[i].type) {
-+ case VASurfaceAttribPixelFormat:
-+ fourcc = attr_list[i].value.value.i;
-+ pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
-+ if (pix_fmt != AV_PIX_FMT_NONE) {
-+ ++pix_fmt_count;
-+ } else {
-+ // Something unsupported - ignore.
-+ }
-+ break;
-+ case VASurfaceAttribMinWidth:
-+ constraints->min_width = attr_list[i].value.value.i;
-+ break;
-+ case VASurfaceAttribMinHeight:
-+ constraints->min_height = attr_list[i].value.value.i;
-+ break;
-+ case VASurfaceAttribMaxWidth:
-+ constraints->max_width = attr_list[i].value.value.i;
-+ break;
-+ case VASurfaceAttribMaxHeight:
-+ constraints->max_height = attr_list[i].value.value.i;
-+ break;
-+ }
-+ }
-+ if (pix_fmt_count == 0) {
-+ // Nothing usable found. Presumably there exists something which
-+ // works, so leave the set null to indicate unknown.
-+ constraints->valid_sw_formats = NULL;
-+ } else {
-+ constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
-+ sizeof(pix_fmt));
-+ if (!constraints->valid_sw_formats) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ for (i = j = 0; i < attr_count; i++) {
-+ if (attr_list[i].type != VASurfaceAttribPixelFormat)
-+ continue;
-+ fourcc = attr_list[i].value.value.i;
-+ pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
-+ if (pix_fmt != AV_PIX_FMT_NONE)
-+ constraints->valid_sw_formats[j++] = pix_fmt;
-+ }
-+ av_assert0(j == pix_fmt_count);
-+ constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
-+ }
-+ } else {
-+ // No configuration supplied.
-+ // Return the full set of image formats known by the implementation.
-+ constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
-+ sizeof(pix_fmt));
-+ if (!constraints->valid_sw_formats) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ for (i = 0; i < ctx->nb_formats; i++)
-+ constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
-+ constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
-+ }
-+
-+ constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
-+ if (!constraints->valid_hw_formats) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
-+ constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
-+
-+ err = 0;
-+fail:
-+ av_freep(&attr_list);
-+ return err;
-+}
-+
-+static const struct {
-+ const char *friendly_name;
-+ const char *match_string;
-+ unsigned int quirks;
-+} vaapi_driver_quirks_table[] = {
-+#if !VA_CHECK_VERSION(1, 0, 0)
-+ // The i965 driver did not conform before version 2.0.
-+ {
-+ "Intel i965 (Quick Sync)",
-+ "i965",
-+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
-+ },
-+#endif
-+ {
-+ "Intel iHD",
-+ "ubit",
-+ AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
-+ },
-+ {
-+ "VDPAU wrapper",
-+ "Splitted-Desktop Systems VDPAU backend for VA-API",
-+ AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
-+ },
-+};
-+
-+static int vaapi_device_init(AVHWDeviceContext *hwdev)
-+{
-+ VAAPIDeviceContext *ctx = hwdev->internal->priv;
-+ AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
-+ VAImageFormat *image_list = NULL;
-+ VAStatus vas;
-+ const char *vendor_string;
-+ int err, i, image_count;
-+ enum AVPixelFormat pix_fmt;
-+ unsigned int fourcc;
-+
-+ image_count = vaMaxNumImageFormats(hwctx->display);
-+ if (image_count <= 0) {
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+ image_list = av_malloc(image_count * sizeof(*image_list));
-+ if (!image_list) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+
-+ ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
-+ if (!ctx->formats) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ ctx->nb_formats = 0;
-+ for (i = 0; i < image_count; i++) {
-+ fourcc = image_list[i].fourcc;
-+ pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
-+ if (pix_fmt == AV_PIX_FMT_NONE) {
-+ av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
-+ fourcc);
-+ } else {
-+ av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
-+ fourcc, av_get_pix_fmt_name(pix_fmt));
-+ ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
-+ ctx->formats[ctx->nb_formats].image_format = image_list[i];
-+ ++ctx->nb_formats;
-+ }
-+ }
-+
-+ vendor_string = vaQueryVendorString(hwctx->display);
-+ if (vendor_string)
-+ av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
-+
-+ if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
-+ av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
-+ hwctx->driver_quirks);
-+ } else {
-+ // Detect the driver in use and set quirk flags if necessary.
-+ hwctx->driver_quirks = 0;
-+ if (vendor_string) {
-+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
-+ if (strstr(vendor_string,
-+ vaapi_driver_quirks_table[i].match_string)) {
-+ av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
-+ "as known nonstandard driver \"%s\", setting "
-+ "quirks (%#x).\n",
-+ vaapi_driver_quirks_table[i].friendly_name,
-+ vaapi_driver_quirks_table[i].quirks);
-+ hwctx->driver_quirks |=
-+ vaapi_driver_quirks_table[i].quirks;
-+ break;
-+ }
-+ }
-+ if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
-+ av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
-+ "nonstandard list, using standard behaviour.\n");
-+ }
-+ } else {
-+ av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
-+ "assuming standard behaviour.\n");
-+ }
-+ }
-+
-+ av_free(image_list);
-+ return 0;
-+fail:
-+ av_freep(&ctx->formats);
-+ av_free(image_list);
-+ return err;
-+}
-+
-+static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
-+{
-+ VAAPIDeviceContext *ctx = hwdev->internal->priv;
-+
-+ av_freep(&ctx->formats);
-+}
-+
-+static void vaapi_buffer_free(void *opaque, uint8_t *data)
-+{
-+ AVHWFramesContext *hwfc = opaque;
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+
-+ surface_id = (VASurfaceID)(uintptr_t)data;
-+
-+ vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
-+ "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ }
-+}
-+
-+static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
-+{
-+ AVHWFramesContext *hwfc = opaque;
-+ VAAPIFramesContext *ctx = hwfc->internal->priv;
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ AVVAAPIFramesContext *avfc = hwfc->hwctx;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+ AVBufferRef *ref;
-+
-+ if (hwfc->initial_pool_size > 0 &&
-+ avfc->nb_surfaces >= hwfc->initial_pool_size)
-+ return NULL;
-+
-+ vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
-+ hwfc->width, hwfc->height,
-+ &surface_id, 1,
-+ ctx->attributes, ctx->nb_attributes);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ return NULL;
-+ }
-+ av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
-+
-+ ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
-+ sizeof(surface_id), &vaapi_buffer_free,
-+ hwfc, AV_BUFFER_FLAG_READONLY);
-+ if (!ref) {
-+ vaDestroySurfaces(hwctx->display, &surface_id, 1);
-+ return NULL;
-+ }
-+
-+ if (hwfc->initial_pool_size > 0) {
-+ // This is a fixed-size pool, so we must still be in the initial
-+ // allocation sequence.
-+ av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
-+ avfc->surface_ids[avfc->nb_surfaces] = surface_id;
-+ ++avfc->nb_surfaces;
-+ }
-+
-+ return ref;
-+}
-+
-+static int vaapi_frames_init(AVHWFramesContext *hwfc)
-+{
-+ AVVAAPIFramesContext *avfc = hwfc->hwctx;
-+ VAAPIFramesContext *ctx = hwfc->internal->priv;
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ const VAAPIFormatDescriptor *desc;
-+ VAImageFormat *expected_format;
-+ AVBufferRef *test_surface = NULL;
-+ VASurfaceID test_surface_id;
-+ VAImage test_image;
-+ VAStatus vas;
-+ int err, i;
-+
-+ desc = vaapi_format_from_pix_fmt(hwfc->sw_format);
-+ if (!desc) {
-+ av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
-+ av_get_pix_fmt_name(hwfc->sw_format));
-+ return AVERROR(EINVAL);
-+ }
-+
-+ if (!hwfc->pool) {
-+ if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
-+ int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
-+ int need_pixel_format = 1;
-+ for (i = 0; i < avfc->nb_attributes; i++) {
-+ if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
-+ need_memory_type = 0;
-+ if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
-+ need_pixel_format = 0;
-+ }
-+ ctx->nb_attributes =
-+ avfc->nb_attributes + need_memory_type + need_pixel_format;
-+
-+ ctx->attributes = av_malloc(ctx->nb_attributes *
-+ sizeof(*ctx->attributes));
-+ if (!ctx->attributes) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ for (i = 0; i < avfc->nb_attributes; i++)
-+ ctx->attributes[i] = avfc->attributes[i];
-+ if (need_memory_type) {
-+ ctx->attributes[i++] = (VASurfaceAttrib) {
-+ .type = VASurfaceAttribMemoryType,
-+ .flags = VA_SURFACE_ATTRIB_SETTABLE,
-+ .value.type = VAGenericValueTypeInteger,
-+ .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
-+ };
-+ }
-+ if (need_pixel_format) {
-+ ctx->attributes[i++] = (VASurfaceAttrib) {
-+ .type = VASurfaceAttribPixelFormat,
-+ .flags = VA_SURFACE_ATTRIB_SETTABLE,
-+ .value.type = VAGenericValueTypeInteger,
-+ .value.value.i = desc->fourcc,
-+ };
-+ }
-+ av_assert0(i == ctx->nb_attributes);
-+ } else {
-+ ctx->attributes = NULL;
-+ ctx->nb_attributes = 0;
-+ }
-+
-+ ctx->rt_format = desc->rt_format;
-+
-+ if (hwfc->initial_pool_size > 0) {
-+ // This pool will be usable as a render target, so we need to store
-+ // all of the surface IDs somewhere that vaCreateContext() calls
-+ // will be able to access them.
-+ avfc->nb_surfaces = 0;
-+ avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
-+ sizeof(*avfc->surface_ids));
-+ if (!avfc->surface_ids) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ } else {
-+ // This pool allows dynamic sizing, and will not be usable as a
-+ // render target.
-+ avfc->nb_surfaces = 0;
-+ avfc->surface_ids = NULL;
-+ }
-+
-+ hwfc->internal->pool_internal =
-+ av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
-+ &vaapi_pool_alloc, NULL);
-+ if (!hwfc->internal->pool_internal) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ }
-+
-+ // Allocate a single surface to test whether vaDeriveImage() is going
-+ // to work for the specific configuration.
-+ if (hwfc->pool) {
-+ test_surface = av_buffer_pool_get(hwfc->pool);
-+ if (!test_surface) {
-+ av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
-+ "user-configured buffer pool.\n");
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ } else {
-+ test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
-+ if (!test_surface) {
-+ av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
-+ "internal buffer pool.\n");
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+ }
-+ test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
-+
-+ ctx->derive_works = 0;
-+
-+ err = vaapi_get_image_format(hwfc->device_ctx,
-+ hwfc->sw_format, &expected_format);
-+ if (err == 0) {
-+ vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
-+ if (vas == VA_STATUS_SUCCESS) {
-+ if (expected_format->fourcc == test_image.format.fourcc) {
-+ av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
-+ ctx->derive_works = 1;
-+ } else {
-+ av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
-+ "derived image format %08x does not match "
-+ "expected format %08x.\n",
-+ expected_format->fourcc, test_image.format.fourcc);
-+ }
-+ vaDestroyImage(hwctx->display, test_image.image_id);
-+ } else {
-+ av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
-+ "deriving image does not work: "
-+ "%d (%s).\n", vas, vaErrorStr(vas));
-+ }
-+ } else {
-+ av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
-+ "image format is not supported.\n");
-+ }
-+
-+ av_buffer_unref(&test_surface);
-+ return 0;
-+
-+fail:
-+ av_buffer_unref(&test_surface);
-+ av_freep(&avfc->surface_ids);
-+ av_freep(&ctx->attributes);
-+ return err;
-+}
-+
-+static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
-+{
-+ AVVAAPIFramesContext *avfc = hwfc->hwctx;
-+ VAAPIFramesContext *ctx = hwfc->internal->priv;
-+
-+ av_freep(&avfc->surface_ids);
-+ av_freep(&ctx->attributes);
-+}
-+
-+static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
-+{
-+ frame->buf[0] = av_buffer_pool_get(hwfc->pool);
-+ if (!frame->buf[0])
-+ return AVERROR(ENOMEM);
-+
-+ frame->data[3] = frame->buf[0]->data;
-+ frame->format = AV_PIX_FMT_VAAPI;
-+ frame->width = hwfc->width;
-+ frame->height = hwfc->height;
-+
-+ return 0;
-+}
-+
-+static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
-+ enum AVHWFrameTransferDirection dir,
-+ enum AVPixelFormat **formats)
-+{
-+ VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
-+ enum AVPixelFormat *pix_fmts;
-+ int i, k, sw_format_available;
-+
-+ sw_format_available = 0;
-+ for (i = 0; i < ctx->nb_formats; i++) {
-+ if (ctx->formats[i].pix_fmt == hwfc->sw_format)
-+ sw_format_available = 1;
-+ }
-+
-+ pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
-+ if (!pix_fmts)
-+ return AVERROR(ENOMEM);
-+
-+ if (sw_format_available) {
-+ pix_fmts[0] = hwfc->sw_format;
-+ k = 1;
-+ } else {
-+ k = 0;
-+ }
-+ for (i = 0; i < ctx->nb_formats; i++) {
-+ if (ctx->formats[i].pix_fmt == hwfc->sw_format)
-+ continue;
-+ av_assert0(k < ctx->nb_formats);
-+ pix_fmts[k++] = ctx->formats[i].pix_fmt;
-+ }
-+ pix_fmts[k] = AV_PIX_FMT_NONE;
-+
-+ *formats = pix_fmts;
-+ return 0;
-+}
-+
-+static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
-+ HWMapDescriptor *hwmap)
-+{
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ VAAPIMapping *map = hwmap->priv;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+
-+ surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
-+ av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
-+
-+ vas = vaUnmapBuffer(hwctx->display, map->image.buf);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
-+ "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ }
-+
-+ if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
-+ !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
-+ vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
-+ 0, 0, hwfc->width, hwfc->height,
-+ 0, 0, hwfc->width, hwfc->height);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
-+ "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ }
-+ }
-+
-+ vas = vaDestroyImage(hwctx->display, map->image.image_id);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
-+ "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ }
-+
-+ av_free(map);
-+}
-+
-+static int vaapi_map_frame(AVHWFramesContext *hwfc,
-+ AVFrame *dst, const AVFrame *src, int flags)
-+{
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ VAAPIFramesContext *ctx = hwfc->internal->priv;
-+ VASurfaceID surface_id;
-+ const VAAPIFormatDescriptor *desc;
-+ VAImageFormat *image_format;
-+ VAAPIMapping *map;
-+ VAStatus vas;
-+ void *address = NULL;
-+ int err, i;
-+
-+ surface_id = (VASurfaceID)(uintptr_t)src->data[3];
-+ av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
-+
-+ if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
-+ // Requested direct mapping but it is not possible.
-+ return AVERROR(EINVAL);
-+ }
-+ if (dst->format == AV_PIX_FMT_NONE)
-+ dst->format = hwfc->sw_format;
-+ if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
-+ // Requested direct mapping but the formats do not match.
-+ return AVERROR(EINVAL);
-+ }
-+
-+ err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
-+ if (err < 0) {
-+ // Requested format is not a valid output format.
-+ return AVERROR(EINVAL);
-+ }
-+
-+ map = av_malloc(sizeof(*map));
-+ if (!map)
-+ return AVERROR(ENOMEM);
-+ map->flags = flags;
-+ map->image.image_id = VA_INVALID_ID;
-+
-+ vas = vaSyncSurface(hwctx->display, surface_id);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
-+ "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+
-+ // The memory which we map using derive need not be connected to the CPU
-+ // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
-+ // memory is mappable but not cached, so normal memcpy()-like access is
-+ // very slow to read it (but writing is ok). It is possible to read much
-+ // faster with a copy routine which is aware of the limitation, but we
-+ // assume for now that the user is not aware of that and would therefore
-+ // prefer not to be given direct-mapped memory if they request read access.
-+ if (ctx->derive_works && dst->format == hwfc->sw_format &&
-+ ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
-+ vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
-+ "surface %#x: %d (%s).\n",
-+ surface_id, vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+ if (map->image.format.fourcc != image_format->fourcc) {
-+ av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
-+ "is in wrong format: expected %#08x, got %#08x.\n",
-+ surface_id, image_format->fourcc, map->image.format.fourcc);
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+ map->flags |= AV_HWFRAME_MAP_DIRECT;
-+ } else {
-+ vas = vaCreateImage(hwctx->display, image_format,
-+ hwfc->width, hwfc->height, &map->image);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
-+ "surface %#x: %d (%s).\n",
-+ surface_id, vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+ if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
-+ vas = vaGetImage(hwctx->display, surface_id, 0, 0,
-+ hwfc->width, hwfc->height, map->image.image_id);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
-+ "surface %#x: %d (%s).\n",
-+ surface_id, vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+ }
-+ }
-+
-+ vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
-+ "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+
-+ err = ff_hwframe_map_create(src->hw_frames_ctx,
-+ dst, src, &vaapi_unmap_frame, map);
-+ if (err < 0)
-+ goto fail;
-+
-+ dst->width = src->width;
-+ dst->height = src->height;
-+
-+ for (i = 0; i < map->image.num_planes; i++) {
-+ dst->data[i] = (uint8_t*)address + map->image.offsets[i];
-+ dst->linesize[i] = map->image.pitches[i];
-+ }
-+
-+ desc = vaapi_format_from_fourcc(map->image.format.fourcc);
-+ if (desc && desc->chroma_planes_swapped) {
-+ // Chroma planes are YVU rather than YUV, so swap them.
-+ FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
-+ }
-+
-+ return 0;
-+
-+fail:
-+ if (map) {
-+ if (address)
-+ vaUnmapBuffer(hwctx->display, map->image.buf);
-+ if (map->image.image_id != VA_INVALID_ID)
-+ vaDestroyImage(hwctx->display, map->image.image_id);
-+ av_free(map);
-+ }
-+ return err;
-+}
-+
-+static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
-+ AVFrame *dst, const AVFrame *src)
-+{
-+ AVFrame *map;
-+ int err;
-+
-+ if (dst->width > hwfc->width || dst->height > hwfc->height)
-+ return AVERROR(EINVAL);
-+
-+ map = av_frame_alloc();
-+ if (!map)
-+ return AVERROR(ENOMEM);
-+ map->format = dst->format;
-+
-+ err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
-+ if (err)
-+ goto fail;
-+
-+ map->width = dst->width;
-+ map->height = dst->height;
-+
-+ err = av_frame_copy(dst, map);
-+ if (err)
-+ goto fail;
-+
-+ err = 0;
-+fail:
-+ av_frame_free(&map);
-+ return err;
-+}
-+
-+static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
-+ AVFrame *dst, const AVFrame *src)
-+{
-+ AVFrame *map;
-+ int err;
-+
-+ if (src->width > hwfc->width || src->height > hwfc->height)
-+ return AVERROR(EINVAL);
-+
-+ map = av_frame_alloc();
-+ if (!map)
-+ return AVERROR(ENOMEM);
-+ map->format = src->format;
-+
-+ err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
-+ if (err)
-+ goto fail;
-+
-+ map->width = src->width;
-+ map->height = src->height;
-+
-+ err = av_frame_copy(map, src);
-+ if (err)
-+ goto fail;
-+
-+ err = 0;
-+fail:
-+ av_frame_free(&map);
-+ return err;
-+}
-+
-+static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+ int err;
-+
-+ if (dst->format != AV_PIX_FMT_NONE) {
-+ err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
-+ if (err < 0)
-+ return AVERROR(ENOSYS);
-+ }
-+
-+ err = vaapi_map_frame(hwfc, dst, src, flags);
-+ if (err)
-+ return err;
-+
-+ err = av_frame_copy_props(dst, src);
-+ if (err)
-+ return err;
-+
-+ return 0;
-+}
-+
-+#if CONFIG_LIBDRM
-+
-+#define DRM_MAP(va, layers, ...) { \
-+ VA_FOURCC_ ## va, \
-+ layers, \
-+ { __VA_ARGS__ } \
-+ }
-+static const struct {
-+ uint32_t va_fourcc;
-+ int nb_layer_formats;
-+ uint32_t layer_formats[AV_DRM_MAX_PLANES];
-+} vaapi_drm_format_map[] = {
-+#ifdef DRM_FORMAT_R8
-+ DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
-+#endif
-+ DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
-+#if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
-+ DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
-+#endif
-+ DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
-+ DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
-+ DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
-+ DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
-+#ifdef VA_FOURCC_ABGR
-+ DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
-+ DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
-+#endif
-+ DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
-+ DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
-+};
-+#undef DRM_MAP
-+
-+static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
-+ HWMapDescriptor *hwmap)
-+{
-+ AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
-+
-+ VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
-+
-+ av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
-+
-+ vaDestroySurfaces(dst_dev->display, &surface_id, 1);
-+}
-+
-+static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+ AVHWFramesContext *dst_fc =
-+ (AVHWFramesContext*)dst->hw_frames_ctx->data;
-+ AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
-+ const AVDRMFrameDescriptor *desc;
-+ const VAAPIFormatDescriptor *format_desc;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+ uint32_t va_fourcc;
-+ int err, i, j, k;
-+
-+ unsigned long buffer_handle;
-+ VASurfaceAttribExternalBuffers buffer_desc;
-+ VASurfaceAttrib attrs[2] = {
-+ {
-+ .type = VASurfaceAttribMemoryType,
-+ .flags = VA_SURFACE_ATTRIB_SETTABLE,
-+ .value.type = VAGenericValueTypeInteger,
-+ .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
-+ },
-+ {
-+ .type = VASurfaceAttribExternalBufferDescriptor,
-+ .flags = VA_SURFACE_ATTRIB_SETTABLE,
-+ .value.type = VAGenericValueTypePointer,
-+ .value.value.p = &buffer_desc,
-+ }
-+ };
-+
-+ desc = (AVDRMFrameDescriptor*)src->data[0];
-+
-+ if (desc->nb_objects != 1) {
-+ av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
-+ "made from a single DRM object.\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ va_fourcc = 0;
-+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
-+ if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
-+ continue;
-+ for (j = 0; j < desc->nb_layers; j++) {
-+ if (desc->layers[j].format !=
-+ vaapi_drm_format_map[i].layer_formats[j])
-+ break;
-+ }
-+ if (j != desc->nb_layers)
-+ continue;
-+ va_fourcc = vaapi_drm_format_map[i].va_fourcc;
-+ break;
-+ }
-+ if (!va_fourcc) {
-+ av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
-+ "by VAAPI.\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
-+ "%08x.\n", desc->objects[0].fd, va_fourcc);
-+
-+ format_desc = vaapi_format_from_fourcc(va_fourcc);
-+ av_assert0(format_desc);
-+
-+ buffer_handle = desc->objects[0].fd;
-+ buffer_desc.pixel_format = va_fourcc;
-+ buffer_desc.width = src_fc->width;
-+ buffer_desc.height = src_fc->height;
-+ buffer_desc.data_size = desc->objects[0].size;
-+ buffer_desc.buffers = &buffer_handle;
-+ buffer_desc.num_buffers = 1;
-+ buffer_desc.flags = 0;
-+
-+ k = 0;
-+ for (i = 0; i < desc->nb_layers; i++) {
-+ for (j = 0; j < desc->layers[i].nb_planes; j++) {
-+ buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
-+ buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
-+ ++k;
-+ }
-+ }
-+ buffer_desc.num_planes = k;
-+
-+ if (format_desc->chroma_planes_swapped &&
-+ buffer_desc.num_planes == 3) {
-+ FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
-+ FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
-+ }
-+
-+ vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
-+ src->width, src->height,
-+ &surface_id, 1,
-+ attrs, FF_ARRAY_ELEMS(attrs));
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
-+ "object: %d (%s).\n", vas, vaErrorStr(vas));
-+ return AVERROR(EIO);
-+ }
-+ av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
-+
-+ err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
-+ &vaapi_unmap_from_drm,
-+ (void*)(uintptr_t)surface_id);
-+ if (err < 0)
-+ return err;
-+
-+ dst->width = src->width;
-+ dst->height = src->height;
-+ dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
-+
-+ av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
-+ "surface %#x.\n", desc->objects[0].fd, surface_id);
-+
-+ return 0;
-+}
-+
-+#if VA_CHECK_VERSION(1, 1, 0)
-+static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
-+ HWMapDescriptor *hwmap)
-+{
-+ AVDRMFrameDescriptor *drm_desc = hwmap->priv;
-+ int i;
-+
-+ for (i = 0; i < drm_desc->nb_objects; i++)
-+ close(drm_desc->objects[i].fd);
-+
-+ av_freep(&drm_desc);
-+}
-+
-+static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+ VADRMPRIMESurfaceDescriptor va_desc;
-+ AVDRMFrameDescriptor *drm_desc = NULL;
-+ uint32_t export_flags;
-+ int err, i, j;
-+
-+ surface_id = (VASurfaceID)(uintptr_t)src->data[3];
-+
-+ export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
-+ if (flags & AV_HWFRAME_MAP_READ)
-+ export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
-+ if (flags & AV_HWFRAME_MAP_WRITE)
-+ export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
-+
-+ vas = vaExportSurfaceHandle(hwctx->display, surface_id,
-+ VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
-+ export_flags, &va_desc);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
-+ return AVERROR(ENOSYS);
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
-+ "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
-+ return AVERROR(EIO);
-+ }
-+
-+ drm_desc = av_mallocz(sizeof(*drm_desc));
-+ if (!drm_desc) {
-+ err = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
-+ // By some bizarre coincidence, these structures are very similar...
-+ drm_desc->nb_objects = va_desc.num_objects;
-+ for (i = 0; i < va_desc.num_objects; i++) {
-+ drm_desc->objects[i].fd = va_desc.objects[i].fd;
-+ drm_desc->objects[i].size = va_desc.objects[i].size;
-+ drm_desc->objects[i].format_modifier =
-+ va_desc.objects[i].drm_format_modifier;
-+ }
-+ drm_desc->nb_layers = va_desc.num_layers;
-+ for (i = 0; i < va_desc.num_layers; i++) {
-+ drm_desc->layers[i].format = va_desc.layers[i].drm_format;
-+ drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
-+ for (j = 0; j < va_desc.layers[i].num_planes; j++) {
-+ drm_desc->layers[i].planes[j].object_index =
-+ va_desc.layers[i].object_index[j];
-+ drm_desc->layers[i].planes[j].offset =
-+ va_desc.layers[i].offset[j];
-+ drm_desc->layers[i].planes[j].pitch =
-+ va_desc.layers[i].pitch[j];
-+ }
-+ }
-+
-+ err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
-+ &vaapi_unmap_to_drm_esh, drm_desc);
-+ if (err < 0)
-+ goto fail;
-+
-+ dst->width = src->width;
-+ dst->height = src->height;
-+ dst->data[0] = (uint8_t*)drm_desc;
-+
-+ return 0;
-+
-+fail:
-+ for (i = 0; i < va_desc.num_objects; i++)
-+ close(va_desc.objects[i].fd);
-+ av_freep(&drm_desc);
-+ return err;
-+}
-+#endif
-+
-+#if VA_CHECK_VERSION(0, 36, 0)
-+typedef struct VAAPIDRMImageBufferMapping {
-+ VAImage image;
-+ VABufferInfo buffer_info;
-+
-+ AVDRMFrameDescriptor drm_desc;
-+} VAAPIDRMImageBufferMapping;
-+
-+static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
-+ HWMapDescriptor *hwmap)
-+{
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+
-+ surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
-+ av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
-+ surface_id);
-+
-+ // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
-+ // so we shouldn't close them separately.
-+
-+ vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
-+ "handle of image %#x (derived from surface %#x): "
-+ "%d (%s).\n", mapping->image.buf, surface_id,
-+ vas, vaErrorStr(vas));
-+ }
-+
-+ vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
-+ "derived from surface %#x: %d (%s).\n",
-+ surface_id, vas, vaErrorStr(vas));
-+ }
-+
-+ av_free(mapping);
-+}
-+
-+static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-+ VAAPIDRMImageBufferMapping *mapping = NULL;
-+ VASurfaceID surface_id;
-+ VAStatus vas;
-+ int err, i, p;
-+
-+ surface_id = (VASurfaceID)(uintptr_t)src->data[3];
-+ av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
-+ surface_id);
-+
-+ mapping = av_mallocz(sizeof(*mapping));
-+ if (!mapping)
-+ return AVERROR(ENOMEM);
-+
-+ vas = vaDeriveImage(hwctx->display, surface_id,
-+ &mapping->image);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
-+ "surface %#x: %d (%s).\n",
-+ surface_id, vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail;
-+ }
-+
-+ for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
-+ if (vaapi_drm_format_map[i].va_fourcc ==
-+ mapping->image.format.fourcc)
-+ break;
-+ }
-+ if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
-+ av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
-+ "VAAPI format %#x.\n", mapping->image.format.fourcc);
-+ err = AVERROR(EINVAL);
-+ goto fail_derived;
-+ }
-+
-+ mapping->buffer_info.mem_type =
-+ VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
-+
-+ mapping->drm_desc.nb_layers =
-+ vaapi_drm_format_map[i].nb_layer_formats;
-+ if (mapping->drm_desc.nb_layers > 1) {
-+ if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
-+ av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
-+ "expected format: got %d planes, but expected %d.\n",
-+ mapping->image.num_planes, mapping->drm_desc.nb_layers);
-+ err = AVERROR(EINVAL);
-+ goto fail_derived;
-+ }
-+
-+ for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
-+ mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
-+ .format = vaapi_drm_format_map[i].layer_formats[p],
-+ .nb_planes = 1,
-+ .planes[0] = {
-+ .object_index = 0,
-+ .offset = mapping->image.offsets[p],
-+ .pitch = mapping->image.pitches[p],
-+ },
-+ };
-+ }
-+ } else {
-+ mapping->drm_desc.layers[0].format =
-+ vaapi_drm_format_map[i].layer_formats[0];
-+ mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
-+ for (p = 0; p < mapping->image.num_planes; p++) {
-+ mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
-+ .object_index = 0,
-+ .offset = mapping->image.offsets[p],
-+ .pitch = mapping->image.pitches[p],
-+ };
-+ }
-+ }
-+
-+ vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
-+ &mapping->buffer_info);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
-+ "handle from image %#x (derived from surface %#x): "
-+ "%d (%s).\n", mapping->image.buf, surface_id,
-+ vas, vaErrorStr(vas));
-+ err = AVERROR(EIO);
-+ goto fail_derived;
-+ }
-+
-+ av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
-+ mapping->buffer_info.handle);
-+
-+ mapping->drm_desc.nb_objects = 1;
-+ mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
-+ .fd = mapping->buffer_info.handle,
-+ .size = mapping->image.data_size,
-+ // There is no way to get the format modifier with this API.
-+ .format_modifier = DRM_FORMAT_MOD_INVALID,
-+ };
-+
-+ err = ff_hwframe_map_create(src->hw_frames_ctx,
-+ dst, src, &vaapi_unmap_to_drm_abh,
-+ mapping);
-+ if (err < 0)
-+ goto fail_mapped;
-+
-+ dst->data[0] = (uint8_t*)&mapping->drm_desc;
-+ dst->width = src->width;
-+ dst->height = src->height;
-+
-+ return 0;
-+
-+fail_mapped:
-+ vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
-+fail_derived:
-+ vaDestroyImage(hwctx->display, mapping->image.image_id);
-+fail:
-+ av_freep(&mapping);
-+ return err;
-+}
-+#endif
-+
-+static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+#if VA_CHECK_VERSION(1, 1, 0)
-+ int err;
-+ err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
-+ if (err != AVERROR(ENOSYS))
-+ return err;
-+#endif
-+#if VA_CHECK_VERSION(0, 36, 0)
-+ return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
-+#endif
-+ return AVERROR(ENOSYS);
-+}
-+
-+#endif /* CONFIG_LIBDRM */
-+
-+static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+ switch (src->format) {
-+#if CONFIG_LIBDRM
-+ case AV_PIX_FMT_DRM_PRIME:
-+ return vaapi_map_from_drm(hwfc, dst, src, flags);
-+#endif
-+ default:
-+ return AVERROR(ENOSYS);
-+ }
-+}
-+
-+static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
-+ const AVFrame *src, int flags)
-+{
-+ switch (dst->format) {
-+#if CONFIG_LIBDRM
-+ case AV_PIX_FMT_DRM_PRIME:
-+ return vaapi_map_to_drm(hwfc, dst, src, flags);
-+#endif
-+ default:
-+ return vaapi_map_to_memory(hwfc, dst, src, flags);
-+ }
-+}
-+
-+static void vaapi_device_free(AVHWDeviceContext *ctx)
-+{
-+ AVVAAPIDeviceContext *hwctx = ctx->hwctx;
-+ VAAPIDevicePriv *priv = ctx->user_opaque;
-+
-+ if (hwctx->display)
-+ vaTerminate(hwctx->display);
-+
-+#if HAVE_VAAPI_X11
-+ if (priv->x11_display)
-+ XCloseDisplay(priv->x11_display);
-+#endif
-+
-+ if (priv->drm_fd >= 0)
-+ close(priv->drm_fd);
-+
-+ av_freep(&priv);
-+}
-+
-+#if CONFIG_VAAPI_1
-+static void vaapi_device_log_error(void *context, const char *message)
-+{
-+ AVHWDeviceContext *ctx = context;
-+
-+ av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
-+}
-+
-+static void vaapi_device_log_info(void *context, const char *message)
-+{
-+ AVHWDeviceContext *ctx = context;
-+
-+ av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
-+}
-+#endif
-+
-+static int vaapi_device_connect(AVHWDeviceContext *ctx,
-+ VADisplay display)
-+{
-+ AVVAAPIDeviceContext *hwctx = ctx->hwctx;
-+ int major, minor;
-+ VAStatus vas;
-+
-+#if CONFIG_VAAPI_1
-+ vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
-+ vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
-+#endif
-+
-+ hwctx->display = display;
-+
-+ vas = vaInitialize(display, &major, &minor);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
-+ "connection: %d (%s).\n", vas, vaErrorStr(vas));
-+ return AVERROR(EIO);
-+ }
-+ av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
-+ "version %d.%d\n", major, minor);
-+
-+ return 0;
-+}
-+
-+static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
-+ AVDictionary *opts, int flags)
-+{
-+ VAAPIDevicePriv *priv;
-+ VADisplay display = NULL;
-+ const AVDictionaryEntry *ent;
-+ int try_drm, try_x11, try_all;
-+
-+ priv = av_mallocz(sizeof(*priv));
-+ if (!priv)
-+ return AVERROR(ENOMEM);
-+
-+ priv->drm_fd = -1;
-+
-+ ctx->user_opaque = priv;
-+ ctx->free = vaapi_device_free;
-+
-+ ent = av_dict_get(opts, "connection_type", NULL, 0);
-+ if (ent) {
-+ try_all = try_drm = try_x11 = 0;
-+ if (!strcmp(ent->value, "drm")) {
-+ try_drm = 1;
-+ } else if (!strcmp(ent->value, "x11")) {
-+ try_x11 = 1;
-+ } else {
-+ av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
-+ ent->value);
-+ return AVERROR(EINVAL);
-+ }
-+ } else {
-+ try_all = 1;
-+ try_drm = HAVE_VAAPI_DRM;
-+ try_x11 = HAVE_VAAPI_X11;
-+ }
-+
-+#if HAVE_VAAPI_DRM
-+ while (!display && try_drm) {
-+ // If the device is specified, try to open it as a DRM device node.
-+ // If not, look for a usable render node, possibly restricted to those
-+ // using a specified kernel driver.
-+ int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR;
-+ if (device) {
-+ priv->drm_fd = open(device, O_RDWR);
-+ if (priv->drm_fd < 0) {
-+ av_log(ctx, loglevel, "Failed to open %s as "
-+ "DRM device node.\n", device);
-+ break;
-+ }
-+ } else {
-+ char path[64];
-+ int n, max_devices = 8;
-+#if CONFIG_LIBDRM
-+ const AVDictionaryEntry *kernel_driver;
-+ kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
-+#endif
-+ for (n = 0; n < max_devices; n++) {
-+ snprintf(path, sizeof(path),
-+ "/dev/dri/renderD%d", 128 + n);
-+ priv->drm_fd = open(path, O_RDWR);
-+ if (priv->drm_fd < 0) {
-+ av_log(ctx, AV_LOG_VERBOSE, "Cannot open "
-+ "DRM render node for device %d.\n", n);
-+ break;
-+ }
-+#if CONFIG_LIBDRM
-+ if (kernel_driver) {
-+ drmVersion *info;
-+ info = drmGetVersion(priv->drm_fd);
-+ if (strcmp(kernel_driver->value, info->name)) {
-+ av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
-+ "with non-matching kernel driver (%s).\n",
-+ n, info->name);
-+ drmFreeVersion(info);
-+ close(priv->drm_fd);
-+ priv->drm_fd = -1;
-+ continue;
-+ }
-+ av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
-+ "DRM render node for device %d, "
-+ "with matching kernel driver (%s).\n",
-+ n, info->name);
-+ drmFreeVersion(info);
-+ } else
-+#endif
-+ {
-+ av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
-+ "DRM render node for device %d.\n", n);
-+ }
-+ break;
-+ }
-+ if (n >= max_devices)
-+ break;
-+ }
-+
-+ display = vaGetDisplayDRM(priv->drm_fd);
-+ if (!display) {
-+ av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display "
-+ "from DRM device %s.\n", device);
-+ return AVERROR_EXTERNAL;
-+ }
-+ break;
-+ }
-+#endif
-+
-+#if HAVE_VAAPI_X11
-+ if (!display && try_x11) {
-+ // Try to open the device as an X11 display.
-+ priv->x11_display = XOpenDisplay(device);
-+ if (!priv->x11_display) {
-+ av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
-+ "%s.\n", XDisplayName(device));
-+ } else {
-+ display = vaGetDisplay(priv->x11_display);
-+ if (!display) {
-+ av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
-+ "from X11 display %s.\n", XDisplayName(device));
-+ return AVERROR_UNKNOWN;
-+ }
-+
-+ av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
-+ "X11 display %s.\n", XDisplayName(device));
-+ }
-+ }
-+#endif
-+
-+ if (!display) {
-+ if (device)
-+ av_log(ctx, AV_LOG_ERROR, "No VA display found for "
-+ "device %s.\n", device);
-+ else
-+ av_log(ctx, AV_LOG_ERROR, "No VA display found for "
-+ "any default device.\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ ent = av_dict_get(opts, "driver", NULL, 0);
-+ if (ent) {
-+#if VA_CHECK_VERSION(0, 38, 0)
-+ VAStatus vas;
-+ vas = vaSetDriverName(display, ent->value);
-+ if (vas != VA_STATUS_SUCCESS) {
-+ av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to "
-+ "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas));
-+ vaTerminate(display);
-+ return AVERROR_EXTERNAL;
-+ }
-+#else
-+ av_log(ctx, AV_LOG_WARNING, "Driver name setting is not "
-+ "supported with this VAAPI version.\n");
-+#endif
-+ }
-+
-+ return vaapi_device_connect(ctx, display);
-+}
-+
-+static int vaapi_device_derive(AVHWDeviceContext *ctx,
-+ AVHWDeviceContext *src_ctx, int flags)
-+{
-+#if HAVE_VAAPI_DRM
-+ if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
-+ AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
-+ VADisplay *display;
-+ VAAPIDevicePriv *priv;
-+
-+ if (src_hwctx->fd < 0) {
-+ av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
-+ "device to derive a VA display from.\n");
-+ return AVERROR(EINVAL);
-+ }
-+
-+ priv = av_mallocz(sizeof(*priv));
-+ if (!priv)
-+ return AVERROR(ENOMEM);
-+
-+ // Inherits the fd from the source context, which will close it.
-+ priv->drm_fd = -1;
-+
-+ ctx->user_opaque = priv;
-+ ctx->free = &vaapi_device_free;
-+
-+ display = vaGetDisplayDRM(src_hwctx->fd);
-+ if (!display) {
-+ av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
-+ "DRM device.\n");
-+ return AVERROR(EIO);
-+ }
-+
-+ return vaapi_device_connect(ctx, display);
-+ }
-+#endif
-+ return AVERROR(ENOSYS);
-+}
-+
-+const HWContextType ff_hwcontext_type_vaapi = {
-+ .type = AV_HWDEVICE_TYPE_VAAPI,
-+ .name = "VAAPI",
-+
-+ .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
-+ .device_priv_size = sizeof(VAAPIDeviceContext),
-+ .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
-+ .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
-+ .frames_priv_size = sizeof(VAAPIFramesContext),
-+
-+ .device_create = &vaapi_device_create,
-+ .device_derive = &vaapi_device_derive,
-+ .device_init = &vaapi_device_init,
-+ .device_uninit = &vaapi_device_uninit,
-+ .frames_get_constraints = &vaapi_frames_get_constraints,
-+ .frames_init = &vaapi_frames_init,
-+ .frames_uninit = &vaapi_frames_uninit,
-+ .frames_get_buffer = &vaapi_get_buffer,
-+ .transfer_get_formats = &vaapi_transfer_get_formats,
-+ .transfer_data_to = &vaapi_transfer_data_to,
-+ .transfer_data_from = &vaapi_transfer_data_from,
-+ .map_to = &vaapi_map_to,
-+ .map_from = &vaapi_map_from,
-+
-+ .pix_fmts = (const enum AVPixelFormat[]) {
-+ AV_PIX_FMT_VAAPI,
-+ AV_PIX_FMT_NONE
-+ },
-+};
-diff -up firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.h.ffvpx firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.h
---- firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.h.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/libavutil/hwcontext_vaapi.h 2020-12-10 20:40:53.390541394 +0100
-@@ -0,0 +1,117 @@
-+/*
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#ifndef AVUTIL_HWCONTEXT_VAAPI_H
-+#define AVUTIL_HWCONTEXT_VAAPI_H
-+
-+#include <va/va.h>
-+
-+/**
-+ * @file
-+ * API-specific header for AV_HWDEVICE_TYPE_VAAPI.
-+ *
-+ * Dynamic frame pools are supported, but note that any pool used as a render
-+ * target is required to be of fixed size in order to be be usable as an
-+ * argument to vaCreateContext().
-+ *
-+ * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs
-+ * with the data pointer set to a VASurfaceID.
-+ */
-+
-+enum {
-+ /**
-+ * The quirks field has been set by the user and should not be detected
-+ * automatically by av_hwdevice_ctx_init().
-+ */
-+ AV_VAAPI_DRIVER_QUIRK_USER_SET = (1 << 0),
-+ /**
-+ * The driver does not destroy parameter buffers when they are used by
-+ * vaRenderPicture(). Additional code will be required to destroy them
-+ * separately afterwards.
-+ */
-+ AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS = (1 << 1),
-+
-+ /**
-+ * The driver does not support the VASurfaceAttribMemoryType attribute,
-+ * so the surface allocation code will not try to use it.
-+ */
-+ AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE = (1 << 2),
-+
-+ /**
-+ * The driver does not support surface attributes at all.
-+ * The surface allocation code will never pass them to surface allocation,
-+ * and the results of the vaQuerySurfaceAttributes() call will be faked.
-+ */
-+ AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES = (1 << 3),
-+};
-+
-+/**
-+ * VAAPI connection details.
-+ *
-+ * Allocated as AVHWDeviceContext.hwctx
-+ */
-+typedef struct AVVAAPIDeviceContext {
-+ /**
-+ * The VADisplay handle, to be filled by the user.
-+ */
-+ VADisplay display;
-+ /**
-+ * Driver quirks to apply - this is filled by av_hwdevice_ctx_init(),
-+ * with reference to a table of known drivers, unless the
-+ * AV_VAAPI_DRIVER_QUIRK_USER_SET bit is already present. The user
-+ * may need to refer to this field when performing any later
-+ * operations using VAAPI with the same VADisplay.
-+ */
-+ unsigned int driver_quirks;
-+} AVVAAPIDeviceContext;
-+
-+/**
-+ * VAAPI-specific data associated with a frame pool.
-+ *
-+ * Allocated as AVHWFramesContext.hwctx.
-+ */
-+typedef struct AVVAAPIFramesContext {
-+ /**
-+ * Set by the user to apply surface attributes to all surfaces in
-+ * the frame pool. If null, default settings are used.
-+ */
-+ VASurfaceAttrib *attributes;
-+ int nb_attributes;
-+ /**
-+ * The surfaces IDs of all surfaces in the pool after creation.
-+ * Only valid if AVHWFramesContext.initial_pool_size was positive.
-+ * These are intended to be used as the render_targets arguments to
-+ * vaCreateContext().
-+ */
-+ VASurfaceID *surface_ids;
-+ int nb_surfaces;
-+} AVVAAPIFramesContext;
-+
-+/**
-+ * VAAPI hardware pipeline configuration details.
-+ *
-+ * Allocated with av_hwdevice_hwconfig_alloc().
-+ */
-+typedef struct AVVAAPIHWConfig {
-+ /**
-+ * ID of a VAAPI pipeline configuration.
-+ */
-+ VAConfigID config_id;
-+} AVVAAPIHWConfig;
-+
-+#endif /* AVUTIL_HWCONTEXT_VAAPI_H */
-diff -up firefox-84.0/media/ffvpx/libavutil/moz.build.ffvpx firefox-84.0/media/ffvpx/libavutil/moz.build
---- firefox-84.0/media/ffvpx/libavutil/moz.build.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/libavutil/moz.build 2020-12-10 20:40:53.390541394 +0100
-@@ -45,6 +45,11 @@ SOURCES += [
- 'time.c',
- 'utils.c'
- ]
-+if CONFIG['MOZ_WAYLAND']:
-+ SOURCES += [
-+ 'hwcontext_vaapi.c',
-+ ]
-+ USE_LIBS += ['mozva']
-
- if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
- SOURCES += [
-diff -up firefox-84.0/media/ffvpx/moz.build.ffvpx firefox-84.0/media/ffvpx/moz.build
---- firefox-84.0/media/ffvpx/moz.build.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/moz.build 2020-12-10 20:40:53.390541394 +0100
-@@ -11,3 +11,8 @@ DIRS += [
- 'libavutil',
- 'libavcodec'
- ]
-+
-+if CONFIG['MOZ_WAYLAND']:
-+ DIRS += [
-+ 'mozva',
-+ ]
-diff -up firefox-84.0/media/ffvpx/mozva/moz.build.ffvpx firefox-84.0/media/ffvpx/mozva/moz.build
---- firefox-84.0/media/ffvpx/mozva/moz.build.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/mozva/moz.build 2020-12-10 20:40:53.390541394 +0100
-@@ -0,0 +1,13 @@
-+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-+# vim: set filetype=python:
-+# This Source Code Form is subject to the terms of the Mozilla Public
-+# License, v. 2.0. If a copy of the MPL was not distributed with this
-+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-+
-+SOURCES += [
-+ 'mozva.c',
-+]
-+
-+LOCAL_INCLUDES += ['/media/ffvpx']
-+
-+Library('mozva')
-diff -up firefox-84.0/media/ffvpx/mozva/mozva.c.ffvpx firefox-84.0/media/ffvpx/mozva/mozva.c
---- firefox-84.0/media/ffvpx/mozva/mozva.c.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/mozva/mozva.c 2020-12-10 20:40:53.390541394 +0100
-@@ -0,0 +1,406 @@
-+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-+/* vim:expandtab:shiftwidth=4:tabstop=4:
-+ */
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+#pragma GCC visibility push(default)
-+#include <va/va.h>
-+#pragma GCC visibility pop
-+
-+#include "mozilla/Types.h"
-+#include <dlfcn.h>
-+#include <pthread.h>
-+#include <stdlib.h>
-+
-+#define GET_FUNC(func, lib) (func##Fn = dlsym(lib, #func))
-+
-+#define IS_FUNC_LOADED(func) (func##Fn != NULL)
-+
-+static VAStatus (*vaDestroyBufferFn)(VADisplay dpy, VABufferID buffer_id);
-+static VAStatus (*vaBeginPictureFn)(VADisplay dpy, VAContextID context,
-+ VASurfaceID render_target);
-+static VAStatus (*vaEndPictureFn)(VADisplay dpy, VAContextID context);
-+static VAStatus (*vaRenderPictureFn)(VADisplay dpy, VAContextID context,
-+ VABufferID* buffers, int num_buffers);
-+static int (*vaMaxNumProfilesFn)(VADisplay dpy);
-+static VAStatus (*vaCreateContextFn)(VADisplay dpy, VAConfigID config_id,
-+ int picture_width, int picture_height,
-+ int flag, VASurfaceID* render_targets,
-+ int num_render_targets,
-+ VAContextID* context /* out */);
-+static VAStatus (*vaDestroyContextFn)(VADisplay dpy, VAContextID context);
-+static VAStatus (*vaCreateBufferFn)(VADisplay dpy, VAContextID context,
-+ VABufferType type, /* in */
-+ unsigned int size, /* in */
-+ unsigned int num_elements, /* in */
-+ void* data, /* in */
-+ VABufferID* buf_id /* out */);
-+static VAStatus (*vaQuerySurfaceAttributesFn)(VADisplay dpy, VAConfigID config,
-+ VASurfaceAttrib* attrib_list,
-+ unsigned int* num_attribs);
-+static VAStatus (*vaQueryConfigProfilesFn)(VADisplay dpy,
-+ VAProfile* profile_list, /* out */
-+ int* num_profiles /* out */);
-+static const char* (*vaErrorStrFn)(VAStatus error_status);
-+static VAStatus (*vaCreateConfigFn)(VADisplay dpy, VAProfile profile,
-+ VAEntrypoint entrypoint,
-+ VAConfigAttrib* attrib_list,
-+ int num_attribs,
-+ VAConfigID* config_id /* out */);
-+static VAStatus (*vaDestroyConfigFn)(VADisplay dpy, VAConfigID config_id);
-+static int (*vaMaxNumImageFormatsFn)(VADisplay dpy);
-+static VAStatus (*vaQueryImageFormatsFn)(VADisplay dpy,
-+ VAImageFormat* format_list, /* out */
-+ int* num_formats /* out */);
-+static const char* (*vaQueryVendorStringFn)(VADisplay dpy);
-+static VAStatus (*vaDestroySurfacesFn)(VADisplay dpy, VASurfaceID* surfaces,
-+ int num_surfaces);
-+static VAStatus (*vaCreateSurfacesFn)(VADisplay dpy, unsigned int format,
-+ unsigned int width, unsigned int height,
-+ VASurfaceID* surfaces,
-+ unsigned int num_surfaces,
-+ VASurfaceAttrib* attrib_list,
-+ unsigned int num_attribs);
-+static VAStatus (*vaDeriveImageFn)(VADisplay dpy, VASurfaceID surface,
-+ VAImage* image /* out */);
-+static VAStatus (*vaDestroyImageFn)(VADisplay dpy, VAImageID image);
-+static VAStatus (*vaPutImageFn)(VADisplay dpy, VASurfaceID surface,
-+ VAImageID image, int src_x, int src_y,
-+ unsigned int src_width, unsigned int src_height,
-+ int dest_x, int dest_y, unsigned int dest_width,
-+ unsigned int dest_height);
-+static VAStatus (*vaSyncSurfaceFn)(VADisplay dpy, VASurfaceID render_target);
-+static VAStatus (*vaCreateImageFn)(VADisplay dpy, VAImageFormat* format,
-+ int width, int height,
-+ VAImage* image /* out */);
-+static VAStatus (*vaGetImageFn)(
-+ VADisplay dpy, VASurfaceID surface,
-+ int x, /* coordinates of the upper left source pixel */
-+ int y, unsigned int width, /* width and height of the region */
-+ unsigned int height, VAImageID image);
-+static VAStatus (*vaMapBufferFn)(VADisplay dpy, VABufferID buf_id, /* in */
-+ void** pbuf /* out */);
-+static VAStatus (*vaUnmapBufferFn)(VADisplay dpy, VABufferID buf_id /* in */);
-+static VAStatus (*vaTerminateFn)(VADisplay dpy);
-+static VAStatus (*vaInitializeFn)(VADisplay dpy, int* major_version, /* out */
-+ int* minor_version /* out */);
-+static VAStatus (*vaSetDriverNameFn)(VADisplay dpy, char* driver_name);
-+
-+int LoadVALibrary() {
-+ static pthread_mutex_t sVALock = PTHREAD_MUTEX_INITIALIZER;
-+ static void* sVALib = NULL;
-+ static int sVAInitialized = 0;
-+ static int sVALoaded = 0;
-+
-+ pthread_mutex_lock(&sVALock);
-+
-+ if (!sVAInitialized) {
-+ sVAInitialized = 1;
-+ sVALib = dlopen("libva.so.2", RTLD_LAZY);
-+ if (!sVALib) {
-+ pthread_mutex_unlock(&sVALock);
-+ return 0;
-+ }
-+ GET_FUNC(vaDestroyBuffer, sVALib);
-+ GET_FUNC(vaBeginPicture, sVALib);
-+ GET_FUNC(vaEndPicture, sVALib);
-+ GET_FUNC(vaRenderPicture, sVALib);
-+ GET_FUNC(vaMaxNumProfiles, sVALib);
-+ GET_FUNC(vaCreateContext, sVALib);
-+ GET_FUNC(vaDestroyContext, sVALib);
-+ GET_FUNC(vaCreateBuffer, sVALib);
-+ GET_FUNC(vaQuerySurfaceAttributes, sVALib);
-+ GET_FUNC(vaQueryConfigProfiles, sVALib);
-+ GET_FUNC(vaErrorStr, sVALib);
-+ GET_FUNC(vaCreateConfig, sVALib);
-+ GET_FUNC(vaDestroyConfig, sVALib);
-+ GET_FUNC(vaMaxNumImageFormats, sVALib);
-+ GET_FUNC(vaQueryImageFormats, sVALib);
-+ GET_FUNC(vaQueryVendorString, sVALib);
-+ GET_FUNC(vaDestroySurfaces, sVALib);
-+ GET_FUNC(vaCreateSurfaces, sVALib);
-+ GET_FUNC(vaDeriveImage, sVALib);
-+ GET_FUNC(vaDestroyImage, sVALib);
-+ GET_FUNC(vaPutImage, sVALib);
-+ GET_FUNC(vaSyncSurface, sVALib);
-+ GET_FUNC(vaCreateImage, sVALib);
-+ GET_FUNC(vaGetImage, sVALib);
-+ GET_FUNC(vaMapBuffer, sVALib);
-+ GET_FUNC(vaUnmapBuffer, sVALib);
-+ GET_FUNC(vaTerminate, sVALib);
-+ GET_FUNC(vaInitialize, sVALib);
-+ GET_FUNC(vaSetDriverName, sVALib);
-+
-+ sVALoaded =
-+ (IS_FUNC_LOADED(vaDestroyBuffer) && IS_FUNC_LOADED(vaBeginPicture) &&
-+ IS_FUNC_LOADED(vaEndPicture) && IS_FUNC_LOADED(vaRenderPicture) &&
-+ IS_FUNC_LOADED(vaMaxNumProfiles) && IS_FUNC_LOADED(vaCreateContext) &&
-+ IS_FUNC_LOADED(vaDestroyContext) && IS_FUNC_LOADED(vaCreateBuffer) &&
-+ IS_FUNC_LOADED(vaQuerySurfaceAttributes) &&
-+ IS_FUNC_LOADED(vaQueryConfigProfiles) && IS_FUNC_LOADED(vaErrorStr) &&
-+ IS_FUNC_LOADED(vaCreateConfig) && IS_FUNC_LOADED(vaDestroyConfig) &&
-+ IS_FUNC_LOADED(vaMaxNumImageFormats) &&
-+ IS_FUNC_LOADED(vaQueryImageFormats) &&
-+ IS_FUNC_LOADED(vaQueryVendorString) &&
-+ IS_FUNC_LOADED(vaDestroySurfaces) &&
-+ IS_FUNC_LOADED(vaCreateSurfaces) && IS_FUNC_LOADED(vaDeriveImage) &&
-+ IS_FUNC_LOADED(vaDestroyImage) && IS_FUNC_LOADED(vaPutImage) &&
-+ IS_FUNC_LOADED(vaSyncSurface) && IS_FUNC_LOADED(vaCreateImage) &&
-+ IS_FUNC_LOADED(vaGetImage) && IS_FUNC_LOADED(vaMapBuffer) &&
-+ IS_FUNC_LOADED(vaUnmapBuffer) && IS_FUNC_LOADED(vaTerminate) &&
-+ IS_FUNC_LOADED(vaInitialize) && IS_FUNC_LOADED(vaSetDriverName));
-+ }
-+ pthread_mutex_unlock(&sVALock);
-+ return sVALoaded;
-+}
-+
-+#pragma GCC visibility push(default)
-+
-+VAStatus vaDestroyBuffer(VADisplay dpy, VABufferID buffer_id) {
-+ if (LoadVALibrary()) {
-+ return vaDestroyBufferFn(dpy, buffer_id);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaBeginPicture(VADisplay dpy, VAContextID context,
-+ VASurfaceID render_target) {
-+ if (LoadVALibrary()) {
-+ return vaBeginPictureFn(dpy, context, render_target);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaEndPicture(VADisplay dpy, VAContextID context) {
-+ if (LoadVALibrary()) {
-+ return vaEndPictureFn(dpy, context);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaRenderPicture(VADisplay dpy, VAContextID context,
-+ VABufferID* buffers, int num_buffers) {
-+ if (LoadVALibrary()) {
-+ return vaRenderPictureFn(dpy, context, buffers, num_buffers);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+int vaMaxNumProfiles(VADisplay dpy) {
-+ if (LoadVALibrary()) {
-+ return vaMaxNumProfilesFn(dpy);
-+ }
-+ return 0;
-+}
-+
-+VAStatus vaCreateContext(VADisplay dpy, VAConfigID config_id, int picture_width,
-+ int picture_height, int flag,
-+ VASurfaceID* render_targets, int num_render_targets,
-+ VAContextID* context /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaCreateContextFn(dpy, config_id, picture_width, picture_height,
-+ flag, render_targets, num_render_targets, context);
-+ }
-+ *context = 0;
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaDestroyContext(VADisplay dpy, VAContextID context) {
-+ if (LoadVALibrary()) {
-+ return vaDestroyContextFn(dpy, context);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaCreateBuffer(VADisplay dpy, VAContextID context,
-+ VABufferType type, /* in */
-+ unsigned int size, /* in */
-+ unsigned int num_elements, /* in */
-+ void* data, /* in */
-+ VABufferID* buf_id /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaCreateBufferFn(dpy, context, type, size, num_elements, data,
-+ buf_id);
-+ }
-+ *buf_id = 0;
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaQuerySurfaceAttributes(VADisplay dpy, VAConfigID config,
-+ VASurfaceAttrib* attrib_list,
-+ unsigned int* num_attribs) {
-+ if (LoadVALibrary()) {
-+ return vaQuerySurfaceAttributesFn(dpy, config, attrib_list, num_attribs);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaQueryConfigProfiles(VADisplay dpy, VAProfile* profile_list, /* out */
-+ int* num_profiles /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaQueryConfigProfilesFn(dpy, profile_list, num_profiles);
-+ }
-+ *num_profiles = 0;
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+const char* vaErrorStr(VAStatus error_status) {
-+ if (LoadVALibrary()) {
-+ return vaErrorStrFn(error_status);
-+ }
-+ static char tmp[] = "Unimplemented";
-+ return tmp;
-+}
-+
-+VAStatus vaCreateConfig(VADisplay dpy, VAProfile profile,
-+ VAEntrypoint entrypoint, VAConfigAttrib* attrib_list,
-+ int num_attribs, VAConfigID* config_id /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaCreateConfigFn(dpy, profile, entrypoint, attrib_list, num_attribs,
-+ config_id);
-+ }
-+ *config_id = 0;
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaDestroyConfig(VADisplay dpy, VAConfigID config_id) {
-+ if (LoadVALibrary()) {
-+ return vaDestroyConfigFn(dpy, config_id);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+int vaMaxNumImageFormats(VADisplay dpy) {
-+ if (LoadVALibrary()) {
-+ return vaMaxNumImageFormatsFn(dpy);
-+ }
-+ return 0;
-+}
-+
-+VAStatus vaQueryImageFormats(VADisplay dpy, VAImageFormat* format_list,
-+ int* num_formats) {
-+ if (LoadVALibrary()) {
-+ return vaQueryImageFormatsFn(dpy, format_list, num_formats);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+const char* vaQueryVendorString(VADisplay dpy) {
-+ if (LoadVALibrary()) {
-+ return vaQueryVendorStringFn(dpy);
-+ }
-+ return NULL;
-+}
-+
-+VAStatus vaDestroySurfaces(VADisplay dpy, VASurfaceID* surfaces,
-+ int num_surfaces) {
-+ if (LoadVALibrary()) {
-+ return vaDestroySurfacesFn(dpy, surfaces, num_surfaces);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaCreateSurfaces(VADisplay dpy, unsigned int format,
-+ unsigned int width, unsigned int height,
-+ VASurfaceID* surfaces, unsigned int num_surfaces,
-+ VASurfaceAttrib* attrib_list,
-+ unsigned int num_attribs) {
-+ if (LoadVALibrary()) {
-+ return vaCreateSurfacesFn(dpy, format, width, height, surfaces,
-+ num_surfaces, attrib_list, num_attribs);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaDeriveImage(VADisplay dpy, VASurfaceID surface,
-+ VAImage* image /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaDeriveImageFn(dpy, surface, image);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaDestroyImage(VADisplay dpy, VAImageID image) {
-+ if (LoadVALibrary()) {
-+ return vaDestroyImageFn(dpy, image);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaPutImage(VADisplay dpy, VASurfaceID surface, VAImageID image,
-+ int src_x, int src_y, unsigned int src_width,
-+ unsigned int src_height, int dest_x, int dest_y,
-+ unsigned int dest_width, unsigned int dest_height) {
-+ if (LoadVALibrary()) {
-+ return vaPutImageFn(dpy, surface, image, src_x, src_y, src_width,
-+ src_height, dest_x, dest_y, dest_width, dest_height);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaSyncSurface(VADisplay dpy, VASurfaceID render_target) {
-+ if (LoadVALibrary()) {
-+ return vaSyncSurfaceFn(dpy, render_target);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaCreateImage(VADisplay dpy, VAImageFormat* format, int width,
-+ int height, VAImage* image /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaCreateImageFn(dpy, format, width, height, image);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaGetImage(VADisplay dpy, VASurfaceID surface,
-+ int x, /* coordinates of the upper left source pixel */
-+ int y,
-+ unsigned int width, /* width and height of the region */
-+ unsigned int height, VAImageID image) {
-+ if (LoadVALibrary()) {
-+ return vaGetImageFn(dpy, surface, x, y, width, height, image);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaMapBuffer(VADisplay dpy, VABufferID buf_id, /* in */
-+ void** pbuf /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaMapBufferFn(dpy, buf_id, pbuf);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaUnmapBuffer(VADisplay dpy, VABufferID buf_id /* in */) {
-+ if (LoadVALibrary()) {
-+ return vaUnmapBufferFn(dpy, buf_id);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaTerminate(VADisplay dpy) {
-+ if (LoadVALibrary()) {
-+ return vaTerminateFn(dpy);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaInitialize(VADisplay dpy, int* major_version, /* out */
-+ int* minor_version /* out */) {
-+ if (LoadVALibrary()) {
-+ return vaInitializeFn(dpy, major_version, minor_version);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+VAStatus vaSetDriverName(VADisplay dpy, char* driver_name) {
-+ if (LoadVALibrary()) {
-+ return vaSetDriverNameFn(dpy, driver_name);
-+ }
-+ return VA_STATUS_ERROR_UNIMPLEMENTED;
-+}
-+
-+#pragma GCC visibility pop
-diff -up firefox-84.0/media/ffvpx/README_MOZILLA.ffvpx firefox-84.0/media/ffvpx/README_MOZILLA
---- firefox-84.0/media/ffvpx/README_MOZILLA.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/README_MOZILLA 2020-12-10 20:40:53.390541394 +0100
-@@ -56,3 +56,5 @@ $ for i in `cat $PATH_CENTRAL/media/ffvp
- Then apply patch.diff on the ffvpx tree.
-
- Compilation will reveal if any files are missing.
-+
-+Apply linux-vaapi-build.patch patch to enable build VA-API support for Linux.
-diff -up firefox-84.0/media/ffvpx/va/README.ffvpx firefox-84.0/media/ffvpx/va/README
---- firefox-84.0/media/ffvpx/va/README.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/va/README 2020-12-10 20:40:53.390541394 +0100
-@@ -0,0 +1,2 @@
-+There are libva headers from libva 1.7.0 used to build vaapi support for in-tree ffvpx.
-+Apply va.patch when you update it to new versions.
-\ No newline at end of file
-diff -up firefox-84.0/media/ffvpx/va/va_dec_vp8.h.ffvpx firefox-84.0/media/ffvpx/va/va_dec_vp8.h
---- firefox-84.0/media/ffvpx/va/va_dec_vp8.h.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/va/va_dec_vp8.h 2020-12-10 20:40:53.390541394 +0100
-@@ -0,0 +1,254 @@
-+/*
-+ * Copyright (c) 2007-2012 Intel Corporation. All Rights Reserved.
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-+ * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE LIABLE FOR
-+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+
-+/**
-+ * \file va_dec_vp.h
-+ * \brief VP8 decoding API
-+ *
-+ * This file contains the \ref api_dec_vp8 "VP8 decoding API".
-+ */
-+
-+#ifndef VA_DEC_VP8_H
-+#define VA_DEC_VP8_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * \defgroup api_dec_vp8 VP8 decoding API
-+ *
-+ * @{
-+ */
-+
-+/**
-+ * \brief VPX Bool Coder Context structure
-+ *
-+ * This common structure is defined for potential sharing by other VP formats
-+ *
-+ */
-+typedef struct _VABoolCoderContextVPX
-+{
-+ /* partition 0 "range" */
-+ uint8_t range;
-+ /* partition 0 "value" */
-+ uint8_t value;
-+ /*
-+ * 'partition 0 number of shifts before an output byte is available'
-+ * it is the number of remaining bits in 'value' for decoding, range [0, 7].
-+ */
-+
-+ uint8_t count;
-+} VABoolCoderContextVPX;
-+
-+/**
-+ * \brief VP8 Decoding Picture Parameter Buffer Structure
-+ *
-+ * This structure conveys frame level parameters and should be sent once
-+ * per frame.
-+ *
-+ */
-+typedef struct _VAPictureParameterBufferVP8
-+{
-+ /* frame width in pixels */
-+ uint32_t frame_width;
-+ /* frame height in pixels */
-+ uint32_t frame_height;
-+
-+ /* specifies the "last" reference frame */
-+ VASurfaceID last_ref_frame;
-+ /* specifies the "golden" reference frame */
-+ VASurfaceID golden_ref_frame;
-+ /* specifies the "alternate" referrence frame */
-+ VASurfaceID alt_ref_frame;
-+ /* specifies the out-of-loop deblocked frame, not used currently */
-+ VASurfaceID out_of_loop_frame;
-+
-+ union {
-+ struct {
-+ /* same as key_frame in bitstream syntax, 0 means a key frame */
-+ uint32_t key_frame : 1;
-+ /* same as version in bitstream syntax */
-+ uint32_t version : 3;
-+ /* same as segmentation_enabled in bitstream syntax */
-+ uint32_t segmentation_enabled : 1;
-+ /* same as update_mb_segmentation_map in bitstream syntax */
-+ uint32_t update_mb_segmentation_map : 1;
-+ /* same as update_segment_feature_data in bitstream syntax */
-+ uint32_t update_segment_feature_data : 1;
-+ /* same as filter_type in bitstream syntax */
-+ uint32_t filter_type : 1;
-+ /* same as sharpness_level in bitstream syntax */
-+ uint32_t sharpness_level : 3;
-+ /* same as loop_filter_adj_enable in bitstream syntax */
-+ uint32_t loop_filter_adj_enable : 1;
-+ /* same as mode_ref_lf_delta_update in bitstream syntax */
-+ uint32_t mode_ref_lf_delta_update : 1;
-+ /* same as sign_bias_golden in bitstream syntax */
-+ uint32_t sign_bias_golden : 1;
-+ /* same as sign_bias_alternate in bitstream syntax */
-+ uint32_t sign_bias_alternate : 1;
-+ /* same as mb_no_coeff_skip in bitstream syntax */
-+ uint32_t mb_no_coeff_skip : 1;
-+ /* flag to indicate that loop filter should be disabled */
-+ uint32_t loop_filter_disable : 1;
-+ } bits;
-+ uint32_t value;
-+ } pic_fields;
-+
-+ /*
-+ * probabilities of the segment_id decoding tree and same as
-+ * mb_segment_tree_probs in the spec.
-+ */
-+ uint8_t mb_segment_tree_probs[3];
-+
-+ /* Post-adjustment loop filter levels for the 4 segments */
-+ uint8_t loop_filter_level[4];
-+ /* loop filter deltas for reference frame based MB level adjustment */
-+ int8_t loop_filter_deltas_ref_frame[4];
-+ /* loop filter deltas for coding mode based MB level adjustment */
-+ int8_t loop_filter_deltas_mode[4];
-+
-+ /* same as prob_skip_false in bitstream syntax */
-+ uint8_t prob_skip_false;
-+ /* same as prob_intra in bitstream syntax */
-+ uint8_t prob_intra;
-+ /* same as prob_last in bitstream syntax */
-+ uint8_t prob_last;
-+ /* same as prob_gf in bitstream syntax */
-+ uint8_t prob_gf;
-+
-+ /*
-+ * list of 4 probabilities of the luma intra prediction mode decoding
-+ * tree and same as y_mode_probs in frame header
-+ */
-+ uint8_t y_mode_probs[4];
-+ /*
-+ * list of 3 probabilities of the chroma intra prediction mode decoding
-+ * tree and same as uv_mode_probs in frame header
-+ */
-+ uint8_t uv_mode_probs[3];
-+ /*
-+ * updated mv decoding probabilities and same as mv_probs in
-+ * frame header
-+ */
-+ uint8_t mv_probs[2][19];
-+
-+ VABoolCoderContextVPX bool_coder_ctx;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAPictureParameterBufferVP8;
-+
-+/**
-+ * \brief VP8 Slice Parameter Buffer Structure
-+ *
-+ * This structure conveys parameters related to data partitions and should be
-+ * sent once per frame. Slice data buffer of VASliceDataBufferType is used
-+ * to send the partition data.
-+ *
-+ */
-+typedef struct _VASliceParameterBufferVP8
-+{
-+ /*
-+ * number of bytes in the slice data buffer for the partitions
-+ */
-+ uint32_t slice_data_size;
-+ /*
-+ * offset to the first byte of partition data (control partition)
-+ */
-+ uint32_t slice_data_offset;
-+ /*
-+ * see VA_SLICE_DATA_FLAG_XXX definitions
-+ */
-+ uint32_t slice_data_flag;
-+ /*
-+ * offset to the first bit of MB from the first byte of partition data(slice_data_offset)
-+ */
-+ uint32_t macroblock_offset;
-+
-+ /*
-+ * Partitions
-+ * (1<<log2_nbr_of_dct_partitions)+1, count both control partition (frame header) and toke partition
-+ */
-+ uint8_t num_of_partitions;
-+ /*
-+ * partition_size[0] is remaining bytes of control partition after parsed by application.
-+ * exclude current byte for the remaining bits in bool_coder_ctx.
-+ * exclude the uncompress data chunk since first_part_size 'excluding the uncompressed data chunk'
-+ */
-+ uint32_t partition_size[9];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VASliceParameterBufferVP8;
-+
-+/**
-+ * \brief VP8 Coefficient Probability Data Buffer Structure
-+ *
-+ * Contains the contents of the token probability table, which may be
-+ * incrementally modified in the frame header. There are four dimensions to
-+ * the token probability array. The outermost dimension is indexed by the
-+ * type of plane being decoded; the next dimension is selected by the
-+ * position of the coefficient being decoded; the third dimension, * roughly
-+ * speaking, measures the "local complexity" or extent to which nearby
-+ * coefficients are non-zero; the fourth, and final, dimension of the token
-+ * probability array is indexed by the position in the token tree structure,
-+ * as are all tree probability arrays. This structure is sent once per frame.
-+ *
-+ */
-+typedef struct _VAProbabilityDataBufferVP8
-+{
-+ uint8_t dct_coeff_probs[4][8][3][11];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAProbabilityDataBufferVP8;
-+
-+/**
-+ * \brief VP8 Inverse Quantization Matrix Buffer Structure
-+ *
-+ * Contains quantization indices for yac(0),ydc(1),y2dc(2),y2ac(3),uvdc(4),
-+ * uvac(5) for each segment (0-3). When segmentation is disabled, only
-+ * quantization_index[0][] will be used. This structure is sent once per frame.
-+ */
-+typedef struct _VAIQMatrixBufferVP8
-+{
-+ /*
-+ * array first dimensional is segment and 2nd dimensional is Q index
-+ * all Q indexs should be clipped to be range [0, 127]
-+ */
-+ uint16_t quantization_index[4][6];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAIQMatrixBufferVP8;
-+
-+/**@}*/
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* VA_DEC_VP8_H */
-diff -up firefox-84.0/media/ffvpx/va/va_dec_vp9.h.ffvpx firefox-84.0/media/ffvpx/va/va_dec_vp9.h
---- firefox-84.0/media/ffvpx/va/va_dec_vp9.h.ffvpx 2020-12-10 20:40:53.390541394 +0100
-+++ firefox-84.0/media/ffvpx/va/va_dec_vp9.h 2020-12-10 20:40:53.390541394 +0100
-@@ -0,0 +1,319 @@
-+/*
-+ * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-+ * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE LIABLE FOR
-+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+
-+/**
-+ * \file va_dec_vp9.h
-+ * \brief The VP9 decoding API
-+ *
-+ * This file contains the \ref api_dec_vp9 "VP9 decoding API".
-+ */
-+
-+#ifndef VA_DEC_VP9_H
-+#define VA_DEC_VP9_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * \defgroup api_dec_vp9 VP9 decoding API
-+ *
-+ * This VP9 decoding API supports 8-bit 420 format only.
-+ *
-+ * @{
-+ */
-+
-+
-+
-+
-+/**
-+ * \brief VP9 Decoding Picture Parameter Buffer Structure
-+ *
-+ * This structure conveys picture level parameters.
-+ * App should send a surface with this data structure down to VAAPI once
-+ * per frame.
-+ *
-+ */
-+typedef struct _VADecPictureParameterBufferVP9
-+{
-+ /** \brief picture width
-+ * Picture original resolution. The value may not be multiple of 8.
-+ */
-+ uint16_t frame_width;
-+ /** \brief picture height
-+ * Picture original resolution. The value may not be multiple of 8.
-+ */
-+ uint16_t frame_height;
-+
-+ /** \brief Surface indices of reference frames in DPB.
-+ *
-+ * Each entry of the list specifies the surface index of the picture
-+ * that is referred by current picture or will be referred by any future
-+ * picture.
-+ * Application who calls this API should update this list based on the
-+ * refreshing information from VP9 bitstream.
-+ */
-+ VASurfaceID reference_frames[8];
-+
-+ union
-+ {
-+ struct
-+ {
-+ /** \brief flags for current picture
-+ * same syntax and semantic as those in VP9 code
-+ */
-+ uint32_t subsampling_x : 1;
-+ uint32_t subsampling_y : 1;
-+ uint32_t frame_type : 1;
-+ uint32_t show_frame : 1;
-+ uint32_t error_resilient_mode : 1;
-+ uint32_t intra_only : 1;
-+ uint32_t allow_high_precision_mv : 1;
-+ uint32_t mcomp_filter_type : 3;
-+ uint32_t frame_parallel_decoding_mode : 1;
-+ uint32_t reset_frame_context : 2;
-+ uint32_t refresh_frame_context : 1;
-+ uint32_t frame_context_idx : 2;
-+ uint32_t segmentation_enabled : 1;
-+
-+ /** \brief corresponds to variable temporal_update in VP9 code.
-+ */
-+ uint32_t segmentation_temporal_update : 1;
-+ /** \brief corresponds to variable update_mb_segmentation_map
-+ * in VP9 code.
-+ */
-+ uint32_t segmentation_update_map : 1;
-+
-+ /** \brief Index of reference_frames[] and points to the
-+ * LAST reference frame.
-+ * It corresponds to active_ref_idx[0] in VP9 code.
-+ */
-+ uint32_t last_ref_frame : 3;
-+ /** \brief Sign Bias of the LAST reference frame.
-+ * It corresponds to ref_frame_sign_bias[LAST_FRAME] in VP9 code.
-+ */
-+ uint32_t last_ref_frame_sign_bias : 1;
-+ /** \brief Index of reference_frames[] and points to the
-+ * GOLDERN reference frame.
-+ * It corresponds to active_ref_idx[1] in VP9 code.
-+ */
-+ uint32_t golden_ref_frame : 3;
-+ /** \brief Sign Bias of the GOLDERN reference frame.
-+ * Corresponds to ref_frame_sign_bias[GOLDERN_FRAME] in VP9 code.
-+ */
-+ uint32_t golden_ref_frame_sign_bias : 1;
-+ /** \brief Index of reference_frames[] and points to the
-+ * ALTERNATE reference frame.
-+ * Corresponds to active_ref_idx[2] in VP9 code.
-+ */
-+ uint32_t alt_ref_frame : 3;
-+ /** \brief Sign Bias of the ALTERNATE reference frame.
-+ * Corresponds to ref_frame_sign_bias[ALTREF_FRAME] in VP9 code.
-+ */
-+ uint32_t alt_ref_frame_sign_bias : 1;
-+ /** \brief Lossless Mode
-+ * LosslessFlag = base_qindex == 0 &&
-+ * y_dc_delta_q == 0 &&
-+ * uv_dc_delta_q == 0 &&
-+ * uv_ac_delta_q == 0;
-+ * Where base_qindex, y_dc_delta_q, uv_dc_delta_q and uv_ac_delta_q
-+ * are all variables in VP9 code.
-+ */
-+ uint32_t lossless_flag : 1;
-+ } bits;
-+ uint32_t value;
-+ } pic_fields;
-+
-+ /* following parameters have same syntax with those in VP9 code */
-+ uint8_t filter_level;
-+ uint8_t sharpness_level;
-+
-+ /** \brief number of tile rows specified by (1 << log2_tile_rows).
-+ * It corresponds the variable with same name in VP9 code.
-+ */
-+ uint8_t log2_tile_rows;
-+ /** \brief number of tile columns specified by (1 << log2_tile_columns).
-+ * It corresponds the variable with same name in VP9 code.
-+ */
-+ uint8_t log2_tile_columns;
-+ /** \brief Number of bytes taken up by the uncompressed frame header,
-+ * which corresponds to byte length of function
-+ * read_uncompressed_header() in VP9 code.
-+ * Specifically, it is the byte count from bit stream buffer start to
-+ * the last byte of uncompressed frame header.
-+ * If there are other meta data in the buffer before uncompressed header,
-+ * its size should be also included here.
-+ */
-+ uint8_t frame_header_length_in_bytes;
-+
-+ /** \brief The byte count of compressed header the bitstream buffer,
-+ * which corresponds to syntax first_partition_size in code.
-+ */
-+ uint16_t first_partition_size;
-+
-+ /** These values are segment probabilities with same names in VP9
-+ * function setup_segmentation(). They should be parsed directly from
-+ * bitstream by application.
-+ */
-+ uint8_t mb_segment_tree_probs[7];
-+ uint8_t segment_pred_probs[3];
-+
-+ /** \brief VP9 Profile definition
-+ * value range [0..3].
-+ */
-+ uint8_t profile;
-+
-+ /** \brief VP9 bit depth per sample
-+ * same for both luma and chroma samples.
-+ */
-+ uint8_t bit_depth;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_MEDIUM];
-+
-+} VADecPictureParameterBufferVP9;
-+
-+
-+
-+/**
-+ * \brief VP9 Segmentation Parameter Data Structure
-+ *
-+ * This structure conveys per segment parameters.
-+ * 8 of this data structure will be included in VASegmentationParameterBufferVP9
-+ * and sent to API in a single buffer.
-+ *
-+ */
-+typedef struct _VASegmentParameterVP9
-+{
-+ union
-+ {
-+ struct
-+ {
-+ /** \brief Indicates if per segment reference frame indicator
-+ * is enabled.
-+ * Corresponding to variable feature_enabled when
-+ * j == SEG_LVL_REF_FRAME in function setup_segmentation() VP9 code.
-+ */
-+ uint16_t segment_reference_enabled : 1;
-+ /** \brief Specifies per segment reference indication.
-+ * 0: reserved
-+ * 1: Last ref
-+ * 2: golden
-+ * 3: altref
-+ * Value can be derived from variable data when
-+ * j == SEG_LVL_REF_FRAME in function setup_segmentation() VP9 code.
-+ */
-+ uint16_t segment_reference : 2;
-+ /** \brief Indicates if per segment skip feature is enabled.
-+ * Corresponding to variable feature_enabled when
-+ * j == SEG_LVL_SKIP in function setup_segmentation() VP9 code.
-+ */
-+ uint16_t segment_reference_skipped : 1;
-+ } fields;
-+ uint16_t value;
-+ } segment_flags;
-+
-+ /** \brief Specifies the filter level information per segment.
-+ * The value corresponds to variable lfi->lvl[seg][ref][mode] in VP9 code,
-+ * where m is [ref], and n is [mode] in FilterLevel[m][n].
-+ */
-+ uint8_t filter_level[4][2];
-+ /** \brief Specifies per segment Luma AC quantization scale.
-+ * Corresponding to y_dequant[qindex][1] in vp9_mb_init_quantizer()
-+ * function of VP9 code.
-+ */
-+ int16_t luma_ac_quant_scale;
-+ /** \brief Specifies per segment Luma DC quantization scale.
-+ * Corresponding to y_dequant[qindex][0] in vp9_mb_init_quantizer()
-+ * function of VP9 code.
-+ */
-+ int16_t luma_dc_quant_scale;
-+ /** \brief Specifies per segment Chroma AC quantization scale.
-+ * Corresponding to uv_dequant[qindex][1] in vp9_mb_init_quantizer()
-+ * function of VP9 code.
-+ */
-+ int16_t chroma_ac_quant_scale;
-+ /** \brief Specifies per segment Chroma DC quantization scale.
-+ * Corresponding to uv_dequant[qindex][0] in vp9_mb_init_quantizer()
-+ * function of VP9 code.
-+ */
-+ int16_t chroma_dc_quant_scale;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+
-+} VASegmentParameterVP9;
-+
-+
-+
-+/**
-+ * \brief VP9 Slice Parameter Buffer Structure
-+ *
-+ * This structure conveys parameters related to segmentation data and should be
-+ * sent once per frame.
-+ *
-+ * When segmentation is disabled, only SegParam[0] has valid values,
-+ * all other entries should be populated with 0.
-+ * Otherwise, all eight entries should be valid.
-+ *
-+ * Slice data buffer of VASliceDataBufferType is used
-+ * to send the bitstream which should include whole or part of partition 0
-+ * (at least compressed header) to the end of frame.
-+ *
-+ */
-+typedef struct _VASliceParameterBufferVP9
-+{
-+ /** \brief The byte count of current frame in the bitstream buffer,
-+ * starting from first byte of the buffer.
-+ * It uses the name slice_data_size to be consitent with other codec,
-+ * but actually means frame_data_size.
-+ */
-+ uint32_t slice_data_size;
-+ /**
-+ * offset to the first byte of partition data (control partition)
-+ */
-+ uint32_t slice_data_offset;
-+ /**
-+ * see VA_SLICE_DATA_FLAG_XXX definitions
-+ */
-+ uint32_t slice_data_flag;
-+
-+ /**
-+ * \brief per segment information
-+ */
-+ VASegmentParameterVP9 seg_param[8];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+
-+} VASliceParameterBufferVP9;
-+
-+
-+/**@}*/
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* VA_DEC_VP9_H */
-diff -up firefox-84.0/media/ffvpx/va/va.h.ffvpx firefox-84.0/media/ffvpx/va/va.h
---- firefox-84.0/media/ffvpx/va/va.h.ffvpx 2020-12-10 20:40:53.391541423 +0100
-+++ firefox-84.0/media/ffvpx/va/va.h 2020-12-10 20:40:53.391541423 +0100
-@@ -0,0 +1,4636 @@
-+/*
-+ * Copyright (c) 2007-2009 Intel Corporation. All Rights Reserved.
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-+ * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE LIABLE FOR
-+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+/*
-+ * Video Acceleration (VA) API Specification
-+ *
-+ * Rev. 0.30
-+ * <jonathan.bian@intel.com>
-+ *
-+ * Revision History:
-+ * rev 0.10 (12/10/2006 Jonathan Bian) - Initial draft
-+ * rev 0.11 (12/15/2006 Jonathan Bian) - Fixed some errors
-+ * rev 0.12 (02/05/2007 Jonathan Bian) - Added VC-1 data structures for slice level decode
-+ * rev 0.13 (02/28/2007 Jonathan Bian) - Added GetDisplay()
-+ * rev 0.14 (04/13/2007 Jonathan Bian) - Fixed MPEG-2 PictureParameter structure, cleaned up a few funcs.
-+ * rev 0.15 (04/20/2007 Jonathan Bian) - Overhauled buffer management
-+ * rev 0.16 (05/02/2007 Jonathan Bian) - Added error codes and fixed some issues with configuration
-+ * rev 0.17 (05/07/2007 Jonathan Bian) - Added H.264/AVC data structures for slice level decode.
-+ * rev 0.18 (05/14/2007 Jonathan Bian) - Added data structures for MPEG-4 slice level decode
-+ * and MPEG-2 motion compensation.
-+ * rev 0.19 (08/06/2007 Jonathan Bian) - Removed extra type for bitplane data.
-+ * rev 0.20 (08/08/2007 Jonathan Bian) - Added missing fields to VC-1 PictureParameter structure.
-+ * rev 0.21 (08/20/2007 Jonathan Bian) - Added image and subpicture support.
-+ * rev 0.22 (08/27/2007 Jonathan Bian) - Added support for chroma-keying and global alpha.
-+ * rev 0.23 (09/11/2007 Jonathan Bian) - Fixed some issues with images and subpictures.
-+ * rev 0.24 (09/18/2007 Jonathan Bian) - Added display attributes.
-+ * rev 0.25 (10/18/2007 Jonathan Bian) - Changed to use IDs only for some types.
-+ * rev 0.26 (11/07/2007 Waldo Bastian) - Change vaCreateBuffer semantics
-+ * rev 0.27 (11/19/2007 Matt Sottek) - Added DeriveImage
-+ * rev 0.28 (12/06/2007 Jonathan Bian) - Added new versions of PutImage and AssociateSubpicture
-+ * to enable scaling
-+ * rev 0.29 (02/07/2008 Jonathan Bian) - VC1 parameter fixes,
-+ * added VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED
-+ * rev 0.30 (03/01/2009 Jonathan Bian) - Added encoding support for H.264 BP and MPEG-4 SP and fixes
-+ * for ISO C conformance.
-+ * rev 0.31 (09/02/2009 Gwenole Beauchesne) - VC-1/H264 fields change for VDPAU and XvBA backend
-+ * Application needs to relink with the new library.
-+ *
-+ * rev 0.31.1 (03/29/2009) - Data structure for JPEG encode
-+ * rev 0.31.2 (01/13/2011 Anthony Pabon)- Added a flag to indicate Subpicture coordinates are screen
-+ * screen relative rather than source video relative.
-+ * rev 0.32.0 (01/13/2011 Xiang Haihao) - Add profile into VAPictureParameterBufferVC1
-+ * update VAAPI to 0.32.0
-+ *
-+ * Acknowledgements:
-+ * Some concepts borrowed from XvMC and XvImage.
-+ * Waldo Bastian (Intel), Matt Sottek (Intel), Austin Yuan (Intel), and Gwenole Beauchesne (SDS)
-+ * contributed to various aspects of the API.
-+ */
-+
-+/**
-+ * \file va.h
-+ * \brief The Core API
-+ *
-+ * This file contains the \ref api_core "Core API".
-+ */
-+
-+#ifndef _VA_H_
-+#define _VA_H_
-+
-+#include <stddef.h>
-+#include <stdint.h>
-+#include "va_version.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#if defined(__GNUC__) && !defined(__COVERITY__)
-+#define va_deprecated __attribute__((deprecated))
-+#if __GNUC__ >= 6
-+#define va_deprecated_enum va_deprecated
-+#else
-+#define va_deprecated_enum
-+#endif
-+#else
-+#define va_deprecated
-+#define va_deprecated_enum
-+#endif
-+
-+/**
-+ * \mainpage Video Acceleration (VA) API
-+ *
-+ * \section intro Introduction
-+ *
-+ * The main motivation for VA-API (Video Acceleration API) is to
-+ * enable hardware accelerated video decode and encode at various
-+ * entry-points (VLD, IDCT, Motion Compensation etc.) for the
-+ * prevailing coding standards today (MPEG-2, MPEG-4 ASP/H.263, MPEG-4
-+ * AVC/H.264, VC-1/VMW3, and JPEG, HEVC/H265, VP8, VP9) and video pre/post
-+ * processing
-+ *
-+ * VA-API is split into several modules:
-+ * - \ref api_core
-+ * - Encoder (H264, HEVC, JPEG, MPEG2, VP8, VP9)
-+ * - \ref api_enc_h264
-+ * - \ref api_enc_hevc
-+ * - \ref api_enc_jpeg
-+ * - \ref api_enc_mpeg2
-+ * - \ref api_enc_vp8
-+ * - \ref api_enc_vp9
-+ * - Decoder (HEVC, JPEG, VP8, VP9)
-+ * - \ref api_dec_hevc
-+ * - \ref api_dec_jpeg
-+ * - \ref api_dec_vp8
-+ * - \ref api_dec_vp9
-+ * - \ref api_vpp
-+ * - FEI (H264, HEVC)
-+ * - \ref api_fei
-+ * - \ref api_fei_h264
-+ * - \ref api_fei_hevc
-+ */
-+
-+/**
-+ * \defgroup api_core Core API
-+ *
-+ * @{
-+ */
-+
-+/**
-+Overview
-+
-+The VA API is intended to provide an interface between a video decode/encode/processing
-+application (client) and a hardware accelerator (server), to off-load
-+video decode/encode/processing operations from the host to the hardware accelerator at various
-+entry-points.
-+
-+The basic operation steps are:
-+
-+- Negotiate a mutually acceptable configuration with the server to lock
-+ down profile, entrypoints, and other attributes that will not change on
-+ a frame-by-frame basis.
-+- Create a video decode, encode or processing context which represents a
-+ "virtualized" hardware device
-+- Get and fill the render buffers with the corresponding data (depending on
-+ profiles and entrypoints)
-+- Pass the render buffers to the server to handle the current frame
-+
-+Initialization & Configuration Management
-+
-+- Find out supported profiles
-+- Find out entrypoints for a given profile
-+- Find out configuration attributes for a given profile/entrypoint pair
-+- Create a configuration for use by the application
-+
-+*/
-+
-+typedef void* VADisplay; /* window system dependent */
-+
-+typedef int VAStatus; /** Return status type from functions */
-+/** Values for the return status */
-+#define VA_STATUS_SUCCESS 0x00000000
-+#define VA_STATUS_ERROR_OPERATION_FAILED 0x00000001
-+#define VA_STATUS_ERROR_ALLOCATION_FAILED 0x00000002
-+#define VA_STATUS_ERROR_INVALID_DISPLAY 0x00000003
-+#define VA_STATUS_ERROR_INVALID_CONFIG 0x00000004
-+#define VA_STATUS_ERROR_INVALID_CONTEXT 0x00000005
-+#define VA_STATUS_ERROR_INVALID_SURFACE 0x00000006
-+#define VA_STATUS_ERROR_INVALID_BUFFER 0x00000007
-+#define VA_STATUS_ERROR_INVALID_IMAGE 0x00000008
-+#define VA_STATUS_ERROR_INVALID_SUBPICTURE 0x00000009
-+#define VA_STATUS_ERROR_ATTR_NOT_SUPPORTED 0x0000000a
-+#define VA_STATUS_ERROR_MAX_NUM_EXCEEDED 0x0000000b
-+#define VA_STATUS_ERROR_UNSUPPORTED_PROFILE 0x0000000c
-+#define VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT 0x0000000d
-+#define VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT 0x0000000e
-+#define VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE 0x0000000f
-+#define VA_STATUS_ERROR_SURFACE_BUSY 0x00000010
-+#define VA_STATUS_ERROR_FLAG_NOT_SUPPORTED 0x00000011
-+#define VA_STATUS_ERROR_INVALID_PARAMETER 0x00000012
-+#define VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED 0x00000013
-+#define VA_STATUS_ERROR_UNIMPLEMENTED 0x00000014
-+#define VA_STATUS_ERROR_SURFACE_IN_DISPLAYING 0x00000015
-+#define VA_STATUS_ERROR_INVALID_IMAGE_FORMAT 0x00000016
-+#define VA_STATUS_ERROR_DECODING_ERROR 0x00000017
-+#define VA_STATUS_ERROR_ENCODING_ERROR 0x00000018
-+/**
-+ * \brief An invalid/unsupported value was supplied.
-+ *
-+ * This is a catch-all error code for invalid or unsupported values.
-+ * e.g. value exceeding the valid range, invalid type in the context
-+ * of generic attribute values.
-+ */
-+#define VA_STATUS_ERROR_INVALID_VALUE 0x00000019
-+/** \brief An unsupported filter was supplied. */
-+#define VA_STATUS_ERROR_UNSUPPORTED_FILTER 0x00000020
-+/** \brief An invalid filter chain was supplied. */
-+#define VA_STATUS_ERROR_INVALID_FILTER_CHAIN 0x00000021
-+/** \brief Indicate HW busy (e.g. run multiple encoding simultaneously). */
-+#define VA_STATUS_ERROR_HW_BUSY 0x00000022
-+/** \brief An unsupported memory type was supplied. */
-+#define VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE 0x00000024
-+/** \brief Indicate allocated buffer size is not enough for input or output. */
-+#define VA_STATUS_ERROR_NOT_ENOUGH_BUFFER 0x00000025
-+#define VA_STATUS_ERROR_UNKNOWN 0xFFFFFFFF
-+
-+/**
-+ * 1. De-interlacing flags for vaPutSurface()
-+ * 2. Surface sample type for input/output surface flag
-+ * - Progressive: VA_FRAME_PICTURE
-+ * - Interleaved: VA_TOP_FIELD_FIRST, VA_BOTTOM_FIELD_FIRST
-+ * - Field: VA_TOP_FIELD, VA_BOTTOM_FIELD
-+*/
-+#define VA_FRAME_PICTURE 0x00000000
-+#define VA_TOP_FIELD 0x00000001
-+#define VA_BOTTOM_FIELD 0x00000002
-+#define VA_TOP_FIELD_FIRST 0x00000004
-+#define VA_BOTTOM_FIELD_FIRST 0x00000008
-+
-+/**
-+ * Enabled the positioning/cropping/blending feature:
-+ * 1, specify the video playback position in the isurface
-+ * 2, specify the cropping info for video playback
-+ * 3, encoded video will blend with background color
-+ */
-+#define VA_ENABLE_BLEND 0x00000004 /* video area blend with the constant color */
-+
-+/**
-+ * Clears the drawable with background color.
-+ * for hardware overlay based implementation this flag
-+ * can be used to turn off the overlay
-+ */
-+#define VA_CLEAR_DRAWABLE 0x00000008
-+
-+/** Color space conversion flags for vaPutSurface() */
-+#define VA_SRC_COLOR_MASK 0x000000f0
-+#define VA_SRC_BT601 0x00000010
-+#define VA_SRC_BT709 0x00000020
-+#define VA_SRC_SMPTE_240 0x00000040
-+
-+/** Scaling flags for vaPutSurface() */
-+#define VA_FILTER_SCALING_DEFAULT 0x00000000
-+#define VA_FILTER_SCALING_FAST 0x00000100
-+#define VA_FILTER_SCALING_HQ 0x00000200
-+#define VA_FILTER_SCALING_NL_ANAMORPHIC 0x00000300
-+#define VA_FILTER_SCALING_MASK 0x00000f00
-+
-+/** Padding size in 4-bytes */
-+#define VA_PADDING_LOW 4
-+#define VA_PADDING_MEDIUM 8
-+#define VA_PADDING_HIGH 16
-+#define VA_PADDING_LARGE 32
-+
-+/**
-+ * Returns a short english description of error_status
-+ */
-+const char *vaErrorStr(VAStatus error_status);
-+
-+typedef struct _VARectangle
-+{
-+ int16_t x;
-+ int16_t y;
-+ uint16_t width;
-+ uint16_t height;
-+} VARectangle;
-+
-+/** \brief Generic motion vector data structure. */
-+typedef struct _VAMotionVector {
-+ /** \mv0[0]: horizontal motion vector for past reference */
-+ /** \mv0[1]: vertical motion vector for past reference */
-+ /** \mv1[0]: horizontal motion vector for future reference */
-+ /** \mv1[1]: vertical motion vector for future reference */
-+ int16_t mv0[2]; /* past reference */
-+ int16_t mv1[2]; /* future reference */
-+} VAMotionVector;
-+
-+/** Type of a message callback, used for both error and info log. */
-+typedef void (*VAMessageCallback)(void *user_context, const char *message);
-+
-+/**
-+ * Set the callback for error messages, or NULL for no logging.
-+ * Returns the previous one, or NULL if it was disabled.
-+ */
-+VAMessageCallback vaSetErrorCallback(VADisplay dpy, VAMessageCallback callback, void *user_context);
-+
-+/**
-+ * Set the callback for info messages, or NULL for no logging.
-+ * Returns the previous one, or NULL if it was disabled.
-+ */
-+VAMessageCallback vaSetInfoCallback(VADisplay dpy, VAMessageCallback callback, void *user_context);
-+
-+/**
-+ * Initialization:
-+ * A display must be obtained by calling vaGetDisplay() before calling
-+ * vaInitialize() and other functions. This connects the API to the
-+ * native window system.
-+ * For X Windows, native_dpy would be from XOpenDisplay()
-+ */
-+typedef void* VANativeDisplay; /* window system dependent */
-+
-+int vaDisplayIsValid(VADisplay dpy);
-+
-+/**
-+ * Set the override driver name instead of queried driver driver.
-+ */
-+VAStatus vaSetDriverName(VADisplay dpy,
-+ char *driver_name
-+);
-+
-+/**
-+ * Initialize the library
-+ */
-+VAStatus vaInitialize (
-+ VADisplay dpy,
-+ int *major_version, /* out */
-+ int *minor_version /* out */
-+);
-+
-+/**
-+ * After this call, all library internal resources will be cleaned up
-+ */
-+VAStatus vaTerminate (
-+ VADisplay dpy
-+);
-+
-+/**
-+ * vaQueryVendorString returns a pointer to a zero-terminated string
-+ * describing some aspects of the VA implemenation on a specific
-+ * hardware accelerator. The format of the returned string is vendor
-+ * specific and at the discretion of the implementer.
-+ * e.g. for the Intel GMA500 implementation, an example would be:
-+ * "Intel GMA500 - 2.0.0.32L.0005"
-+ */
-+const char *vaQueryVendorString (
-+ VADisplay dpy
-+);
-+
-+typedef int (*VAPrivFunc)(void);
-+
-+/**
-+ * Return a function pointer given a function name in the library.
-+ * This allows private interfaces into the library
-+ */
-+VAPrivFunc vaGetLibFunc (
-+ VADisplay dpy,
-+ const char *func
-+);
-+
-+/** Currently defined profiles */
-+typedef enum
-+{
-+ /** \brief Profile ID used for video processing. */
-+ VAProfileNone = -1,
-+ VAProfileMPEG2Simple = 0,
-+ VAProfileMPEG2Main = 1,
-+ VAProfileMPEG4Simple = 2,
-+ VAProfileMPEG4AdvancedSimple = 3,
-+ VAProfileMPEG4Main = 4,
-+ VAProfileH264Baseline va_deprecated_enum = 5,
-+ VAProfileH264Main = 6,
-+ VAProfileH264High = 7,
-+ VAProfileVC1Simple = 8,
-+ VAProfileVC1Main = 9,
-+ VAProfileVC1Advanced = 10,
-+ VAProfileH263Baseline = 11,
-+ VAProfileJPEGBaseline = 12,
-+ VAProfileH264ConstrainedBaseline = 13,
-+ VAProfileVP8Version0_3 = 14,
-+ VAProfileH264MultiviewHigh = 15,
-+ VAProfileH264StereoHigh = 16,
-+ VAProfileHEVCMain = 17,
-+ VAProfileHEVCMain10 = 18,
-+ VAProfileVP9Profile0 = 19,
-+ VAProfileVP9Profile1 = 20,
-+ VAProfileVP9Profile2 = 21,
-+ VAProfileVP9Profile3 = 22,
-+ VAProfileHEVCMain12 = 23,
-+ VAProfileHEVCMain422_10 = 24,
-+ VAProfileHEVCMain422_12 = 25,
-+ VAProfileHEVCMain444 = 26,
-+ VAProfileHEVCMain444_10 = 27,
-+ VAProfileHEVCMain444_12 = 28,
-+ VAProfileHEVCSccMain = 29,
-+ VAProfileHEVCSccMain10 = 30,
-+ VAProfileHEVCSccMain444 = 31
-+} VAProfile;
-+
-+/**
-+ * Currently defined entrypoints
-+ */
-+typedef enum
-+{
-+ VAEntrypointVLD = 1,
-+ VAEntrypointIZZ = 2,
-+ VAEntrypointIDCT = 3,
-+ VAEntrypointMoComp = 4,
-+ VAEntrypointDeblocking = 5,
-+ VAEntrypointEncSlice = 6, /* slice level encode */
-+ VAEntrypointEncPicture = 7, /* pictuer encode, JPEG, etc */
-+ /*
-+ * For an implementation that supports a low power/high performance variant
-+ * for slice level encode, it can choose to expose the
-+ * VAEntrypointEncSliceLP entrypoint. Certain encoding tools may not be
-+ * available with this entrypoint (e.g. interlace, MBAFF) and the
-+ * application can query the encoding configuration attributes to find
-+ * out more details if this entrypoint is supported.
-+ */
-+ VAEntrypointEncSliceLP = 8,
-+ VAEntrypointVideoProc = 10, /**< Video pre/post-processing. */
-+ /**
-+ * \brief VAEntrypointFEI
-+ *
-+ * The purpose of FEI (Flexible Encoding Infrastructure) is to allow applications to
-+ * have more controls and trade off quality for speed with their own IPs.
-+ * The application can optionally provide input to ENC for extra encode control
-+ * and get the output from ENC. Application can chose to modify the ENC
-+ * output/PAK input during encoding, but the performance impact is significant.
-+ *
-+ * On top of the existing buffers for normal encode, there will be
-+ * one extra input buffer (VAEncMiscParameterFEIFrameControl) and
-+ * three extra output buffers (VAEncFEIMVBufferType, VAEncFEIMBModeBufferType
-+ * and VAEncFEIDistortionBufferType) for VAEntrypointFEI entry function.
-+ * If separate PAK is set, two extra input buffers
-+ * (VAEncFEIMVBufferType, VAEncFEIMBModeBufferType) are needed for PAK input.
-+ **/
-+ VAEntrypointFEI = 11,
-+ /**
-+ * \brief VAEntrypointStats
-+ *
-+ * A pre-processing function for getting some statistics and motion vectors is added,
-+ * and some extra controls for Encode pipeline are provided. The application can
-+ * optionally call the statistics function to get motion vectors and statistics like
-+ * variances, distortions before calling Encode function via this entry point.
-+ *
-+ * Checking whether Statistics is supported can be performed with vaQueryConfigEntrypoints().
-+ * If Statistics entry point is supported, then the list of returned entry-points will
-+ * include #VAEntrypointStats. Supported pixel format, maximum resolution and statistics
-+ * specific attributes can be obtained via normal attribute query. One input buffer
-+ * (VAStatsStatisticsParameterBufferType) and one or two output buffers
-+ * (VAStatsStatisticsBufferType, VAStatsStatisticsBottomFieldBufferType (for interlace only)
-+ * and VAStatsMVBufferType) are needed for this entry point.
-+ **/
-+ VAEntrypointStats = 12,
-+} VAEntrypoint;
-+
-+/** Currently defined configuration attribute types */
-+typedef enum
-+{
-+ VAConfigAttribRTFormat = 0,
-+ VAConfigAttribSpatialResidual = 1,
-+ VAConfigAttribSpatialClipping = 2,
-+ VAConfigAttribIntraResidual = 3,
-+ VAConfigAttribEncryption = 4,
-+ VAConfigAttribRateControl = 5,
-+
-+ /** @name Attributes for decoding */
-+ /**@{*/
-+ /**
-+ * \brief Slice Decoding mode. Read/write.
-+ *
-+ * This attribute determines what mode the driver supports for slice
-+ * decoding, through vaGetConfigAttributes(); and what mode the user
-+ * will be providing to the driver, through vaCreateConfig(), if the
-+ * driver supports those. If this attribute is not set by the user then
-+ * it is assumed that VA_DEC_SLICE_MODE_NORMAL mode is used.
-+ *
-+ * See \c VA_DEC_SLICE_MODE_xxx for the list of slice decoding modes.
-+ */
-+ VAConfigAttribDecSliceMode = 6,
-+ /**
-+ * \brief JPEG decoding attribute. Read-only.
-+ *
-+ * This attribute exposes a number of capabilities of the underlying
-+ * JPEG implementation. The attribute value is partitioned into fields as defined in the
-+ * VAConfigAttribValDecJPEG union.
-+ */
-+ VAConfigAttribDecJPEG = 7,
-+ /**
-+ * \brief Decode processing support. Read/write.
-+ *
-+ * This attribute determines if the driver supports video processing
-+ * with decoding using the decoding context in a single call, through
-+ * vaGetConfigAttributes(); and if the user may use this feature,
-+ * through vaCreateConfig(), if the driver supports the user scenario.
-+ * The user will essentially create a regular decode VAContext. Therefore,
-+ * the parameters of vaCreateContext() such as picture_width, picture_height
-+ * and render_targets are in relation to the decode output parameters
-+ * (not processing output parameters) as normal.
-+ * If this attribute is not set by the user then it is assumed that no
-+ * extra processing is done after decoding for this decode context.
-+ *
-+ * Since essentially the application is creating a decoder config and context,
-+ * all function calls that take in the config (e.g. vaQuerySurfaceAttributes())
-+ * or context are in relation to the decoder, except those video processing
-+ * function specified in the next paragraph.
-+ *
-+ * Once the decode config and context are created, the user must further
-+ * query the supported processing filters using vaQueryVideoProcFilters(),
-+ * vaQueryVideoProcFilterCaps(), vaQueryVideoProcPipelineCaps() by specifying
-+ * the created decode context. The user must provide processing information
-+ * and extra processing output surfaces as "additional_outputs" to the driver
-+ * through VAProcPipelineParameterBufferType. The render_target specified
-+ * at vaBeginPicture() time refers to the decode output surface. The
-+ * target surface for the output of processing needs to be a different
-+ * surface since the decode process requires the original reconstructed buffer.
-+ * The “surface” member of VAProcPipelineParameterBuffer should be set to the
-+ * same as “render_target” set in vaBeginPicture(), but the driver may choose
-+ * to ignore this parameter.
-+ */
-+ VAConfigAttribDecProcessing = 8,
-+ /** @name Attributes for encoding */
-+ /**@{*/
-+ /**
-+ * \brief Packed headers mode. Read/write.
-+ *
-+ * This attribute determines what packed headers the driver supports,
-+ * through vaGetConfigAttributes(); and what packed headers the user
-+ * will be providing to the driver, through vaCreateConfig(), if the
-+ * driver supports those.
-+ *
-+ * See \c VA_ENC_PACKED_HEADER_xxx for the list of packed headers.
-+ */
-+ VAConfigAttribEncPackedHeaders = 10,
-+ /**
-+ * \brief Interlaced mode. Read/write.
-+ *
-+ * This attribute determines what kind of interlaced encoding mode
-+ * the driver supports.
-+ *
-+ * See \c VA_ENC_INTERLACED_xxx for the list of interlaced modes.
-+ */
-+ VAConfigAttribEncInterlaced = 11,
-+ /**
-+ * \brief Maximum number of reference frames. Read-only.
-+ *
-+ * This attribute determines the maximum number of reference
-+ * frames supported for encoding.
-+ *
-+ * Note: for H.264 encoding, the value represents the maximum number
-+ * of reference frames for both the reference picture list 0 (bottom
-+ * 16 bits) and the reference picture list 1 (top 16 bits).
-+ */
-+ VAConfigAttribEncMaxRefFrames = 13,
-+ /**
-+ * \brief Maximum number of slices per frame. Read-only.
-+ *
-+ * This attribute determines the maximum number of slices the
-+ * driver can support to encode a single frame.
-+ */
-+ VAConfigAttribEncMaxSlices = 14,
-+ /**
-+ * \brief Slice structure. Read-only.
-+ *
-+ * This attribute determines slice structures supported by the
-+ * driver for encoding. This attribute is a hint to the user so
-+ * that he can choose a suitable surface size and how to arrange
-+ * the encoding process of multiple slices per frame.
-+ *
-+ * More specifically, for H.264 encoding, this attribute
-+ * determines the range of accepted values to
-+ * VAEncSliceParameterBufferH264::macroblock_address and
-+ * VAEncSliceParameterBufferH264::num_macroblocks.
-+ *
-+ * See \c VA_ENC_SLICE_STRUCTURE_xxx for the supported slice
-+ * structure types.
-+ */
-+ VAConfigAttribEncSliceStructure = 15,
-+ /**
-+ * \brief Macroblock information. Read-only.
-+ *
-+ * This attribute determines whether the driver supports extra
-+ * encoding information per-macroblock. e.g. QP.
-+ *
-+ * More specifically, for H.264 encoding, if the driver returns a non-zero
-+ * value for this attribute, this means the application can create
-+ * additional #VAEncMacroblockParameterBufferH264 buffers referenced
-+ * through VAEncSliceParameterBufferH264::macroblock_info.
-+ */
-+ VAConfigAttribEncMacroblockInfo = 16,
-+ /**
-+ * \brief Maximum picture width. Read-only.
-+ *
-+ * This attribute determines the maximum picture width the driver supports
-+ * for a given configuration.
-+ */
-+ VAConfigAttribMaxPictureWidth = 18,
-+ /**
-+ * \brief Maximum picture height. Read-only.
-+ *
-+ * This attribute determines the maximum picture height the driver supports
-+ * for a given configuration.
-+ */
-+ VAConfigAttribMaxPictureHeight = 19,
-+ /**
-+ * \brief JPEG encoding attribute. Read-only.
-+ *
-+ * This attribute exposes a number of capabilities of the underlying
-+ * JPEG implementation. The attribute value is partitioned into fields as defined in the
-+ * VAConfigAttribValEncJPEG union.
-+ */
-+ VAConfigAttribEncJPEG = 20,
-+ /**
-+ * \brief Encoding quality range attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports different quality level settings
-+ * for encoding. A value less than or equal to 1 means that the encoder only has a single
-+ * quality setting, and a value greater than 1 represents the number of quality levels
-+ * that can be configured. e.g. a value of 2 means there are two distinct quality levels.
-+ */
-+ VAConfigAttribEncQualityRange = 21,
-+ /**
-+ * \brief Encoding quantization attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports certain types of quantization methods
-+ * for encoding (e.g. trellis). See \c VA_ENC_QUANTIZATION_xxx for the list of quantization methods
-+ */
-+ VAConfigAttribEncQuantization = 22,
-+ /**
-+ * \brief Encoding intra refresh attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports certain types of intra refresh methods
-+ * for encoding (e.g. adaptive intra refresh or rolling intra refresh).
-+ * See \c VA_ENC_INTRA_REFRESH_xxx for intra refresh methods
-+ */
-+ VAConfigAttribEncIntraRefresh = 23,
-+ /**
-+ * \brief Encoding skip frame attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports sending skip frame parameters
-+ * (VAEncMiscParameterTypeSkipFrame) to the encoder's rate control, when the user has
-+ * externally skipped frames.
-+ */
-+ VAConfigAttribEncSkipFrame = 24,
-+ /**
-+ * \brief Encoding region-of-interest (ROI) attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports region-of-interest (ROI) encoding,
-+ * based on user provided ROI rectangles. The attribute value is partitioned into fields
-+ * as defined in the VAConfigAttribValEncROI union.
-+ *
-+ * If ROI encoding is supported, the ROI information is passed to the driver using
-+ * VAEncMiscParameterTypeROI.
-+ */
-+ VAConfigAttribEncROI = 25,
-+ /**
-+ * \brief Encoding extended rate control attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports any extended rate control features
-+ * The attribute value is partitioned into fields as defined in the
-+ * VAConfigAttribValEncRateControlExt union.
-+ */
-+ VAConfigAttribEncRateControlExt = 26,
-+ /**
-+ * \brief Processing rate reporting attribute. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports reporting of
-+ * encode/decode processing rate based on certain set of parameters
-+ * (i.e. levels, I frame internvals) for a given configuration.
-+ * If this is supported, vaQueryProcessingRate() can be used to get
-+ * encode or decode processing rate.
-+ * See \c VA_PROCESSING_RATE_xxx for encode/decode processing rate
-+ */
-+ VAConfigAttribProcessingRate = 27,
-+ /**
-+ * \brief Encoding dirty rectangle. Read-only.
-+ *
-+ * This attribute conveys whether the driver supports dirty rectangle.
-+ * encoding, based on user provided ROI rectangles which indicate the rectangular areas
-+ * where the content has changed as compared to the previous picture. The regions of the
-+ * picture that are not covered by dirty rect rectangles are assumed to have not changed
-+ * compared to the previous picture. The encoder may do some optimizations based on
-+ * this information. The attribute value returned indicates the number of regions that
-+ * are supported. e.g. A value of 0 means dirty rect encoding is not supported. If dirty
-+ * rect encoding is supported, the ROI information is passed to the driver using
-+ * VAEncMiscParameterTypeDirtyRect.
-+ */
-+ VAConfigAttribEncDirtyRect = 28,
-+ /**
-+ * \brief Parallel Rate Control (hierachical B) attribute. Read-only.
-+ *
-+ * This attribute conveys whether the encoder supports parallel rate control.
-+ * It is a integer value 0 - unsupported, > 0 - maximum layer supported.
-+ * This is the way when hireachical B frames are encoded, multiple independent B frames
-+ * on the same layer may be processed at same time. If supported, app may enable it by
-+ * setting enable_parallel_brc in VAEncMiscParameterRateControl,and the number of B frames
-+ * per layer per GOP will be passed to driver through VAEncMiscParameterParallelRateControl
-+ * structure.Currently three layers are defined.
-+ */
-+ VAConfigAttribEncParallelRateControl = 29,
-+ /**
-+ * \brief Dynamic Scaling Attribute. Read-only.
-+ *
-+ * This attribute conveys whether encoder is capable to determine dynamic frame
-+ * resolutions adaptive to bandwidth utilization and processing power, etc.
-+ * It is a boolean value 0 - unsupported, 1 - supported.
-+ * If it is supported,for VP9, suggested frame resolution can be retrieved from VACodedBufferVP9Status.
-+ */
-+ VAConfigAttribEncDynamicScaling = 30,
-+ /**
-+ * \brief frame size tolerance support
-+ * it indicates the tolerance of frame size
-+ */
-+ VAConfigAttribFrameSizeToleranceSupport = 31,
-+ /**
-+ * \brief Encode function type for FEI.
-+ *
-+ * This attribute conveys whether the driver supports different function types for encode.
-+ * It can be VA_FEI_FUNCTION_ENC, VA_FEI_FUNCTION_PAK, or VA_FEI_FUNCTION_ENC_PAK. Currently
-+ * it is for FEI entry point only.
-+ * Default is VA_FEI_FUNCTION_ENC_PAK.
-+ */
-+ VAConfigAttribFEIFunctionType = 32,
-+ /**
-+ * \brief Maximum number of FEI MV predictors. Read-only.
-+ *
-+ * This attribute determines the maximum number of MV predictors the driver
-+ * can support to encode a single frame. 0 means no MV predictor is supported.
-+ * Currently it is for FEI entry point only.
-+ */
-+ VAConfigAttribFEIMVPredictors = 33,
-+ /**
-+ * \brief Statistics attribute. Read-only.
-+ *
-+ * This attribute exposes a number of capabilities of the VAEntrypointStats entry
-+ * point. The attribute value is partitioned into fields as defined in the
-+ * VAConfigAttribValStats union. Currently it is for VAEntrypointStats only.
-+ */
-+ VAConfigAttribStats = 34,
-+ /**
-+ * \brief Tile Support Attribute. Read-only.
-+ *
-+ * This attribute conveys whether encoder is capable to support tiles.
-+ * If not supported, the tile related parameters sent to encoder, such as
-+ * tiling structure, should be ignored. 0 - unsupported, 1 - supported.
-+ */
-+ VAConfigAttribEncTileSupport = 35,
-+ /**
-+ * \brief whether accept rouding setting from application. Read-only.
-+ * This attribute is for encode quality, if it is report,
-+ * application can change the rounding setting by VAEncMiscParameterTypeCustomRoundingControl
-+ */
-+ VAConfigAttribCustomRoundingControl = 36,
-+ /**
-+ * \brief Encoding QP info block size attribute. Read-only.
-+ * This attribute conveys the block sizes that underlying driver
-+ * support for QP info for buffer #VAEncQpBuffer.
-+ */
-+ VAConfigAttribQPBlockSize = 37,
-+ /**
-+ * \brief encode max frame size attribute. Read-only
-+ * attribute value \c VAConfigAttribValMaxFrameSize represent max frame size support
-+ */
-+ VAConfigAttribMaxFrameSize = 38,
-+ /** \brief inter frame prediction directrion attribute. Read-only.
-+ * this attribute conveys the prediction direction (backward or forword) for specific config
-+ * the value could be VA_PREDICTION_DIRECTION_XXXX. it can be combined with VAConfigAttribEncMaxRefFrames
-+ * to describe reference list , and the prediction direction. if this attrib is not present,both direction
-+ * should be supported, no restriction.
-+ * for example: normal HEVC encoding , maximum reference frame number in reflist 0 and reflist 1 is deduced
-+ * by VAConfigAttribEncMaxRefFrames. so there are typical P frame, B frame,
-+ * if VAConfigAttribPredictionDirection is also present. it will stipulate prediction direction in both
-+ * reference list. if only one prediction direction present(such as PREVIOUS),all reference frame should be
-+ * previous frame (PoC < current).
-+ */
-+ VAConfigAttribPredictionDirection = 39,
-+ /** \brief combined submission of multiple frames from different streams, it is optimization for different HW
-+ * implementation, multiple frames encode/decode can improve HW concurrency
-+ */
-+ VAConfigAttribMultipleFrame = 40,
-+ /**@}*/
-+ VAConfigAttribTypeMax
-+} VAConfigAttribType;
-+
-+/**
-+ * Configuration attributes
-+ * If there is more than one value for an attribute, a default
-+ * value will be assigned to the attribute if the client does not
-+ * specify the attribute when creating a configuration
-+ */
-+typedef struct _VAConfigAttrib {
-+ VAConfigAttribType type;
-+ uint32_t value; /* OR'd flags (bits) for this attribute */
-+} VAConfigAttrib;
-+
-+/* Attribute values for VAConfigAttribRTFormat. */
-+
-+#define VA_RT_FORMAT_YUV420 0x00000001 ///< YUV 4:2:0 8-bit.
-+#define VA_RT_FORMAT_YUV422 0x00000002 ///< YUV 4:2:2 8-bit.
-+#define VA_RT_FORMAT_YUV444 0x00000004 ///< YUV 4:4:4 8-bit.
-+#define VA_RT_FORMAT_YUV411 0x00000008 ///< YUV 4:1:1 8-bit.
-+#define VA_RT_FORMAT_YUV400 0x00000010 ///< Greyscale 8-bit.
-+#define VA_RT_FORMAT_YUV420_10 0x00000100 ///< YUV 4:2:0 10-bit.
-+#define VA_RT_FORMAT_YUV422_10 0x00000200 ///< YUV 4:2:2 10-bit.
-+#define VA_RT_FORMAT_YUV444_10 0x00000400 ///< YUV 4:4:4 10-bit.
-+#define VA_RT_FORMAT_YUV420_12 0x00001000 ///< YUV 4:2:0 12-bit.
-+#define VA_RT_FORMAT_YUV422_12 0x00002000 ///< YUV 4:2:2 12-bit.
-+#define VA_RT_FORMAT_YUV444_12 0x00004000 ///< YUV 4:4:4 12-bit.
-+
-+#define VA_RT_FORMAT_RGB16 0x00010000 ///< Packed RGB, 16 bits per pixel.
-+#define VA_RT_FORMAT_RGB32 0x00020000 ///< Packed RGB, 32 bits per pixel, 8 bits per colour sample.
-+#define VA_RT_FORMAT_RGBP 0x00100000 ///< Planar RGB, 8 bits per sample.
-+#define VA_RT_FORMAT_RGB32_10 0x00200000 ///< Packed RGB, 32 bits per pixel, 10 bits per colour sample.
-+
-+#define VA_RT_FORMAT_PROTECTED 0x80000000
-+
-+#define VA_RT_FORMAT_RGB32_10BPP VA_RT_FORMAT_RGB32_10 ///< @deprecated use VA_RT_FORMAT_RGB32_10 instead.
-+#define VA_RT_FORMAT_YUV420_10BPP VA_RT_FORMAT_YUV420_10 ///< @deprecated use VA_RT_FORMAT_YUV420_10 instead.
-+
-+/** @name Attribute values for VAConfigAttribRateControl */
-+/**@{*/
-+/** \brief Driver does not support any form of rate control. */
-+#define VA_RC_NONE 0x00000001
-+/** \brief Constant bitrate. */
-+#define VA_RC_CBR 0x00000002
-+/** \brief Variable bitrate. */
-+#define VA_RC_VBR 0x00000004
-+/** \brief Video conference mode. */
-+#define VA_RC_VCM 0x00000008
-+/** \brief Constant QP. */
-+#define VA_RC_CQP 0x00000010
-+/** \brief Variable bitrate with peak rate higher than average bitrate. */
-+#define VA_RC_VBR_CONSTRAINED 0x00000020
-+/** \brief Intelligent Constant Quality. Provided an initial ICQ_quality_factor,
-+ * adjusts QP at a frame and MB level based on motion to improve subjective quality. */
-+#define VA_RC_ICQ 0x00000040
-+/** \brief Macroblock based rate control. Per MB control is decided
-+ * internally in the encoder. It may be combined with other RC modes, except CQP. */
-+#define VA_RC_MB 0x00000080
-+/** \brief Constant Frame Size, it is used for small tolerent */
-+#define VA_RC_CFS 0x00000100
-+/** \brief Parallel BRC, for hierachical B.
-+ *
-+ * For hierachical B, B frames can be refered by other B frames.
-+ * Currently three layers of hierachy are defined:
-+ * B0 - regular B, no reference to other B frames.
-+ * B1 - reference to only I, P and regular B0 frames.
-+ * B2 - reference to any other frames, including B1.
-+ * In Hierachical B structure, B frames on the same layer can be processed
-+ * simultaneously. And BRC would adjust accordingly. This is so called
-+ * Parallel BRC. */
-+#define VA_RC_PARALLEL 0x00000200
-+/** \brief Quality defined VBR
-+ * Use Quality factor to determine the good enough QP for each MB such that
-+ * good enough quality can be obtained without waste of bits
-+ * for this BRC mode, you must set all legacy VBR parameters
-+ * and reuse quality_factor in \c VAEncMiscParameterRateControl
-+ * */
-+#define VA_RC_QVBR 0x00000400
-+/** \brief Average VBR
-+ * Average variable bitrate control algorithm focuses on overall encoding
-+ * quality while meeting the specified target bitrate, within the accuracy
-+ * range, after a convergence period.
-+ * bits_per_second in VAEncMiscParameterRateControl is target bitrate for AVBR.
-+ * Convergence is specified in the unit of frame.
-+ * window_size in VAEncMiscParameterRateControl is equal to convergence for AVBR.
-+ * Accuracy is in the range of [1,100], 1 means one percent, and so on.
-+ * target_percentage in VAEncMiscParameterRateControl is equal to accuracy for AVBR. */
-+#define VA_RC_AVBR 0x00000800
-+
-+/**@}*/
-+
-+/** @name Attribute values for VAConfigAttribDecSliceMode */
-+/**@{*/
-+/** \brief Driver supports normal mode for slice decoding */
-+#define VA_DEC_SLICE_MODE_NORMAL 0x00000001
-+/** \brief Driver supports base mode for slice decoding */
-+#define VA_DEC_SLICE_MODE_BASE 0x00000002
-+
-+/** @name Attribute values for VAConfigAttribDecJPEG */
-+/**@{*/
-+typedef union _VAConfigAttribValDecJPEG {
-+ struct {
-+ /** \brief Set to (1 << VA_ROTATION_xxx) for supported rotation angles. */
-+ uint32_t rotation : 4;
-+ /** \brief Reserved for future use. */
-+ uint32_t reserved : 28;
-+ } bits;
-+ uint32_t value;
-+} VAConfigAttribValDecJPEG;
-+/** @name Attribute values for VAConfigAttribDecProcessing */
-+/**@{*/
-+/** \brief No decoding + processing in a single decoding call. */
-+#define VA_DEC_PROCESSING_NONE 0x00000000
-+/** \brief Decode + processing in a single decoding call. */
-+#define VA_DEC_PROCESSING 0x00000001
-+/**@}*/
-+
-+/** @name Attribute values for VAConfigAttribEncPackedHeaders */
-+/**@{*/
-+/** \brief Driver does not support any packed headers mode. */
-+#define VA_ENC_PACKED_HEADER_NONE 0x00000000
-+/**
-+ * \brief Driver supports packed sequence headers. e.g. SPS for H.264.
-+ *
-+ * Application must provide it to driver once this flag is returned through
-+ * vaGetConfigAttributes()
-+ */
-+#define VA_ENC_PACKED_HEADER_SEQUENCE 0x00000001
-+/**
-+ * \brief Driver supports packed picture headers. e.g. PPS for H.264.
-+ *
-+ * Application must provide it to driver once this falg is returned through
-+ * vaGetConfigAttributes()
-+ */
-+#define VA_ENC_PACKED_HEADER_PICTURE 0x00000002
-+/**
-+ * \brief Driver supports packed slice headers. e.g. slice_header() for H.264.
-+ *
-+ * Application must provide it to driver once this flag is returned through
-+ * vaGetConfigAttributes()
-+ */
-+#define VA_ENC_PACKED_HEADER_SLICE 0x00000004
-+/**
-+ * \brief Driver supports misc packed headers. e.g. SEI for H.264.
-+ *
-+ * @deprecated
-+ * This is a deprecated packed header flag, All applications can use
-+ * \c VA_ENC_PACKED_HEADER_RAW_DATA to pass the corresponding packed
-+ * header data buffer to the driver
-+ */
-+#define VA_ENC_PACKED_HEADER_MISC 0x00000008
-+/** \brief Driver supports raw packed header, see VAEncPackedHeaderRawData */
-+#define VA_ENC_PACKED_HEADER_RAW_DATA 0x00000010
-+/**@}*/
-+
-+/** @name Attribute values for VAConfigAttribEncInterlaced */
-+/**@{*/
-+/** \brief Driver does not support interlaced coding. */
-+#define VA_ENC_INTERLACED_NONE 0x00000000
-+/** \brief Driver supports interlaced frame coding. */
-+#define VA_ENC_INTERLACED_FRAME 0x00000001
-+/** \brief Driver supports interlaced field coding. */
-+#define VA_ENC_INTERLACED_FIELD 0x00000002
-+/** \brief Driver supports macroblock adaptive frame field coding. */
-+#define VA_ENC_INTERLACED_MBAFF 0x00000004
-+/** \brief Driver supports picture adaptive frame field coding. */
-+#define VA_ENC_INTERLACED_PAFF 0x00000008
-+/**@}*/
-+
-+/** @name Attribute values for VAConfigAttribEncSliceStructure */
-+/**@{*/
-+/** \brief Driver supports a power-of-two number of rows per slice. */
-+#define VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS 0x00000001
-+/** \brief Driver supports an arbitrary number of macroblocks per slice. */
-+#define VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS 0x00000002
-+/** \brief Dirver support 1 rows per slice */
-+#define VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS 0x00000004
-+/** \brief Dirver support max encoded slice size per slice */
-+#define VA_ENC_SLICE_STRUCTURE_MAX_SLICE_SIZE 0x00000008
-+/** \brief Driver supports an arbitrary number of rows per slice. */
-+#define VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS 0x00000010
-+/**@}*/
-+
-+/** \brief Attribute value for VAConfigAttribMaxFrameSize */
-+typedef union _VAConfigAttribValMaxFrameSize {
-+ struct {
-+ /** \brief support max frame size
-+ * if max_frame_size == 1, VAEncMiscParameterTypeMaxFrameSize/VAEncMiscParameterBufferMaxFrameSize
-+ * could be used to set the frame size, if multiple_pass also equal 1, VAEncMiscParameterTypeMultiPassFrameSize
-+ * VAEncMiscParameterBufferMultiPassFrameSize could be used to set frame size and pass information
-+ */
-+ uint32_t max_frame_size : 1;
-+ /** \brief multiple_pass support */
-+ uint32_t multiple_pass : 1;
-+ /** \brief reserved bits for future, must be zero*/
-+ uint32_t reserved :30;
-+ } bits;
-+ uint32_t value;
-+} VAConfigAttribValMaxFrameSize;
-+
-+/** \brief Attribute value for VAConfigAttribEncJPEG */
-+typedef union _VAConfigAttribValEncJPEG {
-+ struct {
-+ /** \brief set to 1 for arithmatic coding. */
-+ uint32_t arithmatic_coding_mode : 1;
-+ /** \brief set to 1 for progressive dct. */
-+ uint32_t progressive_dct_mode : 1;
-+ /** \brief set to 1 for non-interleaved. */
-+ uint32_t non_interleaved_mode : 1;
-+ /** \brief set to 1 for differential. */
-+ uint32_t differential_mode : 1;
-+ uint32_t max_num_components : 3;
-+ uint32_t max_num_scans : 4;
-+ uint32_t max_num_huffman_tables : 3;
-+ uint32_t max_num_quantization_tables : 3;
-+ } bits;
-+ uint32_t value;
-+} VAConfigAttribValEncJPEG;
-+
-+/** @name Attribute values for VAConfigAttribEncQuantization */
-+/**@{*/
-+/** \brief Driver does not support special types of quantization */
-+#define VA_ENC_QUANTIZATION_NONE 0x00000000
-+/** \brief Driver supports trellis quantization */
-+#define VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED 0x00000001
-+/**@}*/
-+
-+/** @name Attribute values for VAConfigAttribPredictionDirection */
-+/**@{*/
-+/** \brief Driver support forward reference frame (inter frame for vpx, P frame for H26x MPEG)
-+ * can work with the VAConfigAttribEncMaxRefFrames. for example: low delay B frame of HEVC.
-+ * these value can be OR'd together. typical value should be VA_PREDICTION_DIRECTION_PREVIOUS
-+ * or VA_PREDICTION_DIRECTION_PREVIOUS | VA_PREDICTION_DIRECTION_FUTURE, theoretically, there
-+ * are no stream only include future reference frame.
-+ */
-+#define VA_PREDICTION_DIRECTION_PREVIOUS 0x00000001
-+/** \brief Driver support backward prediction frame/slice */
-+#define VA_PREDICTION_DIRECTION_FUTURE 0x00000002
-+/**@}*/
-+
-+/** @name Attribute values for VAConfigAttribEncIntraRefresh */
-+/**@{*/
-+/** \brief Driver does not support intra refresh */
-+#define VA_ENC_INTRA_REFRESH_NONE 0x00000000
-+/** \brief Driver supports column based rolling intra refresh */
-+#define VA_ENC_INTRA_REFRESH_ROLLING_COLUMN 0x00000001
-+/** \brief Driver supports row based rolling intra refresh */
-+#define VA_ENC_INTRA_REFRESH_ROLLING_ROW 0x00000002
-+/** \brief Driver supports adaptive intra refresh */
-+#define VA_ENC_INTRA_REFRESH_ADAPTIVE 0x00000010
-+/** \brief Driver supports cyclic intra refresh */
-+#define VA_ENC_INTRA_REFRESH_CYCLIC 0x00000020
-+/** \brief Driver supports intra refresh of P frame*/
-+#define VA_ENC_INTRA_REFRESH_P_FRAME 0x00010000
-+/** \brief Driver supports intra refresh of B frame */
-+#define VA_ENC_INTRA_REFRESH_B_FRAME 0x00020000
-+/** \brief Driver supports intra refresh of multiple reference encoder */
-+#define VA_ENC_INTRA_REFRESH_MULTI_REF 0x00040000
-+
-+/**@}*/
-+
-+/** \brief Attribute value for VAConfigAttribEncROI */
-+typedef union _VAConfigAttribValEncROI {
-+ struct {
-+ /** \brief The number of ROI regions supported, 0 if ROI is not supported. */
-+ uint32_t num_roi_regions : 8;
-+ /**
-+ * \brief A flag indicates whether ROI priority is supported
-+ *
-+ * \ref roi_rc_priority_support equal to 1 specifies the underlying driver supports
-+ * ROI priority when VAConfigAttribRateControl != VA_RC_CQP, user can use \c roi_value
-+ * in #VAEncROI to set ROI priority. \ref roi_rc_priority_support equal to 0 specifies
-+ * the underlying driver doesn't support ROI priority.
-+ *
-+ * User should ignore \ref roi_rc_priority_support when VAConfigAttribRateControl == VA_RC_CQP
-+ * because ROI delta QP is always required when VAConfigAttribRateControl == VA_RC_CQP.
-+ */
-+ uint32_t roi_rc_priority_support : 1;
-+ /**
-+ * \brief A flag indicates whether ROI delta QP is supported
-+ *
-+ * \ref roi_rc_qp_delta_support equal to 1 specifies the underlying driver supports
-+ * ROI delta QP when VAConfigAttribRateControl != VA_RC_CQP, user can use \c roi_value
-+ * in #VAEncROI to set ROI delta QP. \ref roi_rc_qp_delta_support equal to 0 specifies
-+ * the underlying driver doesn't support ROI delta QP.
-+ *
-+ * User should ignore \ref roi_rc_qp_delta_support when VAConfigAttribRateControl == VA_RC_CQP
-+ * because ROI delta QP is always required when VAConfigAttribRateControl == VA_RC_CQP.
-+ */
-+ uint32_t roi_rc_qp_delta_support : 1;
-+ uint32_t reserved : 22;
-+ } bits;
-+ uint32_t value;
-+} VAConfigAttribValEncROI;
-+
-+/** \brief Attribute value for VAConfigAttribEncRateControlExt */
-+typedef union _VAConfigAttribValEncRateControlExt {
-+ struct {
-+ /**
-+ * \brief The maximum number of temporal layers minus 1
-+ *
-+ * \ref max_num_temporal_layers_minus1 plus 1 specifies the maximum number of temporal
-+ * layers that supported by the underlying driver. \ref max_num_temporal_layers_minus1
-+ * equal to 0 implies the underlying driver doesn't support encoding with temporal layer.
-+ */
-+ uint32_t max_num_temporal_layers_minus1 : 8;
-+
-+ /**
-+ * /brief support temporal layer bit-rate control flag
-+ *
-+ * \ref temporal_layer_bitrate_control_flag equal to 1 specifies the underlying driver
-+ * can support bit-rate control per temporal layer when (#VAConfigAttribRateControl == #VA_RC_CBR ||
-+ * #VAConfigAttribRateControl == #VA_RC_VBR).
-+ *
-+ * The underlying driver must set \ref temporal_layer_bitrate_control_flag to 0 when
-+ * \c max_num_temporal_layers_minus1 is equal to 0
-+ *
-+ * To use bit-rate control per temporal layer, an application must send the right layer
-+ * structure via #VAEncMiscParameterTemporalLayerStructure at the beginning of a coded sequence
-+ * and then followed by #VAEncMiscParameterRateControl and #VAEncMiscParameterFrameRate structures
-+ * for each layer, using the \c temporal_id field as the layer identifier. Otherwise
-+ * the driver doesn't use bitrate control per temporal layer if an application doesn't send the
-+ * layer structure via #VAEncMiscParameterTemporalLayerStructure to the driver. The driver returns
-+ * VA_STATUS_ERROR_INVALID_PARAMETER if an application sends a wrong layer structure or doesn't send
-+ * #VAEncMiscParameterRateControl and #VAEncMiscParameterFrameRate for each layer.
-+ *
-+ * The driver will ignore #VAEncMiscParameterTemporalLayerStructure and the \c temporal_id field
-+ * in #VAEncMiscParameterRateControl and #VAEncMiscParameterFrameRate if
-+ * \ref temporal_layer_bitrate_control_flag is equal to 0 or #VAConfigAttribRateControl == #VA_RC_CQP
-+ */
-+ uint32_t temporal_layer_bitrate_control_flag : 1;
-+ uint32_t reserved : 23;
-+ } bits;
-+ uint32_t value;
-+} VAConfigAttribValEncRateControlExt;
-+
-+/** \brief Attribute value for VAConfigAttribMultipleFrame*/
-+typedef union _VAConfigAttribValMultipleFrame {
-+ struct {
-+ /** \brief max num of concurrent frames from different stream */
-+ uint32_t max_num_concurrent_frames : 8;
-+ /** \brief indicate whether all stream must support same quality level
-+ * if mixed_quality_level == 0, same quality level setting for multple streams is required
-+ * if mixed_quality_level == 1, different stream can have different quality level*/
-+ uint32_t mixed_quality_level : 1;
-+ /** \brief reserved bit for future, must be zero */
-+ uint32_t reserved : 23;
-+ } bits;
-+ uint32_t value;
-+}VAConfigAttribValMultipleFrame;
-+
-+/** @name Attribute values for VAConfigAttribProcessingRate. */
-+/**@{*/
-+/** \brief Driver does not support processing rate report */
-+#define VA_PROCESSING_RATE_NONE 0x00000000
-+/** \brief Driver supports encode processing rate report */
-+#define VA_PROCESSING_RATE_ENCODE 0x00000001
-+/** \brief Driver supports decode processing rate report */
-+#define VA_PROCESSING_RATE_DECODE 0x00000002
-+/**@}*/
-+/**
-+ * if an attribute is not applicable for a given
-+ * profile/entrypoint pair, then set the value to the following
-+ */
-+#define VA_ATTRIB_NOT_SUPPORTED 0x80000000
-+
-+/** Get maximum number of profiles supported by the implementation */
-+int vaMaxNumProfiles (
-+ VADisplay dpy
-+);
-+
-+/** Get maximum number of entrypoints supported by the implementation */
-+int vaMaxNumEntrypoints (
-+ VADisplay dpy
-+);
-+
-+/** Get maximum number of attributs supported by the implementation */
-+int vaMaxNumConfigAttributes (
-+ VADisplay dpy
-+);
-+
-+/**
-+ * Query supported profiles
-+ * The caller must provide a "profile_list" array that can hold at
-+ * least vaMaxNumProfile() entries. The actual number of profiles
-+ * returned in "profile_list" is returned in "num_profile".
-+ */
-+VAStatus vaQueryConfigProfiles (
-+ VADisplay dpy,
-+ VAProfile *profile_list, /* out */
-+ int *num_profiles /* out */
-+);
-+
-+/**
-+ * Query supported entrypoints for a given profile
-+ * The caller must provide an "entrypoint_list" array that can hold at
-+ * least vaMaxNumEntrypoints() entries. The actual number of entrypoints
-+ * returned in "entrypoint_list" is returned in "num_entrypoints".
-+ */
-+VAStatus vaQueryConfigEntrypoints (
-+ VADisplay dpy,
-+ VAProfile profile,
-+ VAEntrypoint *entrypoint_list, /* out */
-+ int *num_entrypoints /* out */
-+);
-+
-+/**
-+ * Get attributes for a given profile/entrypoint pair
-+ * The caller must provide an "attrib_list" with all attributes to be
-+ * retrieved. Upon return, the attributes in "attrib_list" have been
-+ * updated with their value. Unknown attributes or attributes that are
-+ * not supported for the given profile/entrypoint pair will have their
-+ * value set to VA_ATTRIB_NOT_SUPPORTED
-+ */
-+VAStatus vaGetConfigAttributes (
-+ VADisplay dpy,
-+ VAProfile profile,
-+ VAEntrypoint entrypoint,
-+ VAConfigAttrib *attrib_list, /* in/out */
-+ int num_attribs
-+);
-+
-+/** Generic ID type, can be re-typed for specific implementation */
-+typedef unsigned int VAGenericID;
-+
-+typedef VAGenericID VAConfigID;
-+
-+/**
-+ * Create a configuration for the video decode/encode/processing pipeline
-+ * it passes in the attribute list that specifies the attributes it cares
-+ * about, with the rest taking default values.
-+ */
-+VAStatus vaCreateConfig (
-+ VADisplay dpy,
-+ VAProfile profile,
-+ VAEntrypoint entrypoint,
-+ VAConfigAttrib *attrib_list,
-+ int num_attribs,
-+ VAConfigID *config_id /* out */
-+);
-+
-+/**
-+ * Free resources associdated with a given config
-+ */
-+VAStatus vaDestroyConfig (
-+ VADisplay dpy,
-+ VAConfigID config_id
-+);
-+
-+/**
-+ * Query all attributes for a given configuration
-+ * The profile of the configuration is returned in "profile"
-+ * The entrypoint of the configuration is returned in "entrypoint"
-+ * The caller must provide an "attrib_list" array that can hold at least
-+ * vaMaxNumConfigAttributes() entries. The actual number of attributes
-+ * returned in "attrib_list" is returned in "num_attribs"
-+ */
-+VAStatus vaQueryConfigAttributes (
-+ VADisplay dpy,
-+ VAConfigID config_id,
-+ VAProfile *profile, /* out */
-+ VAEntrypoint *entrypoint, /* out */
-+ VAConfigAttrib *attrib_list,/* out */
-+ int *num_attribs /* out */
-+);
-+
-+
-+/**
-+ * Contexts and Surfaces
-+ *
-+ * Context represents a "virtual" video decode, encode or video processing
-+ * pipeline. Surfaces are render targets for a given context. The data in the
-+ * surfaces are not accessible to the client except if derived image is supported
-+ * and the internal data format of the surface is implementation specific.
-+ *
-+ * Surfaces are provided as a hint of what surfaces will be used when the context
-+ * is created through vaCreateContext(). A surface may be used by different contexts
-+ * at the same time as soon as application can make sure the operations are synchronized
-+ * between different contexts, e.g. a surface is used as the output of a decode context
-+ * and the input of a video process context. Surfaces can only be destroyed after all
-+ * contexts using these surfaces have been destroyed.
-+ *
-+ * Both contexts and surfaces are identified by unique IDs and its
-+ * implementation specific internals are kept opaque to the clients
-+ */
-+
-+typedef VAGenericID VAContextID;
-+
-+typedef VAGenericID VASurfaceID;
-+
-+#define VA_INVALID_ID 0xffffffff
-+#define VA_INVALID_SURFACE VA_INVALID_ID
-+
-+/** \brief Generic value types. */
-+typedef enum {
-+ VAGenericValueTypeInteger = 1, /**< 32-bit signed integer. */
-+ VAGenericValueTypeFloat, /**< 32-bit floating-point value. */
-+ VAGenericValueTypePointer, /**< Generic pointer type */
-+ VAGenericValueTypeFunc /**< Pointer to function */
-+} VAGenericValueType;
-+
-+/** \brief Generic function type. */
-+typedef void (*VAGenericFunc)(void);
-+
-+/** \brief Generic value. */
-+typedef struct _VAGenericValue {
-+ /** \brief Value type. See #VAGenericValueType. */
-+ VAGenericValueType type;
-+ /** \brief Value holder. */
-+ union {
-+ /** \brief 32-bit signed integer. */
-+ int32_t i;
-+ /** \brief 32-bit float. */
-+ float f;
-+ /** \brief Generic pointer. */
-+ void *p;
-+ /** \brief Pointer to function. */
-+ VAGenericFunc fn;
-+ } value;
-+} VAGenericValue;
-+
-+/** @name Surface attribute flags */
-+/**@{*/
-+/** \brief Surface attribute is not supported. */
-+#define VA_SURFACE_ATTRIB_NOT_SUPPORTED 0x00000000
-+/** \brief Surface attribute can be got through vaQuerySurfaceAttributes(). */
-+#define VA_SURFACE_ATTRIB_GETTABLE 0x00000001
-+/** \brief Surface attribute can be set through vaCreateSurfaces(). */
-+#define VA_SURFACE_ATTRIB_SETTABLE 0x00000002
-+/**@}*/
-+
-+/** \brief Surface attribute types. */
-+typedef enum {
-+ VASurfaceAttribNone = 0,
-+ /**
-+ * \brief Pixel format (fourcc).
-+ *
-+ * The value is meaningful as input to vaQuerySurfaceAttributes().
-+ * If zero, the driver returns the optimal pixel format for the
-+ * specified config. Otherwise, if non-zero, the value represents
-+ * a pixel format (FOURCC) that is kept as is on output, if the
-+ * driver supports it. Otherwise, the driver sets the value to
-+ * zero and drops the \c VA_SURFACE_ATTRIB_SETTABLE flag.
-+ */
-+ VASurfaceAttribPixelFormat,
-+ /** \brief Minimal width in pixels (int, read-only). */
-+ VASurfaceAttribMinWidth,
-+ /** \brief Maximal width in pixels (int, read-only). */
-+ VASurfaceAttribMaxWidth,
-+ /** \brief Minimal height in pixels (int, read-only). */
-+ VASurfaceAttribMinHeight,
-+ /** \brief Maximal height in pixels (int, read-only). */
-+ VASurfaceAttribMaxHeight,
-+ /** \brief Surface memory type expressed in bit fields (int, read/write). */
-+ VASurfaceAttribMemoryType,
-+ /** \brief External buffer descriptor (pointer, write).
-+ *
-+ * Refer to the documentation for the memory type being created to
-+ * determine what descriptor structure to pass here. If not otherwise
-+ * stated, the common VASurfaceAttribExternalBuffers should be used.
-+ */
-+ VASurfaceAttribExternalBufferDescriptor,
-+ /** \brief Surface usage hint, gives the driver a hint of intended usage
-+ * to optimize allocation (e.g. tiling) (int, read/write). */
-+ VASurfaceAttribUsageHint,
-+ /** \brief Number of surface attributes. */
-+ VASurfaceAttribCount
-+} VASurfaceAttribType;
-+
-+/** \brief Surface attribute. */
-+typedef struct _VASurfaceAttrib {
-+ /** \brief Type. */
-+ VASurfaceAttribType type;
-+ /** \brief Flags. See "Surface attribute flags". */
-+ uint32_t flags;
-+ /** \brief Value. See "Surface attribute types" for the expected types. */
-+ VAGenericValue value;
-+} VASurfaceAttrib;
-+
-+/**
-+ * @name VASurfaceAttribMemoryType values in bit fields.
-+ * Bit 0:7 are reserved for generic types, Bit 31:28 are reserved for
-+ * Linux DRM, Bit 23:20 are reserved for Android. DRM and Android specific
-+ * types are defined in DRM and Android header files.
-+ */
-+/**@{*/
-+/** \brief VA memory type (default) is supported. */
-+#define VA_SURFACE_ATTRIB_MEM_TYPE_VA 0x00000001
-+/** \brief V4L2 buffer memory type is supported. */
-+#define VA_SURFACE_ATTRIB_MEM_TYPE_V4L2 0x00000002
-+/** \brief User pointer memory type is supported. */
-+#define VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR 0x00000004
-+/**@}*/
-+
-+/**
-+ * \brief VASurfaceAttribExternalBuffers structure for
-+ * the VASurfaceAttribExternalBufferDescriptor attribute.
-+ */
-+typedef struct _VASurfaceAttribExternalBuffers {
-+ /** \brief pixel format in fourcc. */
-+ uint32_t pixel_format;
-+ /** \brief width in pixels. */
-+ uint32_t width;
-+ /** \brief height in pixels. */
-+ uint32_t height;
-+ /** \brief total size of the buffer in bytes. */
-+ uint32_t data_size;
-+ /** \brief number of planes for planar layout */
-+ uint32_t num_planes;
-+ /** \brief pitch for each plane in bytes */
-+ uint32_t pitches[4];
-+ /** \brief offset for each plane in bytes */
-+ uint32_t offsets[4];
-+ /** \brief buffer handles or user pointers */
-+ uintptr_t *buffers;
-+ /** \brief number of elements in the "buffers" array */
-+ uint32_t num_buffers;
-+ /** \brief flags. See "Surface external buffer descriptor flags". */
-+ uint32_t flags;
-+ /** \brief reserved for passing private data */
-+ void *private_data;
-+} VASurfaceAttribExternalBuffers;
-+
-+/** @name VASurfaceAttribExternalBuffers flags */
-+/**@{*/
-+/** \brief Enable memory tiling */
-+#define VA_SURFACE_EXTBUF_DESC_ENABLE_TILING 0x00000001
-+/** \brief Memory is cacheable */
-+#define VA_SURFACE_EXTBUF_DESC_CACHED 0x00000002
-+/** \brief Memory is non-cacheable */
-+#define VA_SURFACE_EXTBUF_DESC_UNCACHED 0x00000004
-+/** \brief Memory is write-combined */
-+#define VA_SURFACE_EXTBUF_DESC_WC 0x00000008
-+/** \brief Memory is protected */
-+#define VA_SURFACE_EXTBUF_DESC_PROTECTED 0x80000000
-+
-+/** @name VASurfaceAttribUsageHint attribute usage hint flags */
-+/**@{*/
-+/** \brief Surface usage not indicated. */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC 0x00000000
-+/** \brief Surface used by video decoder. */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_DECODER 0x00000001
-+/** \brief Surface used by video encoder. */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER 0x00000002
-+/** \brief Surface read by video post-processing. */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ 0x00000004
-+/** \brief Surface written by video post-processing. */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_VPP_WRITE 0x00000008
-+/** \brief Surface used for display. */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_DISPLAY 0x00000010
-+/** \brief Surface used for export to third-party APIs, e.g. via
-+ * vaExportSurfaceHandle(). */
-+#define VA_SURFACE_ATTRIB_USAGE_HINT_EXPORT 0x00000020
-+
-+/**@}*/
-+
-+/**
-+ * \brief Queries surface attributes for the supplied config.
-+ *
-+ * This function queries for all supported attributes for the
-+ * supplied VA @config. In particular, if the underlying hardware
-+ * supports the creation of VA surfaces in various formats, then
-+ * this function will enumerate all pixel formats that are supported.
-+ *
-+ * The \c attrib_list array is allocated by the user and \c
-+ * num_attribs shall be initialized to the number of allocated
-+ * elements in that array. Upon successful return, the actual number
-+ * of attributes will be overwritten into \c num_attribs. Otherwise,
-+ * \c VA_STATUS_ERROR_MAX_NUM_EXCEEDED is returned and \c num_attribs
-+ * is adjusted to the number of elements that would be returned if
-+ * enough space was available.
-+ *
-+ * Note: it is perfectly valid to pass NULL to the \c attrib_list
-+ * argument when vaQuerySurfaceAttributes() is used to determine the
-+ * actual number of elements that need to be allocated.
-+ *
-+ * @param[in] dpy the VA display
-+ * @param[in] config the config identifying a codec or a video
-+ * processing pipeline
-+ * @param[out] attrib_list the output array of #VASurfaceAttrib elements
-+ * @param[in,out] num_attribs the number of elements allocated on
-+ * input, the number of elements actually filled in output
-+ */
-+VAStatus
-+vaQuerySurfaceAttributes(
-+ VADisplay dpy,
-+ VAConfigID config,
-+ VASurfaceAttrib *attrib_list,
-+ unsigned int *num_attribs
-+);
-+
-+/**
-+ * \brief Creates an array of surfaces
-+ *
-+ * Creates an array of surfaces. The optional list of attributes shall
-+ * be constructed based on what the underlying hardware could expose
-+ * through vaQuerySurfaceAttributes().
-+ *
-+ * @param[in] dpy the VA display
-+ * @param[in] format the desired surface format. See \c VA_RT_FORMAT_*
-+ * @param[in] width the surface width
-+ * @param[in] height the surface height
-+ * @param[out] surfaces the array of newly created surfaces
-+ * @param[in] num_surfaces the number of surfaces to create
-+ * @param[in] attrib_list the list of (optional) attributes, or \c NULL
-+ * @param[in] num_attribs the number of attributes supplied in
-+ * \c attrib_list, or zero
-+ */
-+VAStatus
-+vaCreateSurfaces(
-+ VADisplay dpy,
-+ unsigned int format,
-+ unsigned int width,
-+ unsigned int height,
-+ VASurfaceID *surfaces,
-+ unsigned int num_surfaces,
-+ VASurfaceAttrib *attrib_list,
-+ unsigned int num_attribs
-+);
-+
-+/**
-+ * vaDestroySurfaces - Destroy resources associated with surfaces.
-+ * Surfaces can only be destroyed after all contexts using these surfaces have been
-+ * destroyed.
-+ * dpy: display
-+ * surfaces: array of surfaces to destroy
-+ * num_surfaces: number of surfaces in the array to be destroyed.
-+ */
-+VAStatus vaDestroySurfaces (
-+ VADisplay dpy,
-+ VASurfaceID *surfaces,
-+ int num_surfaces
-+);
-+
-+#define VA_PROGRESSIVE 0x1
-+/**
-+ * vaCreateContext - Create a context
-+ * dpy: display
-+ * config_id: configuration for the context
-+ * picture_width: coded picture width
-+ * picture_height: coded picture height
-+ * flag: any combination of the following:
-+ * VA_PROGRESSIVE (only progressive frame pictures in the sequence when set)
-+ * render_targets: a hint for render targets (surfaces) tied to the context
-+ * num_render_targets: number of render targets in the above array
-+ * context: created context id upon return
-+ */
-+VAStatus vaCreateContext (
-+ VADisplay dpy,
-+ VAConfigID config_id,
-+ int picture_width,
-+ int picture_height,
-+ int flag,
-+ VASurfaceID *render_targets,
-+ int num_render_targets,
-+ VAContextID *context /* out */
-+);
-+
-+/**
-+ * vaDestroyContext - Destroy a context
-+ * dpy: display
-+ * context: context to be destroyed
-+ */
-+VAStatus vaDestroyContext (
-+ VADisplay dpy,
-+ VAContextID context
-+);
-+
-+//Multi-frame context
-+typedef VAGenericID VAMFContextID;
-+/**
-+ * vaCreateMFContext - Create a multi-frame context
-+ * interface encapsulating common for all streams memory objects and structures
-+ * required for single GPU task submission from several VAContextID's.
-+ * Allocation: This call only creates an instance, doesn't allocate any additional memory.
-+ * Support identification: Application can identify multi-frame feature support by ability
-+ * to create multi-frame context. If driver supports multi-frame - call successful,
-+ * mf_context != NULL and VAStatus = VA_STATUS_SUCCESS, otherwise if multi-frame processing
-+ * not supported driver returns VA_STATUS_ERROR_UNIMPLEMENTED and mf_context = NULL.
-+ * return values:
-+ * VA_STATUS_SUCCESS - operation successful.
-+ * VA_STATUS_ERROR_UNIMPLEMENTED - no support for multi-frame.
-+ * dpy: display adapter.
-+ * mf_context: Multi-Frame context encapsulating all associated context
-+ * for multi-frame submission.
-+ */
-+VAStatus vaCreateMFContext (
-+ VADisplay dpy,
-+ VAMFContextID *mf_context /* out */
-+);
-+
-+/**
-+ * vaMFAddContext - Provide ability to associate each context used for
-+ * Multi-Frame submission and common Multi-Frame context.
-+ * Try to add context to understand if it is supported.
-+ * Allocation: this call allocates and/or reallocates all memory objects
-+ * common for all contexts associated with particular Multi-Frame context.
-+ * All memory required for each context(pixel buffers, internal driver
-+ * buffers required for processing) allocated during standard vaCreateContext call for each context.
-+ * Runtime dependency - if current implementation doesn't allow to run different entry points/profile,
-+ * first context added will set entry point/profile for whole Multi-Frame context,
-+ * all other entry points and profiles can be rejected to be added.
-+ * Return values:
-+ * VA_STATUS_SUCCESS - operation successful, context was added.
-+ * VA_STATUS_ERROR_OPERATION_FAILED - something unexpected happened - application have to close
-+ * current mf_context and associated contexts and start working with new ones.
-+ * VA_STATUS_ERROR_INVALID_CONTEXT - ContextID is invalid, means:
-+ * 1 - mf_context is not valid context or
-+ * 2 - driver can't suport different VAEntrypoint or VAProfile simultaneosly
-+ * and current context contradicts with previously added, application can continue with current mf_context
-+ * and other contexts passed this call, rejected context can continue work in stand-alone
-+ * mode or other mf_context.
-+ * VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT - particular context being added was created with with
-+ * unsupported VAEntrypoint. Application can continue with current mf_context
-+ * and other contexts passed this call, rejected context can continue work in stand-alone
-+ * mode.
-+ * VA_STATUS_ERROR_UNSUPPORTED_PROFILE - Current context with Particular VAEntrypoint is supported
-+ * but VAProfile is not supported. Application can continue with current mf_context
-+ * and other contexts passed this call, rejected context can continue work in stand-alone
-+ * mode.
-+ * dpy: display adapter.
-+ * context: context being associated with Multi-Frame context.
-+ * mf_context: - multi-frame context used to associate contexts for multi-frame submission.
-+ */
-+VAStatus vaMFAddContext (
-+ VADisplay dpy,
-+ VAMFContextID mf_context,
-+ VAContextID context
-+);
-+
-+/**
-+ * vaMFReleaseContext - Removes context from multi-frame and
-+ * association with multi-frame context.
-+ * After association removed vaEndPicture will submit tasks, but not vaMFSubmit.
-+ * Return values:
-+ * VA_STATUS_SUCCESS - operation successful, context was removed.
-+ * VA_STATUS_ERROR_OPERATION_FAILED - something unexpected happened.
-+ * application need to destroy this VAMFContextID and all assotiated VAContextID
-+ * dpy: display
-+ * mf_context: VAMFContextID where context is added
-+ * context: VAContextID to be added
-+ */
-+VAStatus vaMFReleaseContext (
-+ VADisplay dpy,
-+ VAMFContextID mf_context,
-+ VAContextID context
-+);
-+
-+/**
-+ * Buffers
-+ * Buffers are used to pass various types of data from the
-+ * client to the server. The server maintains a data store
-+ * for each buffer created, and the client idenfies a buffer
-+ * through a unique buffer id assigned by the server.
-+ */
-+
-+typedef VAGenericID VABufferID;
-+
-+typedef enum
-+{
-+ VAPictureParameterBufferType = 0,
-+ VAIQMatrixBufferType = 1,
-+ VABitPlaneBufferType = 2,
-+ VASliceGroupMapBufferType = 3,
-+ VASliceParameterBufferType = 4,
-+ VASliceDataBufferType = 5,
-+ VAMacroblockParameterBufferType = 6,
-+ VAResidualDataBufferType = 7,
-+ VADeblockingParameterBufferType = 8,
-+ VAImageBufferType = 9,
-+ VAProtectedSliceDataBufferType = 10,
-+ VAQMatrixBufferType = 11,
-+ VAHuffmanTableBufferType = 12,
-+ VAProbabilityBufferType = 13,
-+
-+/* Following are encode buffer types */
-+ VAEncCodedBufferType = 21,
-+ VAEncSequenceParameterBufferType = 22,
-+ VAEncPictureParameterBufferType = 23,
-+ VAEncSliceParameterBufferType = 24,
-+ VAEncPackedHeaderParameterBufferType = 25,
-+ VAEncPackedHeaderDataBufferType = 26,
-+ VAEncMiscParameterBufferType = 27,
-+ VAEncMacroblockParameterBufferType = 28,
-+ VAEncMacroblockMapBufferType = 29,
-+
-+ /**
-+ * \brief Encoding QP buffer
-+ *
-+ * This buffer contains QP per MB for encoding. Currently
-+ * VAEncQPBufferH264 is defined for H.264 encoding, see
-+ * #VAEncQPBufferH264 for details
-+ */
-+ VAEncQPBufferType = 30,
-+/* Following are video processing buffer types */
-+ /**
-+ * \brief Video processing pipeline parameter buffer.
-+ *
-+ * This buffer describes the video processing pipeline. See
-+ * #VAProcPipelineParameterBuffer for details.
-+ */
-+ VAProcPipelineParameterBufferType = 41,
-+ /**
-+ * \brief Video filter parameter buffer.
-+ *
-+ * This buffer describes the video filter parameters. All buffers
-+ * inherit from #VAProcFilterParameterBufferBase, thus including
-+ * a unique filter buffer type.
-+ *
-+ * The default buffer used by most filters is #VAProcFilterParameterBuffer.
-+ * Filters requiring advanced parameters include, but are not limited to,
-+ * deinterlacing (#VAProcFilterParameterBufferDeinterlacing),
-+ * color balance (#VAProcFilterParameterBufferColorBalance), etc.
-+ */
-+ VAProcFilterParameterBufferType = 42,
-+ /**
-+ * \brief FEI specific buffer types
-+ */
-+ VAEncFEIMVBufferType = 43,
-+ VAEncFEIMBCodeBufferType = 44,
-+ VAEncFEIDistortionBufferType = 45,
-+ VAEncFEIMBControlBufferType = 46,
-+ VAEncFEIMVPredictorBufferType = 47,
-+ VAStatsStatisticsParameterBufferType = 48,
-+ /** \brief Statistics output for VAEntrypointStats progressive and top field of interlaced case*/
-+ VAStatsStatisticsBufferType = 49,
-+ /** \brief Statistics output for VAEntrypointStats bottom field of interlaced case*/
-+ VAStatsStatisticsBottomFieldBufferType = 50,
-+ VAStatsMVBufferType = 51,
-+ VAStatsMVPredictorBufferType = 52,
-+ /** Force MB's to be non skip for encode.it's per-mb control buffer, The width of the MB map
-+ * Surface is (width of the Picture in MB unit) * 1 byte, multiple of 64 bytes.
-+ * The height is (height of the picture in MB unit). The picture is either
-+ * frame or non-interleaved top or bottom field. If the application provides this
-+ *surface, it will override the "skipCheckDisable" setting in VAEncMiscParameterEncQuality.
-+ */
-+ VAEncMacroblockDisableSkipMapBufferType = 53,
-+ /**
-+ * \brief HEVC FEI CTB level cmd buffer
-+ * it is CTB level information for future usage.
-+ */
-+ VAEncFEICTBCmdBufferType = 54,
-+ /**
-+ * \brief HEVC FEI CU level data buffer
-+ * it's CTB level information for future usage
-+ */
-+ VAEncFEICURecordBufferType = 55,
-+ /** decode stream out buffer, intermedia data of decode, it may include MV, MB mode etc.
-+ * it can be used to detect motion and analyze the frame contain */
-+ VADecodeStreamoutBufferType = 56,
-+
-+ /** \brief HEVC Decoding Subset Parameter buffer type
-+ *
-+ * The subsets parameter buffer is concatenation with one or multiple
-+ * subset entry point offsets. All the offset values are layed out one
-+ * by one according to slice order with first slice segment first, second
-+ * slice segment second, etc... The entry number is indicated by parameter
-+ * \ref num_entry_point_offsets. And the first entry position of the entry
-+ * point offsets for any slice segment is indicated by parameter
-+ * entry_offset_to_subset_array in VAPictureParameterBufferHEVC data structure.
-+ */
-+ VASubsetsParameterBufferType = 57,
-+
-+ VABufferTypeMax
-+} VABufferType;
-+
-+/**
-+ * Processing rate parameter for encode.
-+ */
-+typedef struct _VAProcessingRateParameterEnc {
-+ /** \brief Profile level */
-+ uint8_t level_idc;
-+ uint8_t reserved[3];
-+ /** \brief quality level. When set to 0, default quality
-+ * level is used.
-+ */
-+ uint32_t quality_level;
-+ /** \brief Period between I frames. */
-+ uint32_t intra_period;
-+ /** \brief Period between I/P frames. */
-+ uint32_t ip_period;
-+} VAProcessingRateParameterEnc;
-+
-+/**
-+ * Processing rate parameter for decode.
-+ */
-+typedef struct _VAProcessingRateParameterDec {
-+ /** \brief Profile level */
-+ uint8_t level_idc;
-+ uint8_t reserved0[3];
-+ uint32_t reserved;
-+} VAProcessingRateParameterDec;
-+
-+typedef struct _VAProcessingRateParameter {
-+ union {
-+ VAProcessingRateParameterEnc proc_buf_enc;
-+ VAProcessingRateParameterDec proc_buf_dec;
-+ };
-+} VAProcessingRateParameter;
-+
-+/**
-+ * \brief Queries processing rate for the supplied config.
-+ *
-+ * This function queries the processing rate based on parameters in
-+ * \c proc_buf for the given \c config. Upon successful return, the processing
-+ * rate value will be stored in \c processing_rate. Processing rate is
-+ * specified as the number of macroblocks/CTU per second.
-+ *
-+ * If NULL is passed to the \c proc_buf, the default processing rate for the
-+ * given configuration will be returned.
-+ *
-+ * @param[in] dpy the VA display
-+ * @param[in] config the config identifying a codec or a video
-+ * processing pipeline
-+ * @param[in] proc_buf the buffer that contains the parameters for
-+ either the encode or decode processing rate
-+ * @param[out] processing_rate processing rate in number of macroblocks per
-+ second constrained by parameters specified in proc_buf
-+ *
-+ */
-+VAStatus
-+vaQueryProcessingRate(
-+ VADisplay dpy,
-+ VAConfigID config,
-+ VAProcessingRateParameter *proc_buf,
-+ unsigned int *processing_rate
-+);
-+
-+typedef enum
-+{
-+ VAEncMiscParameterTypeFrameRate = 0,
-+ VAEncMiscParameterTypeRateControl = 1,
-+ VAEncMiscParameterTypeMaxSliceSize = 2,
-+ VAEncMiscParameterTypeAIR = 3,
-+ /** \brief Buffer type used to express a maximum frame size (in bits). */
-+ VAEncMiscParameterTypeMaxFrameSize = 4,
-+ /** \brief Buffer type used for HRD parameters. */
-+ VAEncMiscParameterTypeHRD = 5,
-+ VAEncMiscParameterTypeQualityLevel = 6,
-+ /** \brief Buffer type used for Rolling intra refresh */
-+ VAEncMiscParameterTypeRIR = 7,
-+ /** \brief Buffer type used for quantization parameters, it's per-sequence parameter*/
-+ VAEncMiscParameterTypeQuantization = 8,
-+ /** \brief Buffer type used for sending skip frame parameters to the encoder's
-+ * rate control, when the user has externally skipped frames. */
-+ VAEncMiscParameterTypeSkipFrame = 9,
-+ /** \brief Buffer type used for region-of-interest (ROI) parameters. */
-+ VAEncMiscParameterTypeROI = 10,
-+ /** \brief Buffer type used to express a maximum frame size (in bytes) settings for multiple pass. */
-+ VAEncMiscParameterTypeMultiPassFrameSize = 11,
-+ /** \brief Buffer type used for temporal layer structure */
-+ VAEncMiscParameterTypeTemporalLayerStructure = 12,
-+ /** \brief Buffer type used for dirty region-of-interest (ROI) parameters. */
-+ VAEncMiscParameterTypeDirtyRect = 13,
-+ /** \brief Buffer type used for parallel BRC parameters. */
-+ VAEncMiscParameterTypeParallelBRC = 14,
-+ /** \brief Set MB partion mode mask and Half-pel/Quant-pel motion search */
-+ VAEncMiscParameterTypeSubMbPartPel = 15,
-+ /** \brief set encode quality tuning */
-+ VAEncMiscParameterTypeEncQuality = 16,
-+ /** \brief Buffer type used for encoder rounding offset parameters. */
-+ VAEncMiscParameterTypeCustomRoundingControl = 17,
-+ /** \brief Buffer type used for FEI input frame level parameters */
-+ VAEncMiscParameterTypeFEIFrameControl = 18,
-+ /** \brief encode extension buffer, ect. MPEG2 Sequence extenstion data */
-+ VAEncMiscParameterTypeExtensionData = 19
-+} VAEncMiscParameterType;
-+
-+/** \brief Packed header type. */
-+typedef enum {
-+ /** \brief Packed sequence header. */
-+ VAEncPackedHeaderSequence = 1,
-+ /** \brief Packed picture header. */
-+ VAEncPackedHeaderPicture = 2,
-+ /** \brief Packed slice header. */
-+ VAEncPackedHeaderSlice = 3,
-+ /**
-+ * \brief Packed raw header.
-+ *
-+ * Packed raw data header can be used by the client to insert a header
-+ * into the bitstream data buffer at the point it is passed, the driver
-+ * will handle the raw packed header based on "has_emulation_bytes" field
-+ * in the packed header parameter structure.
-+ */
-+ VAEncPackedHeaderRawData = 4,
-+ /**
-+ * \brief Misc packed header. See codec-specific definitions.
-+ *
-+ * @deprecated
-+ * This is a deprecated packed header type. All applications can use
-+ * \c VAEncPackedHeaderRawData to insert a codec-specific packed header
-+ */
-+ VAEncPackedHeaderMiscMask va_deprecated_enum = 0x80000000,
-+} VAEncPackedHeaderType;
-+
-+/** \brief Packed header parameter. */
-+typedef struct _VAEncPackedHeaderParameterBuffer {
-+ /** Type of the packed header buffer. See #VAEncPackedHeaderType. */
-+ uint32_t type;
-+ /** \brief Size of the #VAEncPackedHeaderDataBuffer in bits. */
-+ uint32_t bit_length;
-+ /** \brief Flag: buffer contains start code emulation prevention bytes? */
-+ uint8_t has_emulation_bytes;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncPackedHeaderParameterBuffer;
-+
-+/**
-+ * For application, e.g. set a new bitrate
-+ * VABufferID buf_id;
-+ * VAEncMiscParameterBuffer *misc_param;
-+ * VAEncMiscParameterRateControl *misc_rate_ctrl;
-+ *
-+ * vaCreateBuffer(dpy, context, VAEncMiscParameterBufferType,
-+ * sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterRateControl),
-+ * 1, NULL, &buf_id);
-+ *
-+ * vaMapBuffer(dpy,buf_id,(void **)&misc_param);
-+ * misc_param->type = VAEncMiscParameterTypeRateControl;
-+ * misc_rate_ctrl= (VAEncMiscParameterRateControl *)misc_param->data;
-+ * misc_rate_ctrl->bits_per_second = 6400000;
-+ * vaUnmapBuffer(dpy, buf_id);
-+ * vaRenderPicture(dpy, context, &buf_id, 1);
-+ */
-+typedef struct _VAEncMiscParameterBuffer
-+{
-+ VAEncMiscParameterType type;
-+ uint32_t data[];
-+} VAEncMiscParameterBuffer;
-+
-+/** \brief Temporal layer Structure*/
-+typedef struct _VAEncMiscParameterTemporalLayerStructure
-+{
-+ /** \brief The number of temporal layers */
-+ uint32_t number_of_layers;
-+ /** \brief The length of the array defining frame layer membership. Should be 1-32 */
-+ uint32_t periodicity;
-+ /**
-+ * \brief The array indicating the layer id for each frame
-+ *
-+ * The layer id for the first frame in a coded sequence is always 0, so layer_id[] specifies the layer
-+ * ids for frames starting from the 2nd frame.
-+ */
-+ uint32_t layer_id[32];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterTemporalLayerStructure;
-+
-+
-+/** \brief Rate control parameters */
-+typedef struct _VAEncMiscParameterRateControl
-+{
-+ /** The maximum bit-rate which the the rate controller should generate. */
-+ uint32_t bits_per_second;
-+ /** The target bit-rate which the rate controller should generate, as a percentage of the
-+ * maximum bit-rate.
-+ *
-+ * In CBR mode this value is ignored (treated as 100%).
-+ */
-+ uint32_t target_percentage;
-+ /** Rate control window size in milliseconds.
-+ *
-+ * The rate controller will attempt to guarantee that the target and maximum bit-rates are
-+ * correct over this window.
-+ */
-+ uint32_t window_size;
-+ /** Initial quantiser value used at the start of the stream.
-+ *
-+ * Ignored if set to zero.
-+ */
-+ uint32_t initial_qp;
-+ /** Minimum quantiser value to use.
-+ *
-+ * The quantiser will not go below the value - if this limit is hit, the output bitrate may
-+ * be lower than the target. Ignored if set to zero.
-+ */
-+ uint32_t min_qp;
-+ /** Basic unit size.
-+ *
-+ * Only used by some drivers - see driver documentation for details. Set to zero if unused.
-+ */
-+ uint32_t basic_unit_size;
-+ union
-+ {
-+ struct
-+ {
-+ /** Force rate controller reset.
-+ *
-+ * The next frame will be treated as the start of a new stream, with all rate
-+ * controller state reset to its initial values.
-+ */
-+ uint32_t reset : 1;
-+ /** Disable frame skip in rate control mode. */
-+ uint32_t disable_frame_skip : 1;
-+ /** Disable bit stuffing in rate control mode. */
-+ uint32_t disable_bit_stuffing : 1;
-+ /** Macroblock-level rate control.
-+ *
-+ * 0: use default, 1: always enable, 2: always disable, other: reserved.
-+ *
-+ * This feature is only available if VAConfigAttribRateControl has the
-+ * \ref VA_RC_MB bit set.
-+ */
-+ uint32_t mb_rate_control : 4;
-+ /** The temporal layer that these rate control parameters apply to. */
-+ uint32_t temporal_id : 8;
-+ /** Ensure that intra frames also conform to the constant frame size. */
-+ uint32_t cfs_I_frames : 1;
-+ /** Enable parallel rate control for hierarchical B frames.
-+ *
-+ * See \ref VA_RC_PARALLEL.
-+ */
-+ uint32_t enable_parallel_brc : 1;
-+ uint32_t enable_dynamic_scaling : 1;
-+ /** Frame tolerance mode.
-+ *
-+ * Indicates the tolerance the application has to variations in the frame size.
-+ * For example, wireless display scenarios may require very steady bit rate to
-+ * reduce buffering time. It affects the rate control algorithm used,
-+ * but may or may not have an effect based on the combination of other BRC
-+ * parameters. Only valid when the driver reports support for
-+ * #VAConfigAttribFrameSizeToleranceSupport.
-+ *
-+ * equals 0 -- normal mode;
-+ * equals 1 -- maps to sliding window;
-+ * equals 2 -- maps to low delay mode;
-+ * other -- invalid.
-+ */
-+ uint32_t frame_tolerance_mode : 2;
-+ /** Reserved for future use, must be zero. */
-+ uint32_t reserved : 12;
-+ } bits;
-+ uint32_t value;
-+ } rc_flags;
-+ /** Initial quality factor used in ICQ mode.
-+ *
-+ * This value must be between 1 and 51.
-+ * this value will be deprecated in future, to use quality_factor instead of it.
-+ */
-+ uint32_t ICQ_quality_factor;
-+ /** Maximum quantiser value to use.
-+ *
-+ * The quantiser will not go above this value - if this limit is hit, the output bitrate
-+ * may exceed the target. Ignored if set to zero.
-+ */
-+ uint32_t max_qp;
-+ /** Quality factor
-+ *
-+ * the range will be different for different codec
-+ */
-+ uint32_t quality_factor;
-+ /** Reserved bytes for future use, must be zero. */
-+ uint32_t va_reserved[VA_PADDING_MEDIUM - 3];
-+} VAEncMiscParameterRateControl;
-+
-+/** Encode framerate parameters.
-+ *
-+ * Sets the encode framerate used by the rate controller. This should be
-+ * provided in all modes using a bitrate target (variable framerate is not
-+ * supported).
-+ */
-+typedef struct _VAEncMiscParameterFrameRate
-+{
-+ /** Encode framerate.
-+ *
-+ * The framerate is specified as a number of frames per second, as a
-+ * fraction. The denominator of the fraction is given in the top half
-+ * (the high two bytes) of the framerate field, and the numerator is
-+ * given in the bottom half (the low two bytes).
-+ *
-+ * That is:
-+ * denominator = framerate >> 16 & 0xffff;
-+ * numerator = framerate & 0xffff;
-+ * fps = numerator / denominator;
-+ *
-+ * For example, if framerate is set to (100 << 16 | 750), this is
-+ * 750 / 100, hence 7.5fps.
-+ *
-+ * If the denominator is zero (the high two bytes are both zero) then
-+ * it takes the value one instead, so the framerate is just the integer
-+ * in the low 2 bytes.
-+ */
-+ uint32_t framerate;
-+ union
-+ {
-+ struct
-+ {
-+ /** The temporal layer that these framerate parameters apply to. */
-+ uint32_t temporal_id : 8;
-+ /** Reserved for future use, must be zero. */
-+ uint32_t reserved : 24;
-+ } bits;
-+ uint32_t value;
-+ } framerate_flags;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterFrameRate;
-+
-+/**
-+ * Allow a maximum slice size to be specified (in bits).
-+ * The encoder will attempt to make sure that individual slices do not exceed this size
-+ * Or to signal applicate if the slice size exceed this size, see "status" of VACodedBufferSegment
-+ */
-+typedef struct _VAEncMiscParameterMaxSliceSize
-+{
-+ uint32_t max_slice_size;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterMaxSliceSize;
-+
-+typedef struct _VAEncMiscParameterAIR
-+{
-+ uint32_t air_num_mbs;
-+ uint32_t air_threshold;
-+ uint32_t air_auto; /* if set to 1 then hardware auto-tune the AIR threshold */
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterAIR;
-+
-+/*
-+ * \brief Rolling intra refresh data structure for encoding.
-+ */
-+typedef struct _VAEncMiscParameterRIR
-+{
-+ union
-+ {
-+ struct
-+ /**
-+ * \brief Indicate if intra refresh is enabled in column/row.
-+ *
-+ * App should query VAConfigAttribEncIntraRefresh to confirm RIR support
-+ * by the driver before sending this structure.
-+ */
-+ {
-+ /* \brief enable RIR in column */
-+ uint32_t enable_rir_column : 1;
-+ /* \brief enable RIR in row */
-+ uint32_t enable_rir_row : 1;
-+ uint32_t reserved : 30;
-+ } bits;
-+ uint32_t value;
-+ } rir_flags;
-+ /**
-+ * \brief Indicates the column or row location in MB. It is ignored if
-+ * rir_flags is 0.
-+ */
-+ uint16_t intra_insertion_location;
-+ /**
-+ * \brief Indicates the number of columns or rows in MB. It is ignored if
-+ * rir_flags is 0.
-+ */
-+ uint16_t intra_insert_size;
-+ /**
-+ * \brief indicates the Qp difference for inserted intra columns or rows.
-+ * App can use this to adjust intra Qp based on bitrate & max frame size.
-+ */
-+ uint8_t qp_delta_for_inserted_intra;
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterRIR;
-+
-+/** HRD / VBV buffering parameters for encoding.
-+ *
-+ * This sets the HRD / VBV parameters which will be used by the rate
-+ * controller for encoding. It should be specified in modes using a bitrate
-+ * target when the buffering of the output stream needs to be constrained.
-+ *
-+ * If not provided, the encoder may use arbitrary amounts of buffering.
-+ */
-+typedef struct _VAEncMiscParameterHRD
-+{
-+ /** The initial fullness of the HRD coded picture buffer, in bits.
-+ *
-+ * This sets how full the CPB is when encoding begins - that is, how much
-+ * buffering will happen on the decoder side before the first frame.
-+ * The CPB fullness will be reset to this value after any rate control
-+ * reset (a change in parameters or an explicit reset).
-+ *
-+ * For H.264, it should match the value of initial_cpb_removal_delay in
-+ * buffering_period SEI messages.
-+ */
-+ uint32_t initial_buffer_fullness;
-+ /** The HRD coded picture buffer size, in bits.
-+ *
-+ * For H.264, it should match the value of cpb_size_value_minus1 in the VUI
-+ * parameters.
-+ */
-+ uint32_t buffer_size;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterHRD;
-+
-+/**
-+ * \brief Defines a maximum frame size (in bits).
-+ *
-+ * This misc parameter buffer defines the maximum size of a frame (in
-+ * bits). The encoder will try to make sure that each frame does not
-+ * exceed this size. Otherwise, if the frame size exceeds this size,
-+ * the \c status flag of #VACodedBufferSegment will contain
-+ * #VA_CODED_BUF_STATUS_FRAME_SIZE_OVERFLOW.
-+ */
-+typedef struct _VAEncMiscParameterBufferMaxFrameSize {
-+ /** \brief Type. Shall be set to #VAEncMiscParameterTypeMaxFrameSize. */
-+ /** duplicated with VAEncMiscParameterBuffer, should be deprecated*/
-+ va_deprecated VAEncMiscParameterType type;
-+ /** \brief Maximum size of a frame (in bits). */
-+ uint32_t max_frame_size;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterBufferMaxFrameSize;
-+
-+/**
-+ * \brief Maximum frame size (in bytes) settings for multiple pass.
-+ *
-+ * This misc parameter buffer defines the maximum size of a frame (in
-+ * bytes) settings for multiple pass. currently only AVC encoder can
-+ * support this settings in multiple pass case. If the frame size exceeds
-+ * this size, the encoder will do more pak passes to adjust the QP value
-+ * to control the frame size.
-+ */
-+typedef struct _VAEncMiscParameterBufferMultiPassFrameSize {
-+ /** \brief Type. Shall be set to #VAEncMiscParameterTypeMultiPassMaxFrameSize. */
-+ /** duplicated with VAEncMiscParameterBuffer, should be deprecated*/
-+ va_deprecated VAEncMiscParameterType type;
-+ /** \brief Maximum size of a frame (in byte) */
-+ uint32_t max_frame_size;
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t reserved;
-+ /** \brief number of passes, every pass has different QP, currently AVC encoder can support up to 4 passes */
-+ uint8_t num_passes;
-+ /** \brief delta QP list for every pass */
-+ uint8_t *delta_qp;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ unsigned long va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterBufferMultiPassFrameSize;
-+
-+/**
-+ * \brief Encoding quality level.
-+ *
-+ * The encoding quality could be set through this structure, if the implementation
-+ * supports multiple quality levels. The quality level set through this structure is
-+ * persistent over the entire coded sequence, or until a new structure is being sent.
-+ * The quality level range can be queried through the VAConfigAttribEncQualityRange
-+ * attribute. A lower value means higher quality, and a value of 1 represents the highest
-+ * quality. The quality level setting is used as a trade-off between quality and speed/power
-+ * consumption, with higher quality corresponds to lower speed and higher power consumption.
-+ */
-+typedef struct _VAEncMiscParameterBufferQualityLevel {
-+ /** \brief Encoding quality level setting. When set to 0, default quality
-+ * level is used.
-+ */
-+ uint32_t quality_level;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterBufferQualityLevel;
-+
-+/**
-+ * \brief Quantization settings for encoding.
-+ *
-+ * Some encoders support special types of quantization such as trellis, and this structure
-+ * can be used by the app to control these special types of quantization by the encoder.
-+ */
-+typedef struct _VAEncMiscParameterQuantization
-+{
-+ union
-+ {
-+ /* if no flags is set then quantization is determined by the driver */
-+ struct
-+ {
-+ /* \brief disable trellis for all frames/fields */
-+ uint32_t disable_trellis : 1;
-+ /* \brief enable trellis for I frames/fields */
-+ uint32_t enable_trellis_I : 1;
-+ /* \brief enable trellis for P frames/fields */
-+ uint32_t enable_trellis_P : 1;
-+ /* \brief enable trellis for B frames/fields */
-+ uint32_t enable_trellis_B : 1;
-+ uint32_t reserved : 28;
-+ } bits;
-+ uint32_t value;
-+ } quantization_flags;
-+ uint32_t va_reserved;
-+} VAEncMiscParameterQuantization;
-+
-+/**
-+ * \brief Encoding skip frame.
-+ *
-+ * The application may choose to skip frames externally to the encoder (e.g. drop completely or
-+ * code as all skip's). For rate control purposes the encoder will need to know the size and number
-+ * of skipped frames. Skip frame(s) indicated through this structure is applicable only to the
-+ * current frame. It is allowed for the application to still send in packed headers for the driver to
-+ * pack, although no frame will be encoded (e.g. for HW to encrypt the frame).
-+ */
-+typedef struct _VAEncMiscParameterSkipFrame {
-+ /** \brief Indicates skip frames as below.
-+ * 0: Encode as normal, no skip.
-+ * 1: One or more frames were skipped prior to the current frame, encode the current frame as normal.
-+ * 2: The current frame is to be skipped, do not encode it but pack/encrypt the packed header contents
-+ * (all except VAEncPackedHeaderSlice) which could contain actual frame contents (e.g. pack the frame
-+ * in VAEncPackedHeaderPicture). */
-+ uint8_t skip_frame_flag;
-+ /** \brief The number of frames skipped prior to the current frame. Valid when skip_frame_flag = 1. */
-+ uint8_t num_skip_frames;
-+ /** \brief When skip_frame_flag = 1, the size of the skipped frames in bits. When skip_frame_flag = 2,
-+ * the size of the current skipped frame that is to be packed/encrypted in bits. */
-+ uint32_t size_skip_frames;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterSkipFrame;
-+
-+/**
-+ * \brief Encoding region-of-interest (ROI).
-+ *
-+ * The encoding ROI can be set through VAEncMiscParameterBufferROI, if the implementation
-+ * supports ROI input. The ROI set through this structure is applicable only to the
-+ * current frame or field, so must be sent every frame or field to be applied. The number of
-+ * supported ROIs can be queried through the VAConfigAttribEncROI. The encoder will use the
-+ * ROI information to adjust the QP values of the MB's that fall within the ROIs.
-+ */
-+typedef struct _VAEncROI
-+{
-+ /** \brief Defines the ROI boundary in pixels, the driver will map it to appropriate
-+ * codec coding units. It is relative to frame coordinates for the frame case and
-+ * to field coordinates for the field case. */
-+ VARectangle roi_rectangle;
-+ /**
-+ * \brief ROI value
-+ *
-+ * \ref roi_value specifies ROI delta QP or ROI priority.
-+ * -- ROI delta QP is the value that will be added on top of the frame level QP.
-+ * -- ROI priority specifies the priority of a region, it can be positive (more important)
-+ * or negative (less important) values and is compared with non-ROI region (taken as value 0),
-+ * E.g. ROI region with \ref roi_value -3 is less important than the non-ROI region (\ref roi_value
-+ * implied to be 0) which is less important than ROI region with roi_value +2. For overlapping
-+ * regions, the roi_value that is first in the ROI array will have priority.
-+ *
-+ * \ref roi_value always specifes ROI delta QP when VAConfigAttribRateControl == VA_RC_CQP, no matter
-+ * the value of \c roi_value_is_qp_delta in #VAEncMiscParameterBufferROI.
-+ *
-+ * \ref roi_value depends on \c roi_value_is_qp_delta in #VAEncMiscParameterBufferROI when
-+ * VAConfigAttribRateControl != VA_RC_CQP. \ref roi_value specifies ROI_delta QP if \c roi_value_is_qp_delta
-+ * in VAEncMiscParameterBufferROI is 1, otherwise \ref roi_value specifies ROI priority.
-+ */
-+ int8_t roi_value;
-+} VAEncROI;
-+
-+typedef struct _VAEncMiscParameterBufferROI {
-+ /** \brief Number of ROIs being sent.*/
-+ uint32_t num_roi;
-+
-+ /** \brief Valid when VAConfigAttribRateControl != VA_RC_CQP, then the encoder's
-+ * rate control will determine actual delta QPs. Specifies the max/min allowed delta
-+ * QPs. */
-+ int8_t max_delta_qp;
-+ int8_t min_delta_qp;
-+
-+ /** \brief Pointer to a VAEncROI array with num_roi elements. It is relative to frame
-+ * coordinates for the frame case and to field coordinates for the field case.*/
-+ VAEncROI *roi;
-+ union {
-+ struct {
-+ /**
-+ * \brief An indication for roi value.
-+ *
-+ * \ref roi_value_is_qp_delta equal to 1 indicates \c roi_value in #VAEncROI should
-+ * be used as ROI delta QP. \ref roi_value_is_qp_delta equal to 0 indicates \c roi_value
-+ * in #VAEncROI should be used as ROI priority.
-+ *
-+ * \ref roi_value_is_qp_delta is only available when VAConfigAttribRateControl != VA_RC_CQP,
-+ * the setting must comply with \c roi_rc_priority_support and \c roi_rc_qp_delta_support in
-+ * #VAConfigAttribValEncROI. The underlying driver should ignore this field
-+ * when VAConfigAttribRateControl == VA_RC_CQP.
-+ */
-+ uint32_t roi_value_is_qp_delta : 1;
-+ uint32_t reserved : 31;
-+ } bits;
-+ uint32_t value;
-+ } roi_flags;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncMiscParameterBufferROI;
-+/*
-+ * \brief Dirty rectangle data structure for encoding.
-+ *
-+ * The encoding dirty rect can be set through VAEncMiscParameterBufferDirtyRect, if the
-+ * implementation supports dirty rect input. The rect set through this structure is applicable
-+ * only to the current frame or field, so must be sent every frame or field to be applied.
-+ * The number of supported rects can be queried through the VAConfigAttribEncDirtyRect. The
-+ * encoder will use the rect information to know those rectangle areas have changed while the
-+ * areas not covered by dirty rect rectangles are assumed to have not changed compared to the
-+ * previous picture. The encoder may do some internal optimizations.
-+ */
-+typedef struct _VAEncMiscParameterBufferDirtyRect
-+{
-+ /** \brief Number of Rectangle being sent.*/
-+ uint32_t num_roi_rectangle;
-+
-+ /** \brief Pointer to a VARectangle array with num_roi_rectangle elements.*/
-+ VARectangle *roi_rectangle;
-+} VAEncMiscParameterBufferDirtyRect;
-+
-+/** \brief Attribute value for VAConfigAttribEncParallelRateControl */
-+typedef struct _VAEncMiscParameterParallelRateControl {
-+ /** brief Number of layers*/
-+ uint32_t num_layers;
-+ /** brief Number of B frames per layer per GOP.
-+ *
-+ * it should be allocated by application, and the is num_layers.
-+ * num_b_in_gop[0] is the number of regular B which refers to only I or P frames. */
-+ uint32_t *num_b_in_gop;
-+} VAEncMiscParameterParallelRateControl;
-+
-+/** per frame encoder quality controls, once set they will persist for all future frames
-+ *till it is updated again. */
-+typedef struct _VAEncMiscParameterEncQuality
-+{
-+ union
-+ {
-+ struct
-+ {
-+ /** Use raw frames for reference instead of reconstructed frames.
-+ * it only impact motion estimation (ME) stage, and will not impact MC stage
-+ * so the reconstruct picture will can match with decode side */
-+ uint32_t useRawPicForRef : 1;
-+ /** Disables skip check for ME stage, it will increase the bistream size
-+ * but will improve the qulity */
-+ uint32_t skipCheckDisable : 1;
-+ /** Indicates app will override default driver FTQ settings using FTQEnable.
-+ * FTQ is forward transform quantization */
-+ uint32_t FTQOverride : 1;
-+ /** Enables/disables FTQ. */
-+ uint32_t FTQEnable : 1;
-+ /** Indicates the app will provide the Skip Threshold LUT to use when FTQ is
-+ * enabled (FTQSkipThresholdLUT), else default driver thresholds will be used. */
-+ uint32_t FTQSkipThresholdLUTInput : 1;
-+ /** Indicates the app will provide the Skip Threshold LUT to use when FTQ is
-+ * disabled (NonFTQSkipThresholdLUT), else default driver thresholds will be used. */
-+ uint32_t NonFTQSkipThresholdLUTInput : 1;
-+ uint32_t ReservedBit : 1;
-+ /** Control to enable the ME mode decision algorithm to bias to fewer B Direct/Skip types.
-+ * Applies only to B frames, all other frames will ignore this setting. */
-+ uint32_t directBiasAdjustmentEnable : 1;
-+ /** Enables global motion bias. global motion also is called HME (Heirarchical Motion Estimation )
-+ * HME is used to handle large motions and avoiding local minima in the video encoding process
-+ * down scaled the input and reference picture, then do ME. the result will be a predictor to next level HME or ME
-+ * current interface divide the HME to 3 level. UltraHME , SuperHME, and HME, result of UltraHME will be input of SurperHME,
-+ * result of superHME will be a input for HME. HME result will be input of ME. it is a switch for HMEMVCostScalingFactor
-+ * can change the HME bias inside RDO stage*/
-+ uint32_t globalMotionBiasAdjustmentEnable : 1;
-+ /** MV cost scaling ratio for HME ( predictors. It is used when
-+ * globalMotionBiasAdjustmentEnable == 1, else it is ignored. Values are:
-+ * 0: set MV cost to be 0 for HME predictor.
-+ * 1: scale MV cost to be 1/2 of the default value for HME predictor.
-+ * 2: scale MV cost to be 1/4 of the default value for HME predictor.
-+ * 3: scale MV cost to be 1/8 of the default value for HME predictor. */
-+ uint32_t HMEMVCostScalingFactor : 2;
-+ /**disable HME, if it is disabled. Super*ultraHME should also be disabled */
-+ uint32_t HMEDisable : 1;
-+ /**disable Super HME, if it is disabled, ultraHME should be disabled */
-+ uint32_t SuperHMEDisable : 1;
-+ /** disable Ultra HME */
-+ uint32_t UltraHMEDisable : 1;
-+ /** disable panic mode. Panic mode happened when there are extreme BRC (bit rate control) requirement
-+ * frame size cant achieve the target of BRC. when Panic mode is triggered, Coefficients will
-+ * be set to zero. disable panic mode will improve quality but will impact BRC */
-+ uint32_t PanicModeDisable : 1;
-+ /** Force RepartitionCheck
-+ * 0: DEFAULT - follow driver default settings.
-+ * 1: FORCE_ENABLE - enable this feature totally for all cases.
-+ * 2: FORCE_DISABLE - disable this feature totally for all cases. */
-+ uint32_t ForceRepartitionCheck : 2;
-+
-+ };
-+ uint32_t encControls;
-+ };
-+
-+ /** Maps QP to skip thresholds when FTQ is enabled. Valid range is 0-255. */
-+ uint8_t FTQSkipThresholdLUT[52];
-+ /** Maps QP to skip thresholds when FTQ is disabled. Valid range is 0-65535. */
-+ uint16_t NonFTQSkipThresholdLUT[52];
-+
-+ uint32_t reserved[VA_PADDING_HIGH]; // Reserved for future use.
-+
-+} VAEncMiscParameterEncQuality;
-+
-+/**
-+ * \brief Custom Encoder Rounding Offset Control.
-+ * Application may use this structure to set customized rounding
-+ * offset parameters for quantization.
-+ * Valid when \c VAConfigAttribCustomRoundingControl equals 1.
-+ */
-+typedef struct _VAEncMiscParameterCustomRoundingControl
-+{
-+ union {
-+ struct {
-+ /** \brief Enable customized rounding offset for intra blocks.
-+ * If 0, default value would be taken by driver for intra
-+ * rounding offset.
-+ */
-+ uint32_t enable_custom_rouding_intra : 1 ;
-+
-+ /** \brief Intra rounding offset
-+ * Ignored if \c enable_custom_rouding_intra equals 0.
-+ */
-+ uint32_t rounding_offset_intra : 7;
-+
-+ /** \brief Enable customized rounding offset for inter blocks.
-+ * If 0, default value would be taken by driver for inter
-+ * rounding offset.
-+ */
-+ uint32_t enable_custom_rounding_inter : 1 ;
-+
-+ /** \brief Inter rounding offset
-+ * Ignored if \c enable_custom_rouding_inter equals 0.
-+ */
-+ uint32_t rounding_offset_inter : 7;
-+
-+ /* Reserved */
-+ uint32_t reserved :16;
-+ } bits;
-+ uint32_t value;
-+ } rounding_offset_setting;
-+} VAEncMiscParameterCustomRoundingControl;
-+/**
-+ * There will be cases where the bitstream buffer will not have enough room to hold
-+ * the data for the entire slice, and the following flags will be used in the slice
-+ * parameter to signal to the server for the possible cases.
-+ * If a slice parameter buffer and slice data buffer pair is sent to the server with
-+ * the slice data partially in the slice data buffer (BEGIN and MIDDLE cases below),
-+ * then a slice parameter and data buffer needs to be sent again to complete this slice.
-+ */
-+#define VA_SLICE_DATA_FLAG_ALL 0x00 /* whole slice is in the buffer */
-+#define VA_SLICE_DATA_FLAG_BEGIN 0x01 /* The beginning of the slice is in the buffer but the end if not */
-+#define VA_SLICE_DATA_FLAG_MIDDLE 0x02 /* Neither beginning nor end of the slice is in the buffer */
-+#define VA_SLICE_DATA_FLAG_END 0x04 /* end of the slice is in the buffer */
-+
-+/* Codec-independent Slice Parameter Buffer base */
-+typedef struct _VASliceParameterBufferBase
-+{
-+ uint32_t slice_data_size; /* number of bytes in the slice data buffer for this slice */
-+ uint32_t slice_data_offset; /* the offset to the first byte of slice data */
-+ uint32_t slice_data_flag; /* see VA_SLICE_DATA_FLAG_XXX definitions */
-+} VASliceParameterBufferBase;
-+
-+/**********************************
-+ * JPEG common data structures
-+ **********************************/
-+/**
-+ * \brief Huffman table for JPEG decoding.
-+ *
-+ * This structure holds the complete Huffman tables. This is an
-+ * aggregation of all Huffman table (DHT) segments maintained by the
-+ * application. i.e. up to 2 Huffman tables are stored in there for
-+ * baseline profile.
-+ *
-+ * The #load_huffman_table array can be used as a hint to notify the
-+ * VA driver implementation about which table(s) actually changed
-+ * since the last submission of this buffer.
-+ */
-+typedef struct _VAHuffmanTableBufferJPEGBaseline {
-+ /** \brief Specifies which #huffman_table is valid. */
-+ uint8_t load_huffman_table[2];
-+ /** \brief Huffman tables indexed by table identifier (Th). */
-+ struct {
-+ /** @name DC table (up to 12 categories) */
-+ /**@{*/
-+ /** \brief Number of Huffman codes of length i + 1 (Li). */
-+ uint8_t num_dc_codes[16];
-+ /** \brief Value associated with each Huffman code (Vij). */
-+ uint8_t dc_values[12];
-+ /**@}*/
-+ /** @name AC table (2 special codes + up to 16 * 10 codes) */
-+ /**@{*/
-+ /** \brief Number of Huffman codes of length i + 1 (Li). */
-+ uint8_t num_ac_codes[16];
-+ /** \brief Value associated with each Huffman code (Vij). */
-+ uint8_t ac_values[162];
-+ /** \brief Padding to 4-byte boundaries. Must be set to zero. */
-+ uint8_t pad[2];
-+ /**@}*/
-+ } huffman_table[2];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAHuffmanTableBufferJPEGBaseline;
-+
-+/****************************
-+ * MPEG-2 data structures
-+ ****************************/
-+
-+/* MPEG-2 Picture Parameter Buffer */
-+/*
-+ * For each frame or field, and before any slice data, a single
-+ * picture parameter buffer must be send.
-+ */
-+typedef struct _VAPictureParameterBufferMPEG2
-+{
-+ uint16_t horizontal_size;
-+ uint16_t vertical_size;
-+ VASurfaceID forward_reference_picture;
-+ VASurfaceID backward_reference_picture;
-+ /* meanings of the following fields are the same as in the standard */
-+ int32_t picture_coding_type;
-+ int32_t f_code; /* pack all four fcode into this */
-+ union {
-+ struct {
-+ uint32_t intra_dc_precision : 2;
-+ uint32_t picture_structure : 2;
-+ uint32_t top_field_first : 1;
-+ uint32_t frame_pred_frame_dct : 1;
-+ uint32_t concealment_motion_vectors : 1;
-+ uint32_t q_scale_type : 1;
-+ uint32_t intra_vlc_format : 1;
-+ uint32_t alternate_scan : 1;
-+ uint32_t repeat_first_field : 1;
-+ uint32_t progressive_frame : 1;
-+ uint32_t is_first_field : 1; /* indicate whether the current field
-+ * is the first field for field picture
-+ */
-+ } bits;
-+ uint32_t value;
-+ } picture_coding_extension;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAPictureParameterBufferMPEG2;
-+
-+/** MPEG-2 Inverse Quantization Matrix Buffer */
-+typedef struct _VAIQMatrixBufferMPEG2
-+{
-+ /** \brief Same as the MPEG-2 bitstream syntax element. */
-+ int32_t load_intra_quantiser_matrix;
-+ /** \brief Same as the MPEG-2 bitstream syntax element. */
-+ int32_t load_non_intra_quantiser_matrix;
-+ /** \brief Same as the MPEG-2 bitstream syntax element. */
-+ int32_t load_chroma_intra_quantiser_matrix;
-+ /** \brief Same as the MPEG-2 bitstream syntax element. */
-+ int32_t load_chroma_non_intra_quantiser_matrix;
-+ /** \brief Luminance intra matrix, in zig-zag scan order. */
-+ uint8_t intra_quantiser_matrix[64];
-+ /** \brief Luminance non-intra matrix, in zig-zag scan order. */
-+ uint8_t non_intra_quantiser_matrix[64];
-+ /** \brief Chroma intra matrix, in zig-zag scan order. */
-+ uint8_t chroma_intra_quantiser_matrix[64];
-+ /** \brief Chroma non-intra matrix, in zig-zag scan order. */
-+ uint8_t chroma_non_intra_quantiser_matrix[64];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAIQMatrixBufferMPEG2;
-+
-+/** MPEG-2 Slice Parameter Buffer */
-+typedef struct _VASliceParameterBufferMPEG2
-+{
-+ uint32_t slice_data_size;/* number of bytes in the slice data buffer for this slice */
-+ uint32_t slice_data_offset;/* the offset to the first byte of slice data */
-+ uint32_t slice_data_flag; /* see VA_SLICE_DATA_FLAG_XXX defintions */
-+ uint32_t macroblock_offset;/* the offset to the first bit of MB from the first byte of slice data */
-+ uint32_t slice_horizontal_position;
-+ uint32_t slice_vertical_position;
-+ int32_t quantiser_scale_code;
-+ int32_t intra_slice_flag;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VASliceParameterBufferMPEG2;
-+
-+/** MPEG-2 Macroblock Parameter Buffer */
-+typedef struct _VAMacroblockParameterBufferMPEG2
-+{
-+ uint16_t macroblock_address;
-+ /*
-+ * macroblock_address (in raster scan order)
-+ * top-left: 0
-+ * bottom-right: picture-height-in-mb*picture-width-in-mb - 1
-+ */
-+ uint8_t macroblock_type; /* see definition below */
-+ union {
-+ struct {
-+ uint32_t frame_motion_type : 2;
-+ uint32_t field_motion_type : 2;
-+ uint32_t dct_type : 1;
-+ } bits;
-+ uint32_t value;
-+ } macroblock_modes;
-+ uint8_t motion_vertical_field_select;
-+ /*
-+ * motion_vertical_field_select:
-+ * see section 6.3.17.2 in the spec
-+ * only the lower 4 bits are used
-+ * bit 0: first vector forward
-+ * bit 1: first vector backward
-+ * bit 2: second vector forward
-+ * bit 3: second vector backward
-+ */
-+ int16_t PMV[2][2][2]; /* see Table 7-7 in the spec */
-+ uint16_t coded_block_pattern;
-+ /*
-+ * The bitplanes for coded_block_pattern are described
-+ * in Figure 6.10-12 in the spec
-+ */
-+
-+ /* Number of skipped macroblocks after this macroblock */
-+ uint16_t num_skipped_macroblocks;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAMacroblockParameterBufferMPEG2;
-+
-+/*
-+ * OR'd flags for macroblock_type (section 6.3.17.1 in the spec)
-+ */
-+#define VA_MB_TYPE_MOTION_FORWARD 0x02
-+#define VA_MB_TYPE_MOTION_BACKWARD 0x04
-+#define VA_MB_TYPE_MOTION_PATTERN 0x08
-+#define VA_MB_TYPE_MOTION_INTRA 0x10
-+
-+/**
-+ * MPEG-2 Residual Data Buffer
-+ * For each macroblock, there wil be 64 shorts (16-bit) in the
-+ * residual data buffer
-+ */
-+
-+/****************************
-+ * MPEG-4 Part 2 data structures
-+ ****************************/
-+
-+/* MPEG-4 Picture Parameter Buffer */
-+/*
-+ * For each frame or field, and before any slice data, a single
-+ * picture parameter buffer must be send.
-+ */
-+typedef struct _VAPictureParameterBufferMPEG4
-+{
-+ uint16_t vop_width;
-+ uint16_t vop_height;
-+ VASurfaceID forward_reference_picture;
-+ VASurfaceID backward_reference_picture;
-+ union {
-+ struct {
-+ uint32_t short_video_header : 1;
-+ uint32_t chroma_format : 2;
-+ uint32_t interlaced : 1;
-+ uint32_t obmc_disable : 1;
-+ uint32_t sprite_enable : 2;
-+ uint32_t sprite_warping_accuracy : 2;
-+ uint32_t quant_type : 1;
-+ uint32_t quarter_sample : 1;
-+ uint32_t data_partitioned : 1;
-+ uint32_t reversible_vlc : 1;
-+ uint32_t resync_marker_disable : 1;
-+ } bits;
-+ uint32_t value;
-+ } vol_fields;
-+ uint8_t no_of_sprite_warping_points;
-+ int16_t sprite_trajectory_du[3];
-+ int16_t sprite_trajectory_dv[3];
-+ uint8_t quant_precision;
-+ union {
-+ struct {
-+ uint32_t vop_coding_type : 2;
-+ uint32_t backward_reference_vop_coding_type : 2;
-+ uint32_t vop_rounding_type : 1;
-+ uint32_t intra_dc_vlc_thr : 3;
-+ uint32_t top_field_first : 1;
-+ uint32_t alternate_vertical_scan_flag : 1;
-+ } bits;
-+ uint32_t value;
-+ } vop_fields;
-+ uint8_t vop_fcode_forward;
-+ uint8_t vop_fcode_backward;
-+ uint16_t vop_time_increment_resolution;
-+ /* short header related */
-+ uint8_t num_gobs_in_vop;
-+ uint8_t num_macroblocks_in_gob;
-+ /* for direct mode prediction */
-+ int16_t TRB;
-+ int16_t TRD;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAPictureParameterBufferMPEG4;
-+
-+/** MPEG-4 Inverse Quantization Matrix Buffer */
-+typedef struct _VAIQMatrixBufferMPEG4
-+{
-+ /** Same as the MPEG-4:2 bitstream syntax element. */
-+ int32_t load_intra_quant_mat;
-+ /** Same as the MPEG-4:2 bitstream syntax element. */
-+ int32_t load_non_intra_quant_mat;
-+ /** The matrix for intra blocks, in zig-zag scan order. */
-+ uint8_t intra_quant_mat[64];
-+ /** The matrix for non-intra blocks, in zig-zag scan order. */
-+ uint8_t non_intra_quant_mat[64];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAIQMatrixBufferMPEG4;
-+
-+/** MPEG-4 Slice Parameter Buffer */
-+typedef struct _VASliceParameterBufferMPEG4
-+{
-+ uint32_t slice_data_size;/* number of bytes in the slice data buffer for this slice */
-+ uint32_t slice_data_offset;/* the offset to the first byte of slice data */
-+ uint32_t slice_data_flag; /* see VA_SLICE_DATA_FLAG_XXX defintions */
-+ uint32_t macroblock_offset;/* the offset to the first bit of MB from the first byte of slice data */
-+ uint32_t macroblock_number;
-+ int32_t quant_scale;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VASliceParameterBufferMPEG4;
-+
-+/**
-+ VC-1 data structures
-+*/
-+
-+typedef enum /* see 7.1.1.32 */
-+{
-+ VAMvMode1Mv = 0,
-+ VAMvMode1MvHalfPel = 1,
-+ VAMvMode1MvHalfPelBilinear = 2,
-+ VAMvModeMixedMv = 3,
-+ VAMvModeIntensityCompensation = 4
-+} VAMvModeVC1;
-+
-+/** VC-1 Picture Parameter Buffer */
-+/*
-+ * For each picture, and before any slice data, a picture parameter
-+ * buffer must be send. Multiple picture parameter buffers may be
-+ * sent for a single picture. In that case picture parameters will
-+ * apply to all slice data that follow it until a new picture
-+ * parameter buffer is sent.
-+ *
-+ * Notes:
-+ * pic_quantizer_type should be set to the applicable quantizer
-+ * type as defined by QUANTIZER (J.1.19) and either
-+ * PQUANTIZER (7.1.1.8) or PQINDEX (7.1.1.6)
-+ */
-+typedef struct _VAPictureParameterBufferVC1
-+{
-+ VASurfaceID forward_reference_picture;
-+ VASurfaceID backward_reference_picture;
-+ /* if out-of-loop post-processing is done on the render
-+ target, then we need to keep the in-loop decoded
-+ picture as a reference picture */
-+ VASurfaceID inloop_decoded_picture;
-+
-+ /* sequence layer for AP or meta data for SP and MP */
-+ union {
-+ struct {
-+ uint32_t pulldown : 1; /* SEQUENCE_LAYER::PULLDOWN */
-+ uint32_t interlace : 1; /* SEQUENCE_LAYER::INTERLACE */
-+ uint32_t tfcntrflag : 1; /* SEQUENCE_LAYER::TFCNTRFLAG */
-+ uint32_t finterpflag : 1; /* SEQUENCE_LAYER::FINTERPFLAG */
-+ uint32_t psf : 1; /* SEQUENCE_LAYER::PSF */
-+ uint32_t multires : 1; /* METADATA::MULTIRES */
-+ uint32_t overlap : 1; /* METADATA::OVERLAP */
-+ uint32_t syncmarker : 1; /* METADATA::SYNCMARKER */
-+ uint32_t rangered : 1; /* METADATA::RANGERED */
-+ uint32_t max_b_frames : 3; /* METADATA::MAXBFRAMES */
-+ uint32_t profile : 2; /* SEQUENCE_LAYER::PROFILE or The MSB of METADATA::PROFILE */
-+ } bits;
-+ uint32_t value;
-+ } sequence_fields;
-+
-+ uint16_t coded_width; /* ENTRY_POINT_LAYER::CODED_WIDTH */
-+ uint16_t coded_height; /* ENTRY_POINT_LAYER::CODED_HEIGHT */
-+ union {
-+ struct {
-+ uint32_t broken_link : 1; /* ENTRY_POINT_LAYER::BROKEN_LINK */
-+ uint32_t closed_entry : 1; /* ENTRY_POINT_LAYER::CLOSED_ENTRY */
-+ uint32_t panscan_flag : 1; /* ENTRY_POINT_LAYER::PANSCAN_FLAG */
-+ uint32_t loopfilter : 1; /* ENTRY_POINT_LAYER::LOOPFILTER */
-+ } bits;
-+ uint32_t value;
-+ } entrypoint_fields;
-+ uint8_t conditional_overlap_flag; /* ENTRY_POINT_LAYER::CONDOVER */
-+ uint8_t fast_uvmc_flag; /* ENTRY_POINT_LAYER::FASTUVMC */
-+ union {
-+ struct {
-+ uint32_t luma_flag : 1; /* ENTRY_POINT_LAYER::RANGE_MAPY_FLAG */
-+ uint32_t luma : 3; /* ENTRY_POINT_LAYER::RANGE_MAPY */
-+ uint32_t chroma_flag : 1; /* ENTRY_POINT_LAYER::RANGE_MAPUV_FLAG */
-+ uint32_t chroma : 3; /* ENTRY_POINT_LAYER::RANGE_MAPUV */
-+ } bits;
-+ uint32_t value;
-+ } range_mapping_fields;
-+
-+ uint8_t b_picture_fraction; /* Index for PICTURE_LAYER::BFRACTION value in Table 40 (7.1.1.14) */
-+ uint8_t cbp_table; /* PICTURE_LAYER::CBPTAB/ICBPTAB */
-+ uint8_t mb_mode_table; /* PICTURE_LAYER::MBMODETAB */
-+ uint8_t range_reduction_frame;/* PICTURE_LAYER::RANGEREDFRM */
-+ uint8_t rounding_control; /* PICTURE_LAYER::RNDCTRL */
-+ uint8_t post_processing; /* PICTURE_LAYER::POSTPROC */
-+ uint8_t picture_resolution_index; /* PICTURE_LAYER::RESPIC */
-+ uint8_t luma_scale; /* PICTURE_LAYER::LUMSCALE */
-+ uint8_t luma_shift; /* PICTURE_LAYER::LUMSHIFT */
-+
-+ union {
-+ struct {
-+ uint32_t picture_type : 3; /* PICTURE_LAYER::PTYPE */
-+ uint32_t frame_coding_mode : 3; /* PICTURE_LAYER::FCM */
-+ uint32_t top_field_first : 1; /* PICTURE_LAYER::TFF */
-+ uint32_t is_first_field : 1; /* set to 1 if it is the first field */
-+ uint32_t intensity_compensation : 1; /* PICTURE_LAYER::INTCOMP */
-+ } bits;
-+ uint32_t value;
-+ } picture_fields;
-+ union {
-+ struct {
-+ uint32_t mv_type_mb : 1; /* PICTURE::MVTYPEMB */
-+ uint32_t direct_mb : 1; /* PICTURE::DIRECTMB */
-+ uint32_t skip_mb : 1; /* PICTURE::SKIPMB */
-+ uint32_t field_tx : 1; /* PICTURE::FIELDTX */
-+ uint32_t forward_mb : 1; /* PICTURE::FORWARDMB */
-+ uint32_t ac_pred : 1; /* PICTURE::ACPRED */
-+ uint32_t overflags : 1; /* PICTURE::OVERFLAGS */
-+ } flags;
-+ uint32_t value;
-+ } raw_coding;
-+ union {
-+ struct {
-+ uint32_t bp_mv_type_mb : 1; /* PICTURE::MVTYPEMB */
-+ uint32_t bp_direct_mb : 1; /* PICTURE::DIRECTMB */
-+ uint32_t bp_skip_mb : 1; /* PICTURE::SKIPMB */
-+ uint32_t bp_field_tx : 1; /* PICTURE::FIELDTX */
-+ uint32_t bp_forward_mb : 1; /* PICTURE::FORWARDMB */
-+ uint32_t bp_ac_pred : 1; /* PICTURE::ACPRED */
-+ uint32_t bp_overflags : 1; /* PICTURE::OVERFLAGS */
-+ } flags;
-+ uint32_t value;
-+ } bitplane_present; /* signal what bitplane is being passed via the bitplane buffer */
-+ union {
-+ struct {
-+ uint32_t reference_distance_flag : 1;/* PICTURE_LAYER::REFDIST_FLAG */
-+ uint32_t reference_distance : 5;/* PICTURE_LAYER::REFDIST */
-+ uint32_t num_reference_pictures: 1;/* PICTURE_LAYER::NUMREF */
-+ uint32_t reference_field_pic_indicator : 1;/* PICTURE_LAYER::REFFIELD */
-+ } bits;
-+ uint32_t value;
-+ } reference_fields;
-+ union {
-+ struct {
-+ uint32_t mv_mode : 3; /* PICTURE_LAYER::MVMODE */
-+ uint32_t mv_mode2 : 3; /* PICTURE_LAYER::MVMODE2 */
-+ uint32_t mv_table : 3; /* PICTURE_LAYER::MVTAB/IMVTAB */
-+ uint32_t two_mv_block_pattern_table: 2; /* PICTURE_LAYER::2MVBPTAB */
-+ uint32_t four_mv_switch : 1; /* PICTURE_LAYER::4MVSWITCH */
-+ uint32_t four_mv_block_pattern_table : 2; /* PICTURE_LAYER::4MVBPTAB */
-+ uint32_t extended_mv_flag : 1; /* ENTRY_POINT_LAYER::EXTENDED_MV */
-+ uint32_t extended_mv_range : 2; /* PICTURE_LAYER::MVRANGE */
-+ uint32_t extended_dmv_flag : 1; /* ENTRY_POINT_LAYER::EXTENDED_DMV */
-+ uint32_t extended_dmv_range : 2; /* PICTURE_LAYER::DMVRANGE */
-+ } bits;
-+ uint32_t value;
-+ } mv_fields;
-+ union {
-+ struct {
-+ uint32_t dquant : 2; /* ENTRY_POINT_LAYER::DQUANT */
-+ uint32_t quantizer : 2; /* ENTRY_POINT_LAYER::QUANTIZER */
-+ uint32_t half_qp : 1; /* PICTURE_LAYER::HALFQP */
-+ uint32_t pic_quantizer_scale : 5;/* PICTURE_LAYER::PQUANT */
-+ uint32_t pic_quantizer_type : 1;/* PICTURE_LAYER::PQUANTIZER */
-+ uint32_t dq_frame : 1; /* VOPDQUANT::DQUANTFRM */
-+ uint32_t dq_profile : 2; /* VOPDQUANT::DQPROFILE */
-+ uint32_t dq_sb_edge : 2; /* VOPDQUANT::DQSBEDGE */
-+ uint32_t dq_db_edge : 2; /* VOPDQUANT::DQDBEDGE */
-+ uint32_t dq_binary_level : 1; /* VOPDQUANT::DQBILEVEL */
-+ uint32_t alt_pic_quantizer : 5;/* VOPDQUANT::ALTPQUANT */
-+ } bits;
-+ uint32_t value;
-+ } pic_quantizer_fields;
-+ union {
-+ struct {
-+ uint32_t variable_sized_transform_flag : 1;/* ENTRY_POINT_LAYER::VSTRANSFORM */
-+ uint32_t mb_level_transform_type_flag : 1;/* PICTURE_LAYER::TTMBF */
-+ uint32_t frame_level_transform_type : 2;/* PICTURE_LAYER::TTFRM */
-+ uint32_t transform_ac_codingset_idx1 : 2;/* PICTURE_LAYER::TRANSACFRM */
-+ uint32_t transform_ac_codingset_idx2 : 2;/* PICTURE_LAYER::TRANSACFRM2 */
-+ uint32_t intra_transform_dc_table : 1;/* PICTURE_LAYER::TRANSDCTAB */
-+ } bits;
-+ uint32_t value;
-+ } transform_fields;
-+
-+ uint8_t luma_scale2; /* PICTURE_LAYER::LUMSCALE2 */
-+ uint8_t luma_shift2; /* PICTURE_LAYER::LUMSHIFT2 */
-+ uint8_t intensity_compensation_field; /* Index for PICTURE_LAYER::INTCOMPFIELD value in Table 109 (9.1.1.48) */
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_MEDIUM - 1];
-+} VAPictureParameterBufferVC1;
-+
-+/** VC-1 Bitplane Buffer
-+There will be at most three bitplanes coded in any picture header. To send
-+the bitplane data more efficiently, each byte is divided in two nibbles, with
-+each nibble carrying three bitplanes for one macroblock. The following table
-+shows the bitplane data arrangement within each nibble based on the picture
-+type.
-+
-+Picture Type Bit3 Bit2 Bit1 Bit0
-+I or BI OVERFLAGS ACPRED FIELDTX
-+P MYTYPEMB SKIPMB DIRECTMB
-+B FORWARDMB SKIPMB DIRECTMB
-+
-+Within each byte, the lower nibble is for the first MB and the upper nibble is
-+for the second MB. E.g. the lower nibble of the first byte in the bitplane
-+buffer is for Macroblock #1 and the upper nibble of the first byte is for
-+Macroblock #2 in the first row.
-+*/
-+
-+/* VC-1 Slice Parameter Buffer */
-+typedef struct _VASliceParameterBufferVC1
-+{
-+ uint32_t slice_data_size;/* number of bytes in the slice data buffer for this slice */
-+ uint32_t slice_data_offset;/* the offset to the first byte of slice data */
-+ uint32_t slice_data_flag; /* see VA_SLICE_DATA_FLAG_XXX defintions */
-+ uint32_t macroblock_offset;/* the offset to the first bit of MB from the first byte of slice data */
-+ uint32_t slice_vertical_position;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VASliceParameterBufferVC1;
-+
-+/* VC-1 Slice Data Buffer */
-+/*
-+This is simplely a buffer containing raw bit-stream bytes
-+*/
-+
-+/****************************
-+ * H.264/AVC data structures
-+ ****************************/
-+
-+typedef struct _VAPictureH264
-+{
-+ VASurfaceID picture_id;
-+ uint32_t frame_idx;
-+ uint32_t flags;
-+ int32_t TopFieldOrderCnt;
-+ int32_t BottomFieldOrderCnt;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAPictureH264;
-+/* flags in VAPictureH264 could be OR of the following */
-+#define VA_PICTURE_H264_INVALID 0x00000001
-+#define VA_PICTURE_H264_TOP_FIELD 0x00000002
-+#define VA_PICTURE_H264_BOTTOM_FIELD 0x00000004
-+#define VA_PICTURE_H264_SHORT_TERM_REFERENCE 0x00000008
-+#define VA_PICTURE_H264_LONG_TERM_REFERENCE 0x00000010
-+
-+/** H.264 Picture Parameter Buffer */
-+/*
-+ * For each picture, and before any slice data, a single
-+ * picture parameter buffer must be send.
-+ */
-+typedef struct _VAPictureParameterBufferH264
-+{
-+ VAPictureH264 CurrPic;
-+ VAPictureH264 ReferenceFrames[16]; /* in DPB */
-+ uint16_t picture_width_in_mbs_minus1;
-+ uint16_t picture_height_in_mbs_minus1;
-+ uint8_t bit_depth_luma_minus8;
-+ uint8_t bit_depth_chroma_minus8;
-+ uint8_t num_ref_frames;
-+ union {
-+ struct {
-+ uint32_t chroma_format_idc : 2;
-+ uint32_t residual_colour_transform_flag : 1; /* Renamed to separate_colour_plane_flag in newer standard versions. */
-+ uint32_t gaps_in_frame_num_value_allowed_flag : 1;
-+ uint32_t frame_mbs_only_flag : 1;
-+ uint32_t mb_adaptive_frame_field_flag : 1;
-+ uint32_t direct_8x8_inference_flag : 1;
-+ uint32_t MinLumaBiPredSize8x8 : 1; /* see A.3.3.2 */
-+ uint32_t log2_max_frame_num_minus4 : 4;
-+ uint32_t pic_order_cnt_type : 2;
-+ uint32_t log2_max_pic_order_cnt_lsb_minus4 : 4;
-+ uint32_t delta_pic_order_always_zero_flag : 1;
-+ } bits;
-+ uint32_t value;
-+ } seq_fields;
-+ // FMO is not supported.
-+ va_deprecated uint8_t num_slice_groups_minus1;
-+ va_deprecated uint8_t slice_group_map_type;
-+ va_deprecated uint16_t slice_group_change_rate_minus1;
-+ int8_t pic_init_qp_minus26;
-+ int8_t pic_init_qs_minus26;
-+ int8_t chroma_qp_index_offset;
-+ int8_t second_chroma_qp_index_offset;
-+ union {
-+ struct {
-+ uint32_t entropy_coding_mode_flag : 1;
-+ uint32_t weighted_pred_flag : 1;
-+ uint32_t weighted_bipred_idc : 2;
-+ uint32_t transform_8x8_mode_flag : 1;
-+ uint32_t field_pic_flag : 1;
-+ uint32_t constrained_intra_pred_flag : 1;
-+ uint32_t pic_order_present_flag : 1; /* Renamed to bottom_field_pic_order_in_frame_present_flag in newer standard versions. */
-+ uint32_t deblocking_filter_control_present_flag : 1;
-+ uint32_t redundant_pic_cnt_present_flag : 1;
-+ uint32_t reference_pic_flag : 1; /* nal_ref_idc != 0 */
-+ } bits;
-+ uint32_t value;
-+ } pic_fields;
-+ uint16_t frame_num;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_MEDIUM];
-+} VAPictureParameterBufferH264;
-+
-+/** H.264 Inverse Quantization Matrix Buffer */
-+typedef struct _VAIQMatrixBufferH264
-+{
-+ /** \brief 4x4 scaling list, in raster scan order. */
-+ uint8_t ScalingList4x4[6][16];
-+ /** \brief 8x8 scaling list, in raster scan order. */
-+ uint8_t ScalingList8x8[2][64];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAIQMatrixBufferH264;
-+
-+/** H.264 Slice Parameter Buffer */
-+typedef struct _VASliceParameterBufferH264
-+{
-+ uint32_t slice_data_size;/* number of bytes in the slice data buffer for this slice */
-+ /** \brief Byte offset to the NAL Header Unit for this slice. */
-+ uint32_t slice_data_offset;
-+ uint32_t slice_data_flag; /* see VA_SLICE_DATA_FLAG_XXX defintions */
-+ /**
-+ * \brief Bit offset from NAL Header Unit to the begining of slice_data().
-+ *
-+ * This bit offset is relative to and includes the NAL unit byte
-+ * and represents the number of bits parsed in the slice_header()
-+ * after the removal of any emulation prevention bytes in
-+ * there. However, the slice data buffer passed to the hardware is
-+ * the original bitstream, thus including any emulation prevention
-+ * bytes.
-+ */
-+ uint16_t slice_data_bit_offset;
-+ uint16_t first_mb_in_slice;
-+ uint8_t slice_type;
-+ uint8_t direct_spatial_mv_pred_flag;
-+ /**
-+ * H264/AVC syntax element
-+ *
-+ * if num_ref_idx_active_override_flag equals 0, host decoder should
-+ * set its value to num_ref_idx_l0_default_active_minus1.
-+ */
-+ uint8_t num_ref_idx_l0_active_minus1;
-+ /**
-+ * H264/AVC syntax element
-+ *
-+ * if num_ref_idx_active_override_flag equals 0, host decoder should
-+ * set its value to num_ref_idx_l1_default_active_minus1.
-+ */
-+ uint8_t num_ref_idx_l1_active_minus1;
-+ uint8_t cabac_init_idc;
-+ int8_t slice_qp_delta;
-+ uint8_t disable_deblocking_filter_idc;
-+ int8_t slice_alpha_c0_offset_div2;
-+ int8_t slice_beta_offset_div2;
-+ VAPictureH264 RefPicList0[32]; /* See 8.2.4.2 */
-+ VAPictureH264 RefPicList1[32]; /* See 8.2.4.2 */
-+ uint8_t luma_log2_weight_denom;
-+ uint8_t chroma_log2_weight_denom;
-+ uint8_t luma_weight_l0_flag;
-+ int16_t luma_weight_l0[32];
-+ int16_t luma_offset_l0[32];
-+ uint8_t chroma_weight_l0_flag;
-+ int16_t chroma_weight_l0[32][2];
-+ int16_t chroma_offset_l0[32][2];
-+ uint8_t luma_weight_l1_flag;
-+ int16_t luma_weight_l1[32];
-+ int16_t luma_offset_l1[32];
-+ uint8_t chroma_weight_l1_flag;
-+ int16_t chroma_weight_l1[32][2];
-+ int16_t chroma_offset_l1[32][2];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VASliceParameterBufferH264;
-+
-+/****************************
-+ * Common encode data structures
-+ ****************************/
-+typedef enum
-+{
-+ VAEncPictureTypeIntra = 0,
-+ VAEncPictureTypePredictive = 1,
-+ VAEncPictureTypeBidirectional = 2,
-+} VAEncPictureType;
-+
-+/**
-+ * \brief Encode Slice Parameter Buffer.
-+ *
-+ * @deprecated
-+ * This is a deprecated encode slice parameter buffer, All applications
-+ * \c can use VAEncSliceParameterBufferXXX (XXX = MPEG2, HEVC, H264, JPEG)
-+ */
-+typedef struct _VAEncSliceParameterBuffer
-+{
-+ uint32_t start_row_number; /* starting MB row number for this slice */
-+ uint32_t slice_height; /* slice height measured in MB */
-+ union {
-+ struct {
-+ uint32_t is_intra : 1;
-+ uint32_t disable_deblocking_filter_idc : 2;
-+ uint32_t uses_long_term_ref :1;
-+ uint32_t is_long_term_ref :1;
-+ } bits;
-+ uint32_t value;
-+ } slice_flags;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncSliceParameterBuffer;
-+
-+
-+/****************************
-+ * H.263 specific encode data structures
-+ ****************************/
-+
-+typedef struct _VAEncSequenceParameterBufferH263
-+{
-+ uint32_t intra_period;
-+ uint32_t bits_per_second;
-+ uint32_t frame_rate;
-+ uint32_t initial_qp;
-+ uint32_t min_qp;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncSequenceParameterBufferH263;
-+
-+typedef struct _VAEncPictureParameterBufferH263
-+{
-+ VASurfaceID reference_picture;
-+ VASurfaceID reconstructed_picture;
-+ VABufferID coded_buf;
-+ uint16_t picture_width;
-+ uint16_t picture_height;
-+ VAEncPictureType picture_type;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncPictureParameterBufferH263;
-+
-+/****************************
-+ * MPEG-4 specific encode data structures
-+ ****************************/
-+
-+typedef struct _VAEncSequenceParameterBufferMPEG4
-+{
-+ uint8_t profile_and_level_indication;
-+ uint32_t intra_period;
-+ uint32_t video_object_layer_width;
-+ uint32_t video_object_layer_height;
-+ uint32_t vop_time_increment_resolution;
-+ uint32_t fixed_vop_rate;
-+ uint32_t fixed_vop_time_increment;
-+ uint32_t bits_per_second;
-+ uint32_t frame_rate;
-+ uint32_t initial_qp;
-+ uint32_t min_qp;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncSequenceParameterBufferMPEG4;
-+
-+typedef struct _VAEncPictureParameterBufferMPEG4
-+{
-+ VASurfaceID reference_picture;
-+ VASurfaceID reconstructed_picture;
-+ VABufferID coded_buf;
-+ uint16_t picture_width;
-+ uint16_t picture_height;
-+ uint32_t modulo_time_base; /* number of 1s */
-+ uint32_t vop_time_increment;
-+ VAEncPictureType picture_type;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAEncPictureParameterBufferMPEG4;
-+
-+
-+
-+/** Buffer functions */
-+
-+/**
-+ * Creates a buffer for "num_elements" elements of "size" bytes and
-+ * initalize with "data".
-+ * if "data" is null, then the contents of the buffer data store
-+ * are undefined.
-+ * Basically there are two ways to get buffer data to the server side. One is
-+ * to call vaCreateBuffer() with a non-null "data", which results the data being
-+ * copied to the data store on the server side. A different method that
-+ * eliminates this copy is to pass null as "data" when calling vaCreateBuffer(),
-+ * and then use vaMapBuffer() to map the data store from the server side to the
-+ * client address space for access.
-+ * The user must call vaDestroyBuffer() to destroy a buffer.
-+ * Note: image buffers are created by the library, not the client. Please see
-+ * vaCreateImage on how image buffers are managed.
-+ */
-+VAStatus vaCreateBuffer (
-+ VADisplay dpy,
-+ VAContextID context,
-+ VABufferType type, /* in */
-+ unsigned int size, /* in */
-+ unsigned int num_elements, /* in */
-+ void *data, /* in */
-+ VABufferID *buf_id /* out */
-+);
-+
-+/**
-+ * Create a buffer for given width & height get unit_size, pitch, buf_id for 2D buffer
-+ * for permb qp buffer, it will return unit_size for one MB or LCU and the pitch for alignments
-+ * can call vaMapBuffer with this Buffer ID to get virtual address.
-+ * e.g. AVC 1080P encode, 1920x1088, the size in MB is 120x68,but inside driver,
-+ * maybe it should align with 256, and one byte present one Qp.so, call the function.
-+ * then get unit_size = 1, pitch = 256. call vaMapBuffer to get the virtual address (pBuf).
-+ * then read write the memory like 2D. the size is 256x68, application can only use 120x68
-+ * pBuf + 256 is the start of next line.
-+ * different driver implementation maybe return different unit_size and pitch
-+ */
-+VAStatus vaCreateBuffer2(
-+ VADisplay dpy,
-+ VAContextID context,
-+ VABufferType type,
-+ unsigned int width,
-+ unsigned int height,
-+ unsigned int *unit_size,
-+ unsigned int *pitch,
-+ VABufferID *buf_id
-+);
-+
-+/**
-+ * Convey to the server how many valid elements are in the buffer.
-+ * e.g. if multiple slice parameters are being held in a single buffer,
-+ * this will communicate to the server the number of slice parameters
-+ * that are valid in the buffer.
-+ */
-+VAStatus vaBufferSetNumElements (
-+ VADisplay dpy,
-+ VABufferID buf_id, /* in */
-+ unsigned int num_elements /* in */
-+);
-+
-+
-+/**
-+ * device independent data structure for codedbuffer
-+ */
-+
-+/*
-+ * FICTURE_AVE_QP(bit7-0): The average Qp value used during this frame
-+ * LARGE_SLICE(bit8):At least one slice in the current frame was large
-+ * enough for the encoder to attempt to limit its size.
-+ * SLICE_OVERFLOW(bit9): At least one slice in the current frame has
-+ * exceeded the maximum slice size specified.
-+ * BITRATE_OVERFLOW(bit10): The peak bitrate was exceeded for this frame.
-+ * BITRATE_HIGH(bit11): The frame size got within the safety margin of the maximum size (VCM only)
-+ * AIR_MB_OVER_THRESHOLD: the number of MBs adapted to Intra MB
-+ */
-+#define VA_CODED_BUF_STATUS_PICTURE_AVE_QP_MASK 0xff
-+#define VA_CODED_BUF_STATUS_LARGE_SLICE_MASK 0x100
-+#define VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK 0x200
-+#define VA_CODED_BUF_STATUS_BITRATE_OVERFLOW 0x400
-+#define VA_CODED_BUF_STATUS_BITRATE_HIGH 0x800
-+/**
-+ * \brief The frame has exceeded the maximum requested size.
-+ *
-+ * This flag indicates that the encoded frame size exceeds the value
-+ * specified through a misc parameter buffer of type
-+ * #VAEncMiscParameterTypeMaxFrameSize.
-+ */
-+#define VA_CODED_BUF_STATUS_FRAME_SIZE_OVERFLOW 0x1000
-+/**
-+ * \brief the bitstream is bad or corrupt.
-+ */
-+#define VA_CODED_BUF_STATUS_BAD_BITSTREAM 0x8000
-+#define VA_CODED_BUF_STATUS_AIR_MB_OVER_THRESHOLD 0xff0000
-+
-+/**
-+ * \brief The coded buffer segment status contains frame encoding passes number
-+ *
-+ * This is the mask to get the number of encoding passes from the coded
-+ * buffer segment status.
-+ * NUMBER_PASS(bit24~bit27): the number for encoding passes executed for the coded frame.
-+ *
-+ */
-+#define VA_CODED_BUF_STATUS_NUMBER_PASSES_MASK 0xf000000
-+
-+/**
-+ * \brief The coded buffer segment contains a single NAL unit.
-+ *
-+ * This flag indicates that the coded buffer segment contains a
-+ * single NAL unit. This flag might be useful to the user for
-+ * processing the coded buffer.
-+ */
-+#define VA_CODED_BUF_STATUS_SINGLE_NALU 0x10000000
-+
-+/**
-+ * \brief Coded buffer segment.
-+ *
-+ * #VACodedBufferSegment is an element of a linked list describing
-+ * some information on the coded buffer. The coded buffer segment
-+ * could contain either a single NAL unit, or more than one NAL unit.
-+ * It is recommended (but not required) to return a single NAL unit
-+ * in a coded buffer segment, and the implementation should set the
-+ * VA_CODED_BUF_STATUS_SINGLE_NALU status flag if that is the case.
-+ */
-+typedef struct _VACodedBufferSegment {
-+ /**
-+ * \brief Size of the data buffer in this segment (in bytes).
-+ */
-+ uint32_t size;
-+ /** \brief Bit offset into the data buffer where the video data starts. */
-+ uint32_t bit_offset;
-+ /** \brief Status set by the driver. See \c VA_CODED_BUF_STATUS_*. */
-+ uint32_t status;
-+ /** \brief Reserved for future use. */
-+ uint32_t reserved;
-+ /** \brief Pointer to the start of the data buffer. */
-+ void *buf;
-+ /**
-+ * \brief Pointer to the next #VACodedBufferSegment element,
-+ * or \c NULL if there is none.
-+ */
-+ void *next;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VACodedBufferSegment;
-+
-+/**
-+ * Map data store of the buffer into the client's address space
-+ * vaCreateBuffer() needs to be called with "data" set to NULL before
-+ * calling vaMapBuffer()
-+ *
-+ * if buffer type is VAEncCodedBufferType, pbuf points to link-list of
-+ * VACodedBufferSegment, and the list is terminated if "next" is NULL
-+ */
-+VAStatus vaMapBuffer (
-+ VADisplay dpy,
-+ VABufferID buf_id, /* in */
-+ void **pbuf /* out */
-+);
-+
-+/**
-+ * After client making changes to a mapped data store, it needs to
-+ * "Unmap" it to let the server know that the data is ready to be
-+ * consumed by the server
-+ */
-+VAStatus vaUnmapBuffer (
-+ VADisplay dpy,
-+ VABufferID buf_id /* in */
-+);
-+
-+/**
-+ * After this call, the buffer is deleted and this buffer_id is no longer valid
-+ *
-+ * A buffer can be re-used and sent to the server by another Begin/Render/End
-+ * sequence if vaDestroyBuffer() is not called with this buffer.
-+ *
-+ * Note re-using a shared buffer (e.g. a slice data buffer) between the host and the
-+ * hardware accelerator can result in performance dropping.
-+ */
-+VAStatus vaDestroyBuffer (
-+ VADisplay dpy,
-+ VABufferID buffer_id
-+);
-+
-+/** \brief VA buffer information */
-+typedef struct {
-+ /** \brief Buffer handle */
-+ uintptr_t handle;
-+ /** \brief Buffer type (See \ref VABufferType). */
-+ uint32_t type;
-+ /**
-+ * \brief Buffer memory type (See \ref VASurfaceAttribMemoryType).
-+ *
-+ * On input to vaAcquireBufferHandle(), this field can serve as a hint
-+ * to specify the set of memory types the caller is interested in.
-+ * On successful return from vaAcquireBufferHandle(), the field is
-+ * updated with the best matching memory type.
-+ */
-+ uint32_t mem_type;
-+ /** \brief Size of the underlying buffer. */
-+ size_t mem_size;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VABufferInfo;
-+
-+/**
-+ * \brief Acquires buffer handle for external API usage
-+ *
-+ * Locks the VA buffer object \ref buf_id for external API usage like
-+ * EGL or OpenCL (OCL). This function is a synchronization point. This
-+ * means that any pending operation is guaranteed to be completed
-+ * prior to returning from the function.
-+ *
-+ * If the referenced VA buffer object is the backing store of a VA
-+ * surface, then this function acts as if vaSyncSurface() on the
-+ * parent surface was called first.
-+ *
-+ * The \ref VABufferInfo argument shall be zero'ed on input. On
-+ * successful output, the data structure is filled in with all the
-+ * necessary buffer level implementation details like handle, type,
-+ * memory type and memory size.
-+ *
-+ * Note: the external API implementation, or the application, can
-+ * express the memory types it is interested in by filling in the \ref
-+ * mem_type field accordingly. On successful output, the memory type
-+ * that fits best the request and that was used is updated in the \ref
-+ * VABufferInfo data structure. If none of the supplied memory types
-+ * is supported, then a \ref VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE
-+ * error is returned.
-+ *
-+ * The \ref VABufferInfo data is valid until vaReleaseBufferHandle()
-+ * is called. Besides, no additional operation is allowed on any of
-+ * the buffer parent object until vaReleaseBufferHandle() is called.
-+ * e.g. decoding into a VA surface backed with the supplied VA buffer
-+ * object \ref buf_id would fail with a \ref VA_STATUS_ERROR_SURFACE_BUSY
-+ * error.
-+ *
-+ * Possible errors:
-+ * - \ref VA_STATUS_ERROR_UNIMPLEMENTED: the VA driver implementation
-+ * does not support this interface
-+ * - \ref VA_STATUS_ERROR_INVALID_DISPLAY: an invalid display was supplied
-+ * - \ref VA_STATUS_ERROR_INVALID_BUFFER: an invalid buffer was supplied
-+ * - \ref VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: the implementation
-+ * does not support exporting buffers of the specified type
-+ * - \ref VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE: none of the requested
-+ * memory types in \ref VABufferInfo.mem_type was supported
-+ *
-+ * @param[in] dpy the VA display
-+ * @param[in] buf_id the VA buffer
-+ * @param[in,out] buf_info the associated VA buffer information
-+ * @return VA_STATUS_SUCCESS if successful
-+ */
-+VAStatus
-+vaAcquireBufferHandle(VADisplay dpy, VABufferID buf_id, VABufferInfo *buf_info);
-+
-+/**
-+ * \brief Releases buffer after usage from external API
-+ *
-+ * Unlocks the VA buffer object \ref buf_id from external API usage like
-+ * EGL or OpenCL (OCL). This function is a synchronization point. This
-+ * means that any pending operation is guaranteed to be completed
-+ * prior to returning from the function.
-+ *
-+ * The \ref VABufferInfo argument shall point to the original data
-+ * structure that was obtained from vaAcquireBufferHandle(), unaltered.
-+ * This is necessary so that the VA driver implementation could
-+ * deallocate any resources that were needed.
-+ *
-+ * In any case, returning from this function invalidates any contents
-+ * in \ref VABufferInfo. i.e. the underlyng buffer handle is no longer
-+ * valid. Therefore, VA driver implementations are free to reset this
-+ * data structure to safe defaults.
-+ *
-+ * Possible errors:
-+ * - \ref VA_STATUS_ERROR_UNIMPLEMENTED: the VA driver implementation
-+ * does not support this interface
-+ * - \ref VA_STATUS_ERROR_INVALID_DISPLAY: an invalid display was supplied
-+ * - \ref VA_STATUS_ERROR_INVALID_BUFFER: an invalid buffer was supplied
-+ * - \ref VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: the implementation
-+ * does not support exporting buffers of the specified type
-+ *
-+ * @param[in] dpy the VA display
-+ * @param[in] buf_id the VA buffer
-+ * @return VA_STATUS_SUCCESS if successful
-+ */
-+VAStatus
-+vaReleaseBufferHandle(VADisplay dpy, VABufferID buf_id);
-+
-+/** @name vaExportSurfaceHandle() flags
-+ *
-+ * @{
-+ */
-+/** Export surface to be read by external API. */
-+#define VA_EXPORT_SURFACE_READ_ONLY 0x0001
-+/** Export surface to be written by external API. */
-+#define VA_EXPORT_SURFACE_WRITE_ONLY 0x0002
-+/** Export surface to be both read and written by external API. */
-+#define VA_EXPORT_SURFACE_READ_WRITE 0x0003
-+/** Export surface with separate layers.
-+ *
-+ * For example, NV12 surfaces should be exported as two separate
-+ * planes for luma and chroma.
-+ */
-+#define VA_EXPORT_SURFACE_SEPARATE_LAYERS 0x0004
-+/** Export surface with composed layers.
-+ *
-+ * For example, NV12 surfaces should be exported as a single NV12
-+ * composed object.
-+ */
-+#define VA_EXPORT_SURFACE_COMPOSED_LAYERS 0x0008
-+
-+/** @} */
-+
-+/**
-+ * \brief Export a handle to a surface for use with an external API
-+ *
-+ * The exported handles are owned by the caller, and the caller is
-+ * responsible for freeing them when no longer needed (e.g. by closing
-+ * DRM PRIME file descriptors).
-+ *
-+ * This does not perform any synchronisation. If the contents of the
-+ * surface will be read, vaSyncSurface() must be called before doing so.
-+ * If the contents of the surface are written, then all operations must
-+ * be completed externally before using the surface again by via VA-API
-+ * functions.
-+ *
-+ * @param[in] dpy VA display.
-+ * @param[in] surface_id Surface to export.
-+ * @param[in] mem_type Memory type to export to.
-+ * @param[in] flags Combination of flags to apply
-+ * (VA_EXPORT_SURFACE_*).
-+ * @param[out] descriptor Pointer to the descriptor structure to fill
-+ * with the handle details. The type of this structure depends on
-+ * the value of mem_type.
-+ *
-+ * @return Status code:
-+ * - VA_STATUS_SUCCESS: Success.
-+ * - VA_STATUS_ERROR_INVALID_DISPLAY: The display is not valid.
-+ * - VA_STATUS_ERROR_UNIMPLEMENTED: The driver does not implement
-+ * this interface.
-+ * - VA_STATUS_ERROR_INVALID_SURFACE: The surface is not valid, or
-+ * the surface is not exportable in the specified way.
-+ * - VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE: The driver does not
-+ * support exporting surfaces to the specified memory type.
-+ */
-+VAStatus vaExportSurfaceHandle(VADisplay dpy,
-+ VASurfaceID surface_id,
-+ uint32_t mem_type, uint32_t flags,
-+ void *descriptor);
-+
-+/**
-+ * Render (Video Decode/Encode/Processing) Pictures
-+ *
-+ * A picture represents either a frame or a field.
-+ *
-+ * The Begin/Render/End sequence sends the video decode/encode/processing buffers
-+ * to the server
-+ */
-+
-+/**
-+ * Get ready for a video pipeline
-+ * - decode a picture to a target surface
-+ * - encode a picture from a target surface
-+ * - process a picture to a target surface
-+ */
-+VAStatus vaBeginPicture (
-+ VADisplay dpy,
-+ VAContextID context,
-+ VASurfaceID render_target
-+);
-+
-+/**
-+ * Send video decode, encode or processing buffers to the server.
-+ */
-+VAStatus vaRenderPicture (
-+ VADisplay dpy,
-+ VAContextID context,
-+ VABufferID *buffers,
-+ int num_buffers
-+);
-+
-+/**
-+ * Make the end of rendering for a picture.
-+ * The server should start processing all pending operations for this
-+ * surface. This call is non-blocking. The client can start another
-+ * Begin/Render/End sequence on a different render target.
-+ * if VAContextID used in this function previously successfully passed
-+ * vaMFAddContext call, real processing will be started during vaMFSubmit
-+ */
-+VAStatus vaEndPicture (
-+ VADisplay dpy,
-+ VAContextID context
-+);
-+
-+/**
-+ * Make the end of rendering for a pictures in contexts passed with submission.
-+ * The server should start processing all pending operations for contexts.
-+ * All contexts passed should be associated through vaMFAddContext
-+ * and call sequence Begin/Render/End performed.
-+ * This call is non-blocking. The client can start another
-+ * Begin/Render/End/vaMFSubmit sequence on a different render targets.
-+ * Return values:
-+ * VA_STATUS_SUCCESS - operation successful, context was removed.
-+ * VA_STATUS_ERROR_INVALID_CONTEXT - mf_context or one of contexts are invalid
-+ * due to mf_context not created or one of contexts not assotiated with mf_context
-+ * through vaAddContext.
-+ * VA_STATUS_ERROR_INVALID_PARAMETER - one of context has not submitted it's frame
-+ * through vaBeginPicture vaRenderPicture vaEndPicture call sequence.
-+ * dpy: display
-+ * mf_context: Multi-Frame context
-+ * contexts: list of contexts submitting their tasks for multi-frame operation.
-+ * num_contexts: number of passed contexts.
-+ */
-+VAStatus vaMFSubmit (
-+ VADisplay dpy,
-+ VAMFContextID mf_context,
-+ VAContextID * contexts,
-+ int num_contexts
-+);
-+
-+/*
-+
-+Synchronization
-+
-+*/
-+
-+/**
-+ * This function blocks until all pending operations on the render target
-+ * have been completed. Upon return it is safe to use the render target for a
-+ * different picture.
-+ */
-+VAStatus vaSyncSurface (
-+ VADisplay dpy,
-+ VASurfaceID render_target
-+);
-+
-+typedef enum
-+{
-+ VASurfaceRendering = 1, /* Rendering in progress */
-+ VASurfaceDisplaying = 2, /* Displaying in progress (not safe to render into it) */
-+ /* this status is useful if surface is used as the source */
-+ /* of an overlay */
-+ VASurfaceReady = 4, /* not being rendered or displayed */
-+ VASurfaceSkipped = 8 /* Indicate a skipped frame during encode */
-+} VASurfaceStatus;
-+
-+/**
-+ * Find out any pending ops on the render target
-+ */
-+VAStatus vaQuerySurfaceStatus (
-+ VADisplay dpy,
-+ VASurfaceID render_target,
-+ VASurfaceStatus *status /* out */
-+);
-+
-+typedef enum
-+{
-+ VADecodeSliceMissing = 0,
-+ VADecodeMBError = 1,
-+} VADecodeErrorType;
-+
-+/**
-+ * Client calls vaQuerySurfaceError with VA_STATUS_ERROR_DECODING_ERROR, server side returns
-+ * an array of structure VASurfaceDecodeMBErrors, and the array is terminated by setting status=-1
-+*/
-+typedef struct _VASurfaceDecodeMBErrors
-+{
-+ int32_t status; /* 1 if hardware has returned detailed info below, -1 means this record is invalid */
-+ uint32_t start_mb; /* start mb address with errors */
-+ uint32_t end_mb; /* end mb address with errors */
-+ VADecodeErrorType decode_error_type;
-+ uint32_t num_mb; /* number of mbs with errors */
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW - 1];
-+} VASurfaceDecodeMBErrors;
-+
-+/**
-+ * After the application gets VA_STATUS_ERROR_DECODING_ERROR after calling vaSyncSurface(),
-+ * it can call vaQuerySurfaceError to find out further details on the particular error.
-+ * VA_STATUS_ERROR_DECODING_ERROR should be passed in as "error_status",
-+ * upon the return, error_info will point to an array of _VASurfaceDecodeMBErrors structure,
-+ * which is allocated and filled by libVA with detailed information on the missing or error macroblocks.
-+ * The array is terminated if "status==-1" is detected.
-+ */
-+VAStatus vaQuerySurfaceError(
-+ VADisplay dpy,
-+ VASurfaceID surface,
-+ VAStatus error_status,
-+ void **error_info
-+);
-+
-+/**
-+ * Images and Subpictures
-+ * VAImage is used to either get the surface data to client memory, or
-+ * to copy image data in client memory to a surface.
-+ * Both images, subpictures and surfaces follow the same 2D coordinate system where origin
-+ * is at the upper left corner with positive X to the right and positive Y down
-+ */
-+#define VA_FOURCC(ch0, ch1, ch2, ch3) \
-+ ((unsigned long)(unsigned char) (ch0) | ((unsigned long)(unsigned char) (ch1) << 8) | \
-+ ((unsigned long)(unsigned char) (ch2) << 16) | ((unsigned long)(unsigned char) (ch3) << 24 ))
-+
-+/* Pre-defined fourcc codes. */
-+
-+/** NV12: two-plane 8-bit YUV 4:2:0.
-+ * The first plane contains Y, the second plane contains U and V in pairs of bytes.
-+ */
-+#define VA_FOURCC_NV12 0x3231564E
-+/** NV21: two-plane 8-bit YUV 4:2:0.
-+ * Same as NV12, but with U and V swapped.
-+ */
-+#define VA_FOURCC_NV21 0x3132564E
-+
-+/** AI44: packed 4-bit YA.
-+ *
-+ * The bottom half of each byte contains luma, the top half contains alpha.
-+ */
-+#define VA_FOURCC_AI44 0x34344149
-+
-+/** RGBA: packed 8-bit RGBA.
-+ *
-+ * Four bytes per pixel: red, green, blue, alpha.
-+ */
-+#define VA_FOURCC_RGBA 0x41424752
-+/** RGBX: packed 8-bit RGB.
-+ *
-+ * Four bytes per pixel: red, green, blue, unspecified.
-+ */
-+#define VA_FOURCC_RGBX 0x58424752
-+/** BGRA: packed 8-bit RGBA.
-+ *
-+ * Four bytes per pixel: blue, green, red, alpha.
-+ */
-+#define VA_FOURCC_BGRA 0x41524742
-+/** BGRX: packed 8-bit RGB.
-+ *
-+ * Four bytes per pixel: blue, green, red, unspecified.
-+ */
-+#define VA_FOURCC_BGRX 0x58524742
-+/** ARGB: packed 8-bit RGBA.
-+ *
-+ * Four bytes per pixel: alpha, red, green, blue.
-+ */
-+#define VA_FOURCC_ARGB 0x42475241
-+/** XRGB: packed 8-bit RGB.
-+ *
-+ * Four bytes per pixel: unspecified, red, green, blue.
-+ */
-+#define VA_FOURCC_XRGB 0x42475258
-+/** ABGR: packed 8-bit RGBA.
-+ *
-+ * Four bytes per pixel: alpha, blue, green, red.
-+ */
-+#define VA_FOURCC_ABGR 0x52474241
-+/** XBGR: packed 8-bit RGB.
-+ *
-+ * Four bytes per pixel: unspecified, blue, green, red.
-+ */
-+#define VA_FOURCC_XBGR 0x52474258
-+
-+/** UYUV: packed 8-bit YUV 4:2:2.
-+ *
-+ * Four bytes per pair of pixels: U, Y, U, V.
-+ */
-+#define VA_FOURCC_UYVY 0x59565955
-+/** YUY2: packed 8-bit YUV 4:2:2.
-+ *
-+ * Four bytes per pair of pixels: Y, U, Y, V.
-+ */
-+#define VA_FOURCC_YUY2 0x32595559
-+/** AYUV: packed 8-bit YUVA 4:4:4.
-+ *
-+ * Four bytes per pixel: A, Y, U, V.
-+ */
-+#define VA_FOURCC_AYUV 0x56555941
-+/** NV11: two-plane 8-bit YUV 4:1:1.
-+ *
-+ * The first plane contains Y, the second plane contains U and V in pairs of bytes.
-+ */
-+#define VA_FOURCC_NV11 0x3131564e
-+/** YV12: three-plane 8-bit YUV 4:2:0.
-+ *
-+ * The three planes contain Y, V and U respectively.
-+ */
-+#define VA_FOURCC_YV12 0x32315659
-+/** P208: two-plane 8-bit YUV 4:2:2.
-+ *
-+ * The first plane contains Y, the second plane contains U and V in pairs of bytes.
-+ */
-+#define VA_FOURCC_P208 0x38303250
-+/** I420: three-plane 8-bit YUV 4:2:0.
-+ *
-+ * The three planes contain Y, U and V respectively.
-+ */
-+#define VA_FOURCC_I420 0x30323449
-+/** YV24: three-plane 8-bit YUV 4:4:4.
-+ *
-+ * The three planes contain Y, V and U respectively.
-+ */
-+#define VA_FOURCC_YV24 0x34325659
-+/** YV32: four-plane 8-bit YUVA 4:4:4
-+ *
-+ * The four planes contain Y, V, U and A respectively.
-+ */
-+#define VA_FOURCC_YV32 0x32335659
-+/** Y800: 8-bit greyscale.
-+ */
-+#define VA_FOURCC_Y800 0x30303859
-+/** IMC3: three-plane 8-bit YUV 4:2:0.
-+ *
-+ * Equivalent to YV12, but with the additional constraint that the pitch of all three planes
-+ * must be the same.
-+ */
-+#define VA_FOURCC_IMC3 0x33434D49
-+/** 411P: three-plane 8-bit YUV 4:1:1.
-+ *
-+ * The three planes contain Y, U and V respectively.
-+ */
-+#define VA_FOURCC_411P 0x50313134
-+/** 411R: three-plane 8-bit YUV.
-+ *
-+ * The subsampling is the transpose of 4:1:1 - full chroma appears on every fourth line.
-+ * The three planes contain Y, U and V respectively.
-+ */
-+#define VA_FOURCC_411R 0x52313134
-+/** 422H: three-plane 8-bit YUV 4:2:2.
-+ *
-+ * The three planes contain Y, U and V respectively.
-+ */
-+#define VA_FOURCC_422H 0x48323234
-+/** 422V: three-plane 8-bit YUV 4:4:0.
-+ *
-+ * The three planes contain Y, U and V respectively.
-+ */
-+#define VA_FOURCC_422V 0x56323234
-+/** 444P: three-plane 8-bit YUV 4:4:4.
-+ *
-+ * The three planes contain Y, U and V respectively.
-+ */
-+#define VA_FOURCC_444P 0x50343434
-+
-+/** RGBP: three-plane 8-bit RGB.
-+ *
-+ * The three planes contain red, green and blue respectively.
-+ */
-+#define VA_FOURCC_RGBP 0x50424752
-+/** BGRP: three-plane 8-bit RGB.
-+ *
-+ * The three planes contain blue, green and red respectively.
-+ */
-+#define VA_FOURCC_BGRP 0x50524742
-+/** RG16: packed 5/6-bit RGB.
-+ *
-+ * Each pixel is a two-byte little-endian value.
-+ * Red, green and blue are found in bits 15:11, 10:5, 4:0 respectively.
-+ */
-+#define VA_FOURCC_RGB565 0x36314752
-+/** BG16: packed 5/6-bit RGB.
-+ *
-+ * Each pixel is a two-byte little-endian value.
-+ * Blue, green and red are found in bits 15:11, 10:5, 4:0 respectively.
-+ */
-+#define VA_FOURCC_BGR565 0x36314742
-+
-+/** Y210: packed 10-bit YUV 4:2:2.
-+ *
-+ * Eight bytes represent a pair of pixels. Each sample is a two-byte little-endian value,
-+ * with the bottom six bits ignored. The samples are in the order Y, U, Y, V.
-+ */
-+#define VA_FOURCC_Y210 0x30313259
-+/** Y216: packed 16-bit YUV 4:2:2.
-+ *
-+ * Eight bytes represent a pair of pixels. Each sample is a two-byte little-endian value.
-+ * The samples are in the order Y, U, Y, V.
-+ */
-+#define VA_FOURCC_Y216 0x36313259
-+/** Y410: packed 10-bit YUVA 4:4:4.
-+ *
-+ * Each pixel is a four-byte little-endian value.
-+ * A, V, Y, U are found in bits 31:30, 29:20, 19:10, 9:0 respectively.
-+ */
-+#define VA_FOURCC_Y410 0x30313459
-+/** Y416: packed 16-bit YUVA 4:4:4.
-+ *
-+ * Each pixel is a set of four samples, each of which is a two-byte little-endian value.
-+ * The samples are in the order A, V, Y, U.
-+ */
-+#define VA_FOURCC_Y416 0x36313459
-+
-+/** YV16: three-plane 8-bit YUV 4:2:2.
-+ *
-+ * The three planes contain Y, V and U respectively.
-+ */
-+#define VA_FOURCC_YV16 0x36315659
-+/** P010: two-plane 10-bit YUV 4:2:0.
-+ *
-+ * Each sample is a two-byte little-endian value with the bottom six bits ignored.
-+ * The first plane contains Y, the second plane contains U and V in pairs of samples.
-+ */
-+#define VA_FOURCC_P010 0x30313050
-+/** P016: two-plane 16-bit YUV 4:2:0.
-+ *
-+ * Each sample is a two-byte little-endian value. The first plane contains Y, the second
-+ * plane contains U and V in pairs of samples.
-+ */
-+#define VA_FOURCC_P016 0x36313050
-+
-+/** I010: three-plane 10-bit YUV 4:2:0.
-+ *
-+ * Each sample is a two-byte little-endian value with the top six bits ignored.
-+ * The three planes contain Y, V and U respectively.
-+ */
-+#define VA_FOURCC_I010 0x30313049
-+
-+/** IYUV: three-plane 8-bit YUV 4:2:0.
-+ *
-+ * @deprecated Use I420 instead.
-+ */
-+#define VA_FOURCC_IYUV 0x56555949
-+/**
-+ * 10-bit Pixel RGB formats.
-+ */
-+#define VA_FOURCC_A2R10G10B10 0x30335241 /* VA_FOURCC('A','R','3','0') */
-+/**
-+ * 10-bit Pixel BGR formats.
-+ */
-+#define VA_FOURCC_A2B10G10R10 0x30334241 /* VA_FOURCC('A','B','3','0') */
-+
-+/** Y8: 8-bit greyscale.
-+ *
-+ * Only a single sample, 8 bit Y plane for monochrome images
-+ */
-+#define VA_FOURCC_Y8 0x20203859
-+/** Y16: 16-bit greyscale.
-+ *
-+ * Only a single sample, 16 bit Y plane for monochrome images
-+ */
-+#define VA_FOURCC_Y16 0x20363159
-+/** VYUV: packed 8-bit YUV 4:2:2.
-+ *
-+ * Four bytes per pair of pixels: V, Y, U, V.
-+ */
-+#define VA_FOURCC_VYUY 0x59555956
-+/** YVYU: packed 8-bit YUV 4:2:2.
-+ *
-+ * Four bytes per pair of pixels: Y, V, Y, U.
-+ */
-+#define VA_FOURCC_YVYU 0x55595659
-+/** AGRB64: three-plane 16-bit ARGB 16:16:16:16
-+ *
-+ * The four planes contain: alpha, red, green, blue respectively.
-+ */
-+#define VA_FOURCC_ARGB64 0x34475241
-+/** ABGR64: three-plane 16-bit ABGR 16:16:16:16
-+ *
-+ * The four planes contain: alpha, blue, green, red respectively.
-+ */
-+#define VA_FOURCC_ABGR64 0x34474241
-+
-+/* byte order */
-+#define VA_LSB_FIRST 1
-+#define VA_MSB_FIRST 2
-+
-+typedef struct _VAImageFormat
-+{
-+ uint32_t fourcc;
-+ uint32_t byte_order; /* VA_LSB_FIRST, VA_MSB_FIRST */
-+ uint32_t bits_per_pixel;
-+ /* for RGB formats */
-+ uint32_t depth; /* significant bits per pixel */
-+ uint32_t red_mask;
-+ uint32_t green_mask;
-+ uint32_t blue_mask;
-+ uint32_t alpha_mask;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAImageFormat;
-+
-+typedef VAGenericID VAImageID;
-+
-+typedef struct _VAImage
-+{
-+ VAImageID image_id; /* uniquely identify this image */
-+ VAImageFormat format;
-+ VABufferID buf; /* image data buffer */
-+ /*
-+ * Image data will be stored in a buffer of type VAImageBufferType to facilitate
-+ * data store on the server side for optimal performance. The buffer will be
-+ * created by the CreateImage function, and proper storage allocated based on the image
-+ * size and format. This buffer is managed by the library implementation, and
-+ * accessed by the client through the buffer Map/Unmap functions.
-+ */
-+ uint16_t width;
-+ uint16_t height;
-+ uint32_t data_size;
-+ uint32_t num_planes; /* can not be greater than 3 */
-+ /*
-+ * An array indicating the scanline pitch in bytes for each plane.
-+ * Each plane may have a different pitch. Maximum 3 planes for planar formats
-+ */
-+ uint32_t pitches[3];
-+ /*
-+ * An array indicating the byte offset from the beginning of the image data
-+ * to the start of each plane.
-+ */
-+ uint32_t offsets[3];
-+
-+ /* The following fields are only needed for paletted formats */
-+ int32_t num_palette_entries; /* set to zero for non-palette images */
-+ /*
-+ * Each component is one byte and entry_bytes indicates the number of components in
-+ * each entry (eg. 3 for YUV palette entries). set to zero for non-palette images
-+ */
-+ int32_t entry_bytes;
-+ /*
-+ * An array of ascii characters describing the order of the components within the bytes.
-+ * Only entry_bytes characters of the string are used.
-+ */
-+ int8_t component_order[4];
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAImage;
-+
-+/** Get maximum number of image formats supported by the implementation */
-+int vaMaxNumImageFormats (
-+ VADisplay dpy
-+);
-+
-+/**
-+ * Query supported image formats
-+ * The caller must provide a "format_list" array that can hold at
-+ * least vaMaxNumImageFormats() entries. The actual number of formats
-+ * returned in "format_list" is returned in "num_formats".
-+ */
-+VAStatus vaQueryImageFormats (
-+ VADisplay dpy,
-+ VAImageFormat *format_list, /* out */
-+ int *num_formats /* out */
-+);
-+
-+/**
-+ * Create a VAImage structure
-+ * The width and height fields returned in the VAImage structure may get
-+ * enlarged for some YUV formats. Upon return from this function,
-+ * image->buf has been created and proper storage allocated by the library.
-+ * The client can access the image through the Map/Unmap calls.
-+ */
-+VAStatus vaCreateImage (
-+ VADisplay dpy,
-+ VAImageFormat *format,
-+ int width,
-+ int height,
-+ VAImage *image /* out */
-+);
-+
-+/**
-+ * Should call DestroyImage before destroying the surface it is bound to
-+ */
-+VAStatus vaDestroyImage (
-+ VADisplay dpy,
-+ VAImageID image
-+);
-+
-+VAStatus vaSetImagePalette (
-+ VADisplay dpy,
-+ VAImageID image,
-+ /*
-+ * pointer to an array holding the palette data. The size of the array is
-+ * num_palette_entries * entry_bytes in size. The order of the components
-+ * in the palette is described by the component_order in VAImage struct
-+ */
-+ unsigned char *palette
-+);
-+
-+/**
-+ * Retrive surface data into a VAImage
-+ * Image must be in a format supported by the implementation
-+ */
-+VAStatus vaGetImage (
-+ VADisplay dpy,
-+ VASurfaceID surface,
-+ int x, /* coordinates of the upper left source pixel */
-+ int y,
-+ unsigned int width, /* width and height of the region */
-+ unsigned int height,
-+ VAImageID image
-+);
-+
-+/**
-+ * Copy data from a VAImage to a surface
-+ * Image must be in a format supported by the implementation
-+ * Returns a VA_STATUS_ERROR_SURFACE_BUSY if the surface
-+ * shouldn't be rendered into when this is called
-+ */
-+VAStatus vaPutImage (
-+ VADisplay dpy,
-+ VASurfaceID surface,
-+ VAImageID image,
-+ int src_x,
-+ int src_y,
-+ unsigned int src_width,
-+ unsigned int src_height,
-+ int dest_x,
-+ int dest_y,
-+ unsigned int dest_width,
-+ unsigned int dest_height
-+);
-+
-+/**
-+ * Derive an VAImage from an existing surface.
-+ * This interface will derive a VAImage and corresponding image buffer from
-+ * an existing VA Surface. The image buffer can then be mapped/unmapped for
-+ * direct CPU access. This operation is only possible on implementations with
-+ * direct rendering capabilities and internal surface formats that can be
-+ * represented with a VAImage. When the operation is not possible this interface
-+ * will return VA_STATUS_ERROR_OPERATION_FAILED. Clients should then fall back
-+ * to using vaCreateImage + vaPutImage to accomplish the same task in an
-+ * indirect manner.
-+ *
-+ * Implementations should only return success when the resulting image buffer
-+ * would be useable with vaMap/Unmap.
-+ *
-+ * When directly accessing a surface special care must be taken to insure
-+ * proper synchronization with the graphics hardware. Clients should call
-+ * vaQuerySurfaceStatus to insure that a surface is not the target of concurrent
-+ * rendering or currently being displayed by an overlay.
-+ *
-+ * Additionally nothing about the contents of a surface should be assumed
-+ * following a vaPutSurface. Implementations are free to modify the surface for
-+ * scaling or subpicture blending within a call to vaPutImage.
-+ *
-+ * Calls to vaPutImage or vaGetImage using the same surface from which the image
-+ * has been derived will return VA_STATUS_ERROR_SURFACE_BUSY. vaPutImage or
-+ * vaGetImage with other surfaces is supported.
-+ *
-+ * An image created with vaDeriveImage should be freed with vaDestroyImage. The
-+ * image and image buffer structures will be destroyed; however, the underlying
-+ * surface will remain unchanged until freed with vaDestroySurfaces.
-+ */
-+VAStatus vaDeriveImage (
-+ VADisplay dpy,
-+ VASurfaceID surface,
-+ VAImage *image /* out */
-+);
-+
-+/**
-+ * Subpictures
-+ * Subpicture is a special type of image that can be blended
-+ * with a surface during vaPutSurface(). Subpicture can be used to render
-+ * DVD sub-titles or closed captioning text etc.
-+ */
-+
-+typedef VAGenericID VASubpictureID;
-+
-+/** Get maximum number of subpicture formats supported by the implementation */
-+int vaMaxNumSubpictureFormats (
-+ VADisplay dpy
-+);
-+
-+/** flags for subpictures */
-+#define VA_SUBPICTURE_CHROMA_KEYING 0x0001
-+#define VA_SUBPICTURE_GLOBAL_ALPHA 0x0002
-+#define VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD 0x0004
-+/**
-+ * Query supported subpicture formats
-+ * The caller must provide a "format_list" array that can hold at
-+ * least vaMaxNumSubpictureFormats() entries. The flags arrary holds the flag
-+ * for each format to indicate additional capabilities for that format. The actual
-+ * number of formats returned in "format_list" is returned in "num_formats".
-+ * flags: returned value to indicate addtional capabilities
-+ * VA_SUBPICTURE_CHROMA_KEYING - supports chroma-keying
-+ * VA_SUBPICTURE_GLOBAL_ALPHA - supports global alpha
-+ * VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD - supports unscaled screen relative subpictures for On Screen Display
-+ */
-+
-+VAStatus vaQuerySubpictureFormats (
-+ VADisplay dpy,
-+ VAImageFormat *format_list, /* out */
-+ unsigned int *flags, /* out */
-+ unsigned int *num_formats /* out */
-+);
-+
-+/**
-+ * Subpictures are created with an image associated.
-+ */
-+VAStatus vaCreateSubpicture (
-+ VADisplay dpy,
-+ VAImageID image,
-+ VASubpictureID *subpicture /* out */
-+);
-+
-+/**
-+ * Destroy the subpicture before destroying the image it is assocated to
-+ */
-+VAStatus vaDestroySubpicture (
-+ VADisplay dpy,
-+ VASubpictureID subpicture
-+);
-+
-+/**
-+ * Bind an image to the subpicture. This image will now be associated with
-+ * the subpicture instead of the one at creation.
-+ */
-+VAStatus vaSetSubpictureImage (
-+ VADisplay dpy,
-+ VASubpictureID subpicture,
-+ VAImageID image
-+);
-+
-+/**
-+ * If chromakey is enabled, then the area where the source value falls within
-+ * the chromakey [min, max] range is transparent
-+ * The chromakey component format is the following:
-+ * For RGB: [0:7] Red [8:15] Blue [16:23] Green
-+ * For YUV: [0:7] V [8:15] U [16:23] Y
-+ * The chromakey mask can be used to mask out certain components for chromakey
-+ * comparision
-+ */
-+VAStatus vaSetSubpictureChromakey (
-+ VADisplay dpy,
-+ VASubpictureID subpicture,
-+ unsigned int chromakey_min,
-+ unsigned int chromakey_max,
-+ unsigned int chromakey_mask
-+);
-+
-+/**
-+ * Global alpha value is between 0 and 1. A value of 1 means fully opaque and
-+ * a value of 0 means fully transparent. If per-pixel alpha is also specified then
-+ * the overall alpha is per-pixel alpha multiplied by the global alpha
-+ */
-+VAStatus vaSetSubpictureGlobalAlpha (
-+ VADisplay dpy,
-+ VASubpictureID subpicture,
-+ float global_alpha
-+);
-+
-+/**
-+ * vaAssociateSubpicture associates the subpicture with target_surfaces.
-+ * It defines the region mapping between the subpicture and the target
-+ * surfaces through source and destination rectangles (with the same width and height).
-+ * Both will be displayed at the next call to vaPutSurface. Additional
-+ * associations before the call to vaPutSurface simply overrides the association.
-+ */
-+VAStatus vaAssociateSubpicture (
-+ VADisplay dpy,
-+ VASubpictureID subpicture,
-+ VASurfaceID *target_surfaces,
-+ int num_surfaces,
-+ int16_t src_x, /* upper left offset in subpicture */
-+ int16_t src_y,
-+ uint16_t src_width,
-+ uint16_t src_height,
-+ int16_t dest_x, /* upper left offset in surface */
-+ int16_t dest_y,
-+ uint16_t dest_width,
-+ uint16_t dest_height,
-+ /*
-+ * whether to enable chroma-keying, global-alpha, or screen relative mode
-+ * see VA_SUBPICTURE_XXX values
-+ */
-+ uint32_t flags
-+);
-+
-+/**
-+ * vaDeassociateSubpicture removes the association of the subpicture with target_surfaces.
-+ */
-+VAStatus vaDeassociateSubpicture (
-+ VADisplay dpy,
-+ VASubpictureID subpicture,
-+ VASurfaceID *target_surfaces,
-+ int num_surfaces
-+);
-+
-+/**
-+ * Display attributes
-+ * Display attributes are used to control things such as contrast, hue, saturation,
-+ * brightness etc. in the rendering process. The application can query what
-+ * attributes are supported by the driver, and then set the appropriate attributes
-+ * before calling vaPutSurface()
-+ */
-+/* PowerVR IEP Lite attributes */
-+typedef enum
-+{
-+ VADISPLAYATTRIB_BLE_OFF = 0x00,
-+ VADISPLAYATTRIB_BLE_LOW,
-+ VADISPLAYATTRIB_BLE_MEDIUM,
-+ VADISPLAYATTRIB_BLE_HIGH,
-+ VADISPLAYATTRIB_BLE_NONE,
-+} VADisplayAttribBLEMode;
-+
-+/** attribute value for VADisplayAttribRotation */
-+#define VA_ROTATION_NONE 0x00000000
-+#define VA_ROTATION_90 0x00000001
-+#define VA_ROTATION_180 0x00000002
-+#define VA_ROTATION_270 0x00000003
-+/**@}*/
-+
-+/**
-+ * @name Mirroring directions
-+ *
-+ * Those values could be used for VADisplayAttribMirror attribute or
-+ * VAProcPipelineParameterBuffer::mirror_state.
-+
-+ */
-+/**@{*/
-+/** \brief No Mirroring. */
-+#define VA_MIRROR_NONE 0x00000000
-+/** \brief Horizontal Mirroring. */
-+#define VA_MIRROR_HORIZONTAL 0x00000001
-+/** \brief Vertical Mirroring. */
-+#define VA_MIRROR_VERTICAL 0x00000002
-+/**@}*/
-+
-+/** attribute value for VADisplayAttribOutOfLoopDeblock */
-+#define VA_OOL_DEBLOCKING_FALSE 0x00000000
-+#define VA_OOL_DEBLOCKING_TRUE 0x00000001
-+
-+/** Render mode */
-+#define VA_RENDER_MODE_UNDEFINED 0
-+#define VA_RENDER_MODE_LOCAL_OVERLAY 1
-+#define VA_RENDER_MODE_LOCAL_GPU 2
-+#define VA_RENDER_MODE_EXTERNAL_OVERLAY 4
-+#define VA_RENDER_MODE_EXTERNAL_GPU 8
-+
-+/** Render device */
-+#define VA_RENDER_DEVICE_UNDEFINED 0
-+#define VA_RENDER_DEVICE_LOCAL 1
-+#define VA_RENDER_DEVICE_EXTERNAL 2
-+
-+/** Currently defined display attribute types */
-+typedef enum
-+{
-+ VADisplayAttribBrightness = 0,
-+ VADisplayAttribContrast = 1,
-+ VADisplayAttribHue = 2,
-+ VADisplayAttribSaturation = 3,
-+ /* client can specifiy a background color for the target window
-+ * the new feature of video conference,
-+ * the uncovered area of the surface is filled by this color
-+ * also it will blend with the decoded video color
-+ */
-+ VADisplayAttribBackgroundColor = 4,
-+ /*
-+ * this is a gettable only attribute. For some implementations that use the
-+ * hardware overlay, after PutSurface is called, the surface can not be
-+ * re-used until after the subsequent PutSurface call. If this is the case
-+ * then the value for this attribute will be set to 1 so that the client
-+ * will not attempt to re-use the surface right after returning from a call
-+ * to PutSurface.
-+ *
-+ * Don't use it, use flag VASurfaceDisplaying of vaQuerySurfaceStatus since
-+ * driver may use overlay or GPU alternatively
-+ */
-+ VADisplayAttribDirectSurface = 5,
-+ VADisplayAttribRotation = 6,
-+ VADisplayAttribOutofLoopDeblock = 7,
-+
-+ /* PowerVR IEP Lite specific attributes */
-+ VADisplayAttribBLEBlackMode = 8,
-+ VADisplayAttribBLEWhiteMode = 9,
-+ VADisplayAttribBlueStretch = 10,
-+ VADisplayAttribSkinColorCorrection = 11,
-+ /*
-+ * For type VADisplayAttribCSCMatrix, "value" field is a pointer to the color
-+ * conversion matrix. Each element in the matrix is float-point
-+ */
-+ VADisplayAttribCSCMatrix = 12,
-+ /* specify the constant color used to blend with video surface
-+ * Cd = Cv*Cc*Ac + Cb *(1 - Ac) C means the constant RGB
-+ * d: the final color to overwrite into the frame buffer
-+ * v: decoded video after color conversion,
-+ * c: video color specified by VADisplayAttribBlendColor
-+ * b: background color of the drawable
-+ */
-+ VADisplayAttribBlendColor = 13,
-+ /*
-+ * Indicate driver to skip painting color key or not.
-+ * only applicable if the render is overlay
-+ */
-+ VADisplayAttribOverlayAutoPaintColorKey = 14,
-+ /*
-+ * customized overlay color key, the format is RGB888
-+ * [23:16] = Red, [15:08] = Green, [07:00] = Blue.
-+ */
-+ VADisplayAttribOverlayColorKey = 15,
-+ /*
-+ * The hint for the implementation of vaPutSurface
-+ * normally, the driver could use an overlay or GPU to render the surface on the screen
-+ * this flag provides APP the flexibity to switch the render dynamically
-+ */
-+ VADisplayAttribRenderMode = 16,
-+ /*
-+ * specify if vaPutSurface needs to render into specified monitors
-+ * one example is that one external monitor (e.g. HDMI) is enabled,
-+ * but the window manager is not aware of it, and there is no associated drawable
-+ */
-+ VADisplayAttribRenderDevice = 17,
-+ /*
-+ * specify vaPutSurface render area if there is no drawable on the monitor
-+ */
-+ VADisplayAttribRenderRect = 18,
-+} VADisplayAttribType;
-+
-+/* flags for VADisplayAttribute */
-+#define VA_DISPLAY_ATTRIB_NOT_SUPPORTED 0x0000
-+#define VA_DISPLAY_ATTRIB_GETTABLE 0x0001
-+#define VA_DISPLAY_ATTRIB_SETTABLE 0x0002
-+
-+typedef struct _VADisplayAttribute
-+{
-+ VADisplayAttribType type;
-+ int32_t min_value;
-+ int32_t max_value;
-+ int32_t value; /* used by the set/get attribute functions */
-+/* flags can be VA_DISPLAY_ATTRIB_GETTABLE or VA_DISPLAY_ATTRIB_SETTABLE or OR'd together */
-+ uint32_t flags;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VADisplayAttribute;
-+
-+/** Get maximum number of display attributs supported by the implementation */
-+int vaMaxNumDisplayAttributes (
-+ VADisplay dpy
-+);
-+
-+/**
-+ * Query display attributes
-+ * The caller must provide a "attr_list" array that can hold at
-+ * least vaMaxNumDisplayAttributes() entries. The actual number of attributes
-+ * returned in "attr_list" is returned in "num_attributes".
-+ */
-+VAStatus vaQueryDisplayAttributes (
-+ VADisplay dpy,
-+ VADisplayAttribute *attr_list, /* out */
-+ int *num_attributes /* out */
-+);
-+
-+/**
-+ * Get display attributes
-+ * This function returns the current attribute values in "attr_list".
-+ * Only attributes returned with VA_DISPLAY_ATTRIB_GETTABLE set in the "flags" field
-+ * from vaQueryDisplayAttributes() can have their values retrieved.
-+ */
-+VAStatus vaGetDisplayAttributes (
-+ VADisplay dpy,
-+ VADisplayAttribute *attr_list, /* in/out */
-+ int num_attributes
-+);
-+
-+/**
-+ * Set display attributes
-+ * Only attributes returned with VA_DISPLAY_ATTRIB_SETTABLE set in the "flags" field
-+ * from vaQueryDisplayAttributes() can be set. If the attribute is not settable or
-+ * the value is out of range, the function returns VA_STATUS_ERROR_ATTR_NOT_SUPPORTED
-+ */
-+VAStatus vaSetDisplayAttributes (
-+ VADisplay dpy,
-+ VADisplayAttribute *attr_list,
-+ int num_attributes
-+);
-+
-+/****************************
-+ * HEVC data structures
-+ ****************************/
-+/**
-+ * \brief Description of picture properties of those in DPB surfaces.
-+ *
-+ * If only progressive scan is supported, each surface contains one whole
-+ * frame picture.
-+ * Otherwise, each surface contains two fields of whole picture.
-+ * In this case, two entries of ReferenceFrames[] may share same picture_id
-+ * value.
-+ */
-+typedef struct _VAPictureHEVC
-+{
-+ /** \brief reconstructed picture buffer surface index
-+ * invalid when taking value VA_INVALID_SURFACE.
-+ */
-+ VASurfaceID picture_id;
-+ /** \brief picture order count.
-+ * in HEVC, POCs for top and bottom fields of same picture should
-+ * take different values.
-+ */
-+ int32_t pic_order_cnt;
-+ /* described below */
-+ uint32_t flags;
-+
-+ /** \brief Reserved bytes for future use, must be zero */
-+ uint32_t va_reserved[VA_PADDING_LOW];
-+} VAPictureHEVC;
-+
-+/* flags in VAPictureHEVC could be OR of the following */
-+#define VA_PICTURE_HEVC_INVALID 0x00000001
-+/** \brief indication of interlace scan picture.
-+ * should take same value for all the pictures in sequence.
-+ */
-+#define VA_PICTURE_HEVC_FIELD_PIC 0x00000002
-+/** \brief polarity of the field picture.
-+ * top field takes even lines of buffer surface.
-+ * bottom field takes odd lines of buffer surface.
-+ */
-+#define VA_PICTURE_HEVC_BOTTOM_FIELD 0x00000004
-+/** \brief Long term reference picture */
-+#define VA_PICTURE_HEVC_LONG_TERM_REFERENCE 0x00000008
-+/**
-+ * VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE, VA_PICTURE_HEVC_RPS_ST_CURR_AFTER
-+ * and VA_PICTURE_HEVC_RPS_LT_CURR of any picture in ReferenceFrames[] should
-+ * be exclusive. No more than one of them can be set for any picture.
-+ * Sum of NumPocStCurrBefore, NumPocStCurrAfter and NumPocLtCurr
-+ * equals NumPocTotalCurr, which should be equal to or smaller than 8.
-+ * Application should provide valid values for both short format and long format.
-+ * The pictures in DPB with any of these three flags turned on are referred by
-+ * the current picture.
-+ */
-+/** \brief RefPicSetStCurrBefore of HEVC spec variable
-+ * Number of ReferenceFrames[] entries with this bit set equals
-+ * NumPocStCurrBefore.
-+ */
-+#define VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE 0x00000010
-+/** \brief RefPicSetStCurrAfter of HEVC spec variable
-+ * Number of ReferenceFrames[] entries with this bit set equals
-+ * NumPocStCurrAfter.
-+ */
-+#define VA_PICTURE_HEVC_RPS_ST_CURR_AFTER 0x00000020
-+/** \brief RefPicSetLtCurr of HEVC spec variable
-+ * Number of ReferenceFrames[] entries with this bit set equals
-+ * NumPocLtCurr.
-+ */
-+#define VA_PICTURE_HEVC_RPS_LT_CURR 0x00000040
-+
-+//#include <va/va_dec_hevc.h>
-+//#include <va/va_dec_jpeg.h>
-+#include "va_dec_vp8.h"
-+#include "va_dec_vp9.h"
-+//#include <va/va_enc_hevc.h>
-+//#include <va/va_fei_hevc.h>
-+//#include <va/va_enc_h264.h>
-+//#include <va/va_enc_jpeg.h>
-+//#include <va/va_enc_mpeg2.h>
-+//#include <va/va_enc_vp8.h>
-+//#include <va/va_enc_vp9.h>
-+//#include <va/va_fei.h>
-+//#include <va/va_fei_h264.h>
-+//#include <va/va_vpp.h>
-+
-+/**@}*/
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _VA_H_ */
-diff -up firefox-84.0/media/ffvpx/va/va.patch.ffvpx firefox-84.0/media/ffvpx/va/va.patch
---- firefox-84.0/media/ffvpx/va/va.patch.ffvpx 2020-12-10 20:40:53.391541423 +0100
-+++ firefox-84.0/media/ffvpx/va/va.patch 2020-12-10 20:40:53.391541423 +0100
-@@ -0,0 +1,33 @@
-+--- va.h.old 2020-10-22 10:41:57.805112031 +0200
-++++ va.h 2020-10-22 10:37:22.597088670 +0200
-+@@ -4613,18 +4613,18 @@
-+ #define VA_PICTURE_HEVC_RPS_LT_CURR 0x00000040
-+
-+-#include <va/va_dec_hevc.h>
-+-#include <va/va_dec_jpeg.h>
-++//#include <va/va_dec_hevc.h>
-++//#include <va/va_dec_jpeg.h>
-+ #include "va_dec_vp8.h"
-+ #include "va_dec_vp9.h"
-+-#include <va/va_enc_hevc.h>
-+-#include <va/va_fei_hevc.h>
-+-#include <va/va_enc_h264.h>
-+-#include <va/va_enc_jpeg.h>
-+-#include <va/va_enc_mpeg2.h>
-+-#include <va/va_enc_vp8.h>
-+-#include <va/va_enc_vp9.h>
-+-#include <va/va_fei.h>
-+-#include <va/va_fei_h264.h>
-+-#include <va/va_vpp.h>
-++//#include <va/va_enc_hevc.h>
-++//#include <va/va_fei_hevc.h>
-++//#include <va/va_enc_h264.h>
-++//#include <va/va_enc_jpeg.h>
-++//#include <va/va_enc_mpeg2.h>
-++//#include <va/va_enc_vp8.h>
-++//#include <va/va_enc_vp9.h>
-++//#include <va/va_fei.h>
-++//#include <va/va_fei_h264.h>
-++//#include <va/va_vpp.h>
-+
-+ /**@}*/
-diff -up firefox-84.0/media/ffvpx/va/va_version.h.ffvpx firefox-84.0/media/ffvpx/va/va_version.h
---- firefox-84.0/media/ffvpx/va/va_version.h.ffvpx 2020-12-10 20:40:53.391541423 +0100
-+++ firefox-84.0/media/ffvpx/va/va_version.h 2020-12-10 20:40:53.391541423 +0100
-@@ -0,0 +1,87 @@
-+/*
-+ * Copyright (C) 2009 Splitted-Desktop Systems. All Rights Reserved.
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
-+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef VA_VERSION_H
-+#define VA_VERSION_H
-+
-+/**
-+ * VA_MAJOR_VERSION:
-+ *
-+ * The major version of VA-API (1, if %VA_VERSION is 1.2.3)
-+ */
-+#define VA_MAJOR_VERSION 1
-+
-+/**
-+ * VA_MINOR_VERSION:
-+ *
-+ * The minor version of VA-API (2, if %VA_VERSION is 1.2.3)
-+ */
-+#define VA_MINOR_VERSION 7
-+
-+/**
-+ * VA_MICRO_VERSION:
-+ *
-+ * The micro version of VA-API (3, if %VA_VERSION is 1.2.3)
-+ */
-+#define VA_MICRO_VERSION 0
-+
-+/**
-+ * VA_VERSION:
-+ *
-+ * The full version of VA-API, like 1.2.3
-+ */
-+#define VA_VERSION 1.7.0
-+
-+/**
-+ * VA_VERSION_S:
-+ *
-+ * The full version of VA-API, in string form (suited for string
-+ * concatenation)
-+ */
-+#define VA_VERSION_S "1.7.0"
-+
-+/**
-+ * VA_VERSION_HEX:
-+ *
-+ * Numerically encoded version of VA-API, like 0x010203
-+ */
-+#define VA_VERSION_HEX ((VA_MAJOR_VERSION << 24) | \
-+ (VA_MINOR_VERSION << 16) | \
-+ (VA_MICRO_VERSION << 8))
-+
-+/**
-+ * VA_CHECK_VERSION:
-+ * @major: major version, like 1 in 1.2.3
-+ * @minor: minor version, like 2 in 1.2.3
-+ * @micro: micro version, like 3 in 1.2.3
-+ *
-+ * Evaluates to %TRUE if the version of VA-API is greater than
-+ * @major, @minor and @micro
-+ */
-+#define VA_CHECK_VERSION(major,minor,micro) \
-+ (VA_MAJOR_VERSION > (major) || \
-+ (VA_MAJOR_VERSION == (major) && VA_MINOR_VERSION > (minor)) || \
-+ (VA_MAJOR_VERSION == (major) && VA_MINOR_VERSION == (minor) && VA_MICRO_VERSION >= (micro)))
-+
-+#endif /* VA_VERSION_H */
-diff -up firefox-84.0/widget/gtk/DMABufSurface.h.ffvpx firefox-84.0/widget/gtk/DMABufSurface.h
---- firefox-84.0/widget/gtk/DMABufSurface.h.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/widget/gtk/DMABufSurface.h 2020-12-10 20:40:53.391541423 +0100
-@@ -8,10 +8,9 @@
- #define DMABufSurface_h__
-
- #include <stdint.h>
--#include "GLContext.h"
--#include "GLContextTypes.h"
- #include "mozilla/widget/nsWaylandDisplay.h"
- #include "mozilla/widget/va_drmcommon.h"
-+#include "GLTypes.h"
-
- typedef void* EGLImageKHR;
- typedef void* EGLSyncKHR;
-@@ -23,6 +22,9 @@ namespace layers {
- class SurfaceDescriptor;
- class SurfaceDescriptorDMABuf;
- } // namespace layers
-+namespace gl {
-+class GLContext;
-+}
- } // namespace mozilla
-
- typedef enum {
-diff -up firefox-84.0/widget/gtk/nsWaylandDisplay.cpp.ffvpx firefox-84.0/widget/gtk/nsWaylandDisplay.cpp
---- firefox-84.0/widget/gtk/nsWaylandDisplay.cpp.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/widget/gtk/nsWaylandDisplay.cpp 2020-12-10 20:40:53.391541423 +0100
-@@ -6,6 +6,10 @@
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- #include "nsWaylandDisplay.h"
-+
-+#include "base/message_loop.h" // for MessageLoop
-+#include "base/task.h" // for NewRunnableMethod, etc
-+#include "mozilla/StaticMutex.h"
- #include "mozilla/StaticPrefs_widget.h"
-
- namespace mozilla {
-diff -up firefox-84.0/widget/gtk/nsWaylandDisplay.h.ffvpx firefox-84.0/widget/gtk/nsWaylandDisplay.h
---- firefox-84.0/widget/gtk/nsWaylandDisplay.h.ffvpx 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/widget/gtk/nsWaylandDisplay.h 2020-12-10 20:40:53.391541423 +0100
-@@ -10,10 +10,6 @@
-
- #include "DMABufLibWrapper.h"
-
--#include "base/message_loop.h" // for MessageLoop
--#include "base/task.h" // for NewRunnableMethod, etc
--#include "mozilla/StaticMutex.h"
--
- #include "mozilla/widget/mozwayland.h"
- #include "mozilla/widget/gbm.h"
- #include "mozilla/widget/gtk-primary-selection-client-protocol.h"
diff --git a/firefox-testing.patch b/firefox-testing.patch
index 965dd1a..ae07de4 100644
--- a/firefox-testing.patch
+++ b/firefox-testing.patch
@@ -1,6 +1,6 @@
-diff -up firefox-84.0/docshell/base/crashtests/crashtests.list.testing firefox-84.0/docshell/base/crashtests/crashtests.list
---- firefox-84.0/docshell/base/crashtests/crashtests.list.testing 2020-12-07 23:32:58.000000000 +0100
-+++ firefox-84.0/docshell/base/crashtests/crashtests.list 2020-12-10 12:42:49.725237640 +0100
+diff -up firefox-85.0/docshell/base/crashtests/crashtests.list.testing firefox-85.0/docshell/base/crashtests/crashtests.list
+--- firefox-85.0/docshell/base/crashtests/crashtests.list.testing 2021-01-18 19:29:32.000000000 +0100
++++ firefox-85.0/docshell/base/crashtests/crashtests.list 2021-01-21 09:45:17.767276466 +0100
@@ -13,7 +13,6 @@ load 614499-1.html
load 678872-1.html
skip-if(Android) pref(dom.disable_open_during_load,false) load 914521.html # Android bug 1584562
@@ -9,21 +9,20 @@ diff -up firefox-84.0/docshell/base/crashtests/crashtests.list.testing firefox-8
load 1341657.html
load 1584467.html
load 1614211-1.html
-diff -up firefox-84.0/dom/media/tests/crashtests/crashtests.list.testing firefox-84.0/dom/media/tests/crashtests/crashtests.list
---- firefox-84.0/dom/media/tests/crashtests/crashtests.list.testing 2020-12-08 00:35:04.000000000 +0100
-+++ firefox-84.0/dom/media/tests/crashtests/crashtests.list 2020-12-10 12:42:49.725237640 +0100
-@@ -24,7 +24,7 @@ asserts-if(Android,0-1) pref(browser.lin
- asserts-if(Android,0-1) pref(browser.link.open_newwindow,2) load 1429507_2.html # window.open() in tab doesn't work for crashtest in e10s, this opens a new window instead
+diff -up firefox-85.0/dom/media/tests/crashtests/crashtests.list.testing firefox-85.0/dom/media/tests/crashtests/crashtests.list
+--- firefox-85.0/dom/media/tests/crashtests/crashtests.list.testing 2021-01-21 09:45:17.767276466 +0100
++++ firefox-85.0/dom/media/tests/crashtests/crashtests.list 2021-01-21 09:48:35.245124690 +0100
+@@ -25,7 +25,6 @@ asserts-if(Android,0-1) pref(browser.lin
+ load 1443212.html
asserts-if(Android,0-2) load 1453030.html
load 1468451.html
-skip-if(Android) load 1490700.html # No screenshare on Android
-+#skip-if(Android) load 1490700.html # No screenshare on Android and Wayland
load 1505957.html
load 1509442.html
load 1511130.html
-diff -up firefox-84.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py.testing firefox-84.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py
---- firefox-84.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py.testing 2020-12-10 12:42:49.725237640 +0100
-+++ firefox-84.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py 2020-12-10 12:54:22.885925814 +0100
+diff -up firefox-85.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py.testing firefox-85.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py
+--- firefox-85.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py.testing 2021-01-18 19:30:26.000000000 +0100
++++ firefox-85.0/testing/marionette/harness/marionette_harness/tests/unit/test_marionette.py 2021-01-21 09:45:17.767276466 +0100
@@ -69,15 +69,7 @@ class TestMarionette(MarionetteTestCase)
def test_application_update_disabled(self):
@@ -41,18 +40,18 @@ diff -up firefox-84.0/testing/marionette/harness/marionette_harness/tests/unit/t
self.assertFalse(update_allowed)
-diff --git a/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt b/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt
---- a/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt
-+++ b/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt
+diff -up firefox-85.0/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt.testing firefox-85.0/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt
+--- firefox-85.0/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt.testing 2021-01-18 19:30:19.000000000 +0100
++++ firefox-85.0/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements_3.txt 2021-01-21 09:45:17.767276466 +0100
@@ -1,4 +1,5 @@
# This file is the websocketprocess requirements.txt used with python 3.
+pyrsistent
# needed by txws, and we'd like pip to get it from the local server before setuptools tries pypi
six
-diff -up firefox-84.0/toolkit/crashreporter/test/unit/xpcshell.ini.old firefox-84.0/toolkit/crashreporter/test/unit/xpcshell.ini
---- firefox-84.0/toolkit/crashreporter/test/unit/xpcshell.ini.old 2020-12-15 12:21:16.177169732 +0100
-+++ firefox-84.0/toolkit/crashreporter/test/unit/xpcshell.ini 2020-12-15 12:21:22.336348783 +0100
+diff -up firefox-85.0/toolkit/crashreporter/test/unit/xpcshell.ini.testing firefox-85.0/toolkit/crashreporter/test/unit/xpcshell.ini
+--- firefox-85.0/toolkit/crashreporter/test/unit/xpcshell.ini.testing 2021-01-18 19:31:16.000000000 +0100
++++ firefox-85.0/toolkit/crashreporter/test/unit/xpcshell.ini 2021-01-21 09:45:17.767276466 +0100
@@ -37,7 +37,7 @@ skip-if = (os != 'win' && os != 'linux')
[test_crash_AsyncShutdown.js]
diff --git a/firefox-tests-reftest.patch b/firefox-tests-reftest.patch
index d18f6fd..625661c 100644
--- a/firefox-tests-reftest.patch
+++ b/firefox-tests-reftest.patch
@@ -1,6 +1,6 @@
-diff -up firefox-84.0.2/dom/canvas/test/reftest/filters/reftest.list.firefox-tests-reftest firefox-84.0.2/dom/canvas/test/reftest/filters/reftest.list
---- firefox-84.0.2/dom/canvas/test/reftest/filters/reftest.list.firefox-tests-reftest 2021-01-05 19:12:22.000000000 +0100
-+++ firefox-84.0.2/dom/canvas/test/reftest/filters/reftest.list 2021-01-12 20:30:45.682412237 +0100
+diff -up firefox-85.0/dom/canvas/test/reftest/filters/reftest.list.firefox-tests-reftest firefox-85.0/dom/canvas/test/reftest/filters/reftest.list
+--- firefox-85.0/dom/canvas/test/reftest/filters/reftest.list.firefox-tests-reftest 2021-01-18 19:29:38.000000000 +0100
++++ firefox-85.0/dom/canvas/test/reftest/filters/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -18,7 +18,6 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(
== svg-off-screen.html ref.html
== units.html ref.html
@@ -9,9 +9,9 @@ diff -up firefox-84.0.2/dom/canvas/test/reftest/filters/reftest.list.firefox-tes
== units-off-screen.html ref.html
fuzzy(0-2,0-700) == fillText-with-filter-opacity-1.html fillText-with-filter-opacity-1-ref.html
fuzzy(0-1,0-302) == fillText-with-filter-opacity-2.html fillText-with-filter-opacity-2-ref.html
-diff -up firefox-84.0.2/dom/html/reftests/reftest.list.firefox-tests-reftest firefox-84.0.2/dom/html/reftests/reftest.list
---- firefox-84.0.2/dom/html/reftests/reftest.list.firefox-tests-reftest 2021-01-05 19:12:22.000000000 +0100
-+++ firefox-84.0.2/dom/html/reftests/reftest.list 2021-01-12 20:30:45.682412237 +0100
+diff -up firefox-85.0/dom/html/reftests/reftest.list.firefox-tests-reftest firefox-85.0/dom/html/reftests/reftest.list
+--- firefox-85.0/dom/html/reftests/reftest.list.firefox-tests-reftest 2021-01-18 19:29:38.000000000 +0100
++++ firefox-85.0/dom/html/reftests/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -43,7 +43,6 @@ skip-if(Android) == 649134-2.html 649134
# image-orientation when determining the size of the image.
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
@@ -20,15 +20,15 @@ diff -up firefox-84.0.2/dom/html/reftests/reftest.list.firefox-tests-reftest fir
fuzzy(0-3,0-640) fuzzy-if(skiaContent,0-3,0-7544) fuzzy-if(webrender&&!geckoview,2-3,50-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
# Test support for SVG-as-image in <picture> elements.
-diff -up firefox-84.0.2/dom/media/webvtt/test/reftest/reftest.list.firefox-tests-reftest firefox-84.0.2/dom/media/webvtt/test/reftest/reftest.list
---- firefox-84.0.2/dom/media/webvtt/test/reftest/reftest.list.firefox-tests-reftest 2021-01-05 19:12:23.000000000 +0100
-+++ firefox-84.0.2/dom/media/webvtt/test/reftest/reftest.list 2021-01-12 20:30:45.682412237 +0100
+diff -up firefox-85.0/dom/media/webvtt/test/reftest/reftest.list.firefox-tests-reftest firefox-85.0/dom/media/webvtt/test/reftest/reftest.list
+--- firefox-85.0/dom/media/webvtt/test/reftest/reftest.list.firefox-tests-reftest 2021-01-18 19:29:39.000000000 +0100
++++ firefox-85.0/dom/media/webvtt/test/reftest/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -1,2 +1 @@
skip-if(Android) fuzzy-if((/^Windows\x20NT\x2010\.0/.test(http.oscpu))&&(/^aarch64-msvc/.test(xulRuntime.XPCOMABI)),0-136,0-427680) == vtt_update_display_after_removed_cue.html vtt_update_display_after_removed_cue_ref.html
-skip-if(Android) fuzzy-if(winWidget,0-170,0-170) == vtt_overlapping_time.html vtt_overlapping_time-ref.html
-diff -up firefox-84.0.2/gfx/layers/apz/test/reftest/reftest.list.firefox-tests-reftest firefox-84.0.2/gfx/layers/apz/test/reftest/reftest.list
---- firefox-84.0.2/gfx/layers/apz/test/reftest/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/gfx/layers/apz/test/reftest/reftest.list 2021-01-12 20:30:45.682412237 +0100
+diff -up firefox-85.0/gfx/layers/apz/test/reftest/reftest.list.firefox-tests-reftest firefox-85.0/gfx/layers/apz/test/reftest/reftest.list
+--- firefox-85.0/gfx/layers/apz/test/reftest/reftest.list.firefox-tests-reftest 2021-01-18 19:29:39.000000000 +0100
++++ firefox-85.0/gfx/layers/apz/test/reftest/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -4,11 +4,8 @@
skip-if(!asyncPan) pref(apz.allow_zooming,true) != async-scrollbar-1-v.html about:blank
skip-if(!asyncPan) pref(apz.allow_zooming,true) != async-scrollbar-1-v-ref.html about:blank
@@ -41,9 +41,9 @@ diff -up firefox-84.0.2/gfx/layers/apz/test/reftest/reftest.list.firefox-tests-r
# Different async zoom levels. Since the scrollthumb gets async-scaled in the
# compositor, the border-radius ends of the scrollthumb are going to be a little
-diff -up firefox-84.0.2/gfx/tests/reftest/reftest.list.firefox-tests-reftest firefox-84.0.2/gfx/tests/reftest/reftest.list
---- firefox-84.0.2/gfx/tests/reftest/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/gfx/tests/reftest/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/gfx/tests/reftest/reftest.list.firefox-tests-reftest firefox-85.0/gfx/tests/reftest/reftest.list
+--- firefox-85.0/gfx/tests/reftest/reftest.list.firefox-tests-reftest 2021-01-18 19:29:44.000000000 +0100
++++ firefox-85.0/gfx/tests/reftest/reftest.list 2021-01-21 09:55:01.721579128 +0100
@@ -12,7 +12,6 @@ fuzzy(0-100,0-30) == 1149923.html 114992
== 1429411.html 1429411-ref.html
fuzzy-if(winWidget,0-1,0-4) == 1435143.html 1435143-ref.html
@@ -52,14 +52,16 @@ diff -up firefox-84.0.2/gfx/tests/reftest/reftest.list.firefox-tests-reftest fir
== 1461313.html 1461313-ref.html
fuzzy(5-32,21908-26621) fuzzy-if(webrender,4-5,868-1039) == 1463802.html 1463802-ref.html
fuzzy(0-11,0-4) == 1474722.html 1474722-ref.html
-@@ -24,4 +23,3 @@ fuzzy-if(webrender,2-7,17500-36908) == 1
+@@ -24,6 +23,5 @@ fuzzy-if(webrender,2-7,17500-36908) == 1
== bug1523410-translate-scale-snap.html bug1523410-translate-scale-snap-ref.html
== 1523080.html 1523080-ref.html
== 1616444-same-color-different-paths.html 1616444-same-color-different-paths-ref.html
-skip-if(!asyncPan||!webrender||Android) fuzzy-if(winWidget,94-94,3415-3415) pref(apz.allow_zooming,true) == picture-caching-on-async-zoom.html picture-caching-on-async-zoom.html?ref
-diff -up firefox-84.0.2/image/test/reftest/downscaling/reftest.list.firefox-tests-reftest firefox-84.0.2/image/test/reftest/downscaling/reftest.list
---- firefox-84.0.2/image/test/reftest/downscaling/reftest.list.firefox-tests-reftest 2021-01-05 19:12:23.000000000 +0100
-+++ firefox-84.0.2/image/test/reftest/downscaling/reftest.list 2021-01-14 10:43:43.676262718 +0100
+ pref(apz.allow_zooming,true) == 1662062-1-no-blurry.html 1662062-1-ref.html
+ == 1681610.html 1681610-ref.html
+diff -up firefox-85.0/image/test/reftest/downscaling/reftest.list.firefox-tests-reftest firefox-85.0/image/test/reftest/downscaling/reftest.list
+--- firefox-85.0/image/test/reftest/downscaling/reftest.list.firefox-tests-reftest 2021-01-18 19:29:39.000000000 +0100
++++ firefox-85.0/image/test/reftest/downscaling/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -87,10 +87,6 @@ fuzzy(0-20,0-999) != downscale-2c.html?2
fuzzy(0-20,0-999) != downscale-2d.html?205,53,bottom about:blank
fuzzy(0-20,0-999) fails-if(OSX>=1008&&!skiaContent) != downscale-2e.html?205,53,bottom about:blank
@@ -83,10 +85,10 @@ diff -up firefox-84.0.2/image/test/reftest/downscaling/reftest.list.firefox-test
== downscale-png.html?16,16,interlaced downscale-png.html?16,16,normal
== downscale-png.html?24,24,interlaced downscale-png.html?24,24,normal
-diff -up firefox-84.0.2/layout/reftests/abs-pos/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/abs-pos/reftest.list
---- firefox-84.0.2/layout/reftests/abs-pos/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/abs-pos/reftest.list 2021-01-12 20:30:45.683412265 +0100
-@@ -49,11 +49,9 @@ fuzzy-if(/^Windows\x20NT\x206\.1/.test(h
+diff -up firefox-85.0/layout/reftests/abs-pos/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/abs-pos/reftest.list
+--- firefox-85.0/layout/reftests/abs-pos/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/abs-pos/reftest.list 2021-01-21 09:52:08.485439676 +0100
+@@ -51,11 +51,9 @@ pref(layout.display-list.improve-fragmen
== continuation-positioned-inline-1.html continuation-positioned-inline-ref.html
== continuation-positioned-inline-2.html continuation-positioned-inline-ref.html
== scrollframe-1.html scrollframe-1-ref.html
@@ -98,9 +100,9 @@ diff -up firefox-84.0.2/layout/reftests/abs-pos/reftest.list.firefox-tests-refte
== multi-column-1.html multi-column-1-ref.html
== button-1.html button-1-ref.html
== button-2.html button-2-ref.html
-diff -up firefox-84.0.2/layout/reftests/async-scrolling/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/async-scrolling/reftest.list
---- firefox-84.0.2/layout/reftests/async-scrolling/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/async-scrolling/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/async-scrolling/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/async-scrolling/reftest.list
+--- firefox-85.0/layout/reftests/async-scrolling/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/async-scrolling/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -53,7 +53,6 @@ fuzzy-if(Android,0-6,0-4) fuzzy-if(skiaC
fuzzy-if(Android,0-6,0-4) fuzzy-if(webrender&&gtkWidget,34-34,30-32) fuzzy-if(webrender&&cocoaWidget,7-7,38-39) skip-if(!asyncPan) == offscreen-clipped-blendmode-2.html offscreen-clipped-blendmode-ref.html # Bug 1604338
fuzzy-if(Android,0-6,0-4) skip == offscreen-clipped-blendmode-3.html offscreen-clipped-blendmode-ref.html # bug 1251588 - wrong AGR on mix-blend-mode item
@@ -125,9 +127,9 @@ diff -up firefox-84.0.2/layout/reftests/async-scrolling/reftest.list.firefox-tes
fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,10-10,4-4) fuzzy-if(webrender&&gtkWidget,20-20,32-32) fuzzy-if(webrender&&cocoaWidget,15-16,44-44) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-2.html position-sticky-transformed-in-scrollframe-2-ref.html # Bug 1604338
fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,13-13,4-4) fuzzy-if(webrender&&gtkWidget,26-27,30-32) fuzzy-if(webrender&&cocoaWidget,16-16,44-44) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-1.html position-sticky-in-transformed-scrollframe-ref.html # Bug 1604338
fuzzy-if(Android&&!webrender,3-3,4-4) fuzzy-if(Android&&webrender,13-13,4-4) fuzzy-if(webrender&&gtkWidget,26-27,30-32) fuzzy-if(webrender&&cocoaWidget,16-16,44-44) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-2.html position-sticky-in-transformed-scrollframe-ref.html # Bug 1604338
-diff -up firefox-84.0.2/layout/reftests/bidi/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/bidi/reftest.list
---- firefox-84.0.2/layout/reftests/bidi/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/bidi/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/bidi/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/bidi/reftest.list
+--- firefox-85.0/layout/reftests/bidi/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/bidi/reftest.list 2021-01-21 09:52:08.485439676 +0100
@@ -30,8 +30,6 @@ random-if(cocoaWidget) == mirroring-02.h
== mixedChartype-00-j.html mixedChartype-00-ref.html
== mixedChartype-01.html mixedChartype-01-ref.html
@@ -160,9 +162,9 @@ diff -up firefox-84.0.2/layout/reftests/bidi/reftest.list.firefox-tests-reftest
== 1217833-1.html 1217833-1-ref.html
== 1217833-2.html 1217833-2-ref.html
== 1231175-1.html 1231175-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/border-radius/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/border-radius/reftest.list
---- firefox-84.0.2/layout/reftests/border-radius/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/border-radius/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/border-radius/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/border-radius/reftest.list
+--- firefox-85.0/layout/reftests/border-radius/reftest.list.firefox-tests-reftest 2021-01-18 19:29:50.000000000 +0100
++++ firefox-85.0/layout/reftests/border-radius/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -51,7 +51,6 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(
fuzzy-if(skiaContent,0-1,0-77) == clipping-5-overflow-hidden.html clipping-5-ref.html
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-4) fuzzy-if(Android,0-5,0-21) fuzzy-if(skiaContent,0-1,0-97) == clipping-5-refi.html clipping-5-ref.html
@@ -171,20 +173,20 @@ diff -up firefox-84.0.2/layout/reftests/border-radius/reftest.list.firefox-tests
fuzzy-if(true,0-2,0-29) fuzzy-if(d2d,0-46,0-71) fuzzy-if(Android,0-255,0-586) fuzzy-if(skiaContent,0-28,0-97) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),0-1,0-5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
fuzzy-if(cocoaWidget,0-1,0-4) fuzzy-if(d2d,0-59,0-342) fuzzy-if(d3d11&&advancedLayers&&!d2d,0-30,0-3) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
-diff -up firefox-84.0.2/layout/reftests/box-shadow/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/box-shadow/reftest.list
---- firefox-84.0.2/layout/reftests/box-shadow/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/box-shadow/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/box-shadow/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/box-shadow/reftest.list
+--- firefox-85.0/layout/reftests/box-shadow/reftest.list.firefox-tests-reftest 2021-01-21 09:52:08.486439705 +0100
++++ firefox-85.0/layout/reftests/box-shadow/reftest.list 2021-01-21 09:53:36.154040097 +0100
@@ -15,7 +15,6 @@ fuzzy-if(OSX==1010,0-1,0-24) fuzzy-if(d2
== boxshadow-fileupload.html boxshadow-fileupload-ref.html
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-98,0-152) fuzzy-if(skiaContent,0-13,0-28) fuzzy-if(webrender,19-19,47-47) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
--fuzzy-if(skiaContent,0-1,0-17) random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
+-fuzzy-if(skiaContent,0-1,0-18) random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
fuzzy-if(skiaContent,0-1,0-17) == boxshadow-mixed-2.html boxshadow-mixed-2-ref.html
random-if(d2d) fuzzy-if(skiaContent,0-1,0-212) fuzzy-if(webrender,0-127,0-3528) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
fuzzy-if(skiaContent,0-1,0-50) == chrome://reftest/content/box-shadow/boxshadow-dynamic.xhtml chrome://reftest/content/box-shadow/boxshadow-dynamic-ref.xhtml
-diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/bugs/reftest.list
---- firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/bugs/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/bugs/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/bugs/reftest.list
+--- firefox-85.0/layout/reftests/bugs/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/bugs/reftest.list 2021-01-21 09:54:18.891308234 +0100
@@ -461,7 +461,6 @@ random == 328829-1.xhtml 328829-1-ref.xh
!= 338251-pre.html about:blank
== 338251-pre-oh.html 338251-pre-oh-ref.html
@@ -201,7 +203,7 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
!= 363706-1.html about:blank
== 363728-1.html 363728-1-ref.html
== 363728-2.html 363728-2-ref.html
-@@ -927,8 +925,6 @@ fuzzy-if(winWidget,0-123,0-1600) fuzzy-i
+@@ -924,8 +922,6 @@ fuzzy-if(winWidget,0-123,0-1600) fuzzy-i
!= 409659-1c.html 409659-1-ref.html
fuzzy-if(winWidget,0-123,0-1900) fuzzy-if(webrender&&swgl,0-1,0-39) == 409659-1d.html 409659-1-ref.html # Bug 1128229
== 410621-1.html 410621-1-ref.html
@@ -210,23 +212,23 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
== 411367-2.html 411367-2-ref.html
== 411367-3.html 411367-3-ref.html
== 411585-1.html 411585-1-ref.html
-@@ -1001,7 +997,6 @@ fuzzy-if(skiaContent,0-1,0-40) == 421632
- fails-if(Android) fuzzy-if(webrender,63-64,1024-1024) fails-if(usesRepeatResampling&&!(webrender&&winWidget)) == 421885-1.xml 421885-1-ref.xml
+@@ -998,7 +994,6 @@ fuzzy-if(skiaContent,0-1,0-40) == 421632
+ fails-if(Android) fuzzy-if(webrender,63-65,1024-1024) fails-if(usesRepeatResampling&&!(webrender&&winWidget)) == 421885-1.xml 421885-1-ref.xml
== 421955-1.html 421955-1-ref.html
== 422249-1.html 422249-1-ref.html
-== 422394-1.html 422394-1-ref.html
== 422678-1.html 422678-1-ref.html
== 423130-1.html 423130-1-ref.html
== 423385-1.html 423385-1-ref.html
-@@ -1176,7 +1171,6 @@ fuzzy-if(webrender,0-4,0-361) == 449519-
+@@ -1173,7 +1168,6 @@ fuzzy-if(webrender,0-4,0-361) == 449519-
== 455171-5.html 455171-5-ref.html
== 455280-1.xhtml 455280-1-ref.xhtml
fails-if(Android) == 455826-1.html 455826-1-ref.html
-fails-if(Android||cocoaWidget||winWidget) == chrome://reftest/content/bugs/456147.xhtml 456147-ref.html # bug 458047
fuzzy-if(Android,0-11,0-41) fuzzy-if(winWidget||gtkWidget,0-4,0-6) fuzzy-if(d2d,0-16,0-95) fuzzy-if(skiaContent,0-42,0-154) fuzzy-if(webrender,56-60,449-570) == 456219-1a.html 456219-1-ref.html # bug 1128229
- fuzzy-if(Android,0-11,0-41) fuzzy-if(winWidget||gtkWidget,0-4,0-6) fuzzy-if(d2d,0-16,0-99) fuzzy-if(skiaContent,0-42,0-154) fuzzy-if(webrender,56-60,449-570) == 456219-1b.html 456219-1-ref.html # bug 1128229
+ fuzzy-if(Android,0-11,0-41) fuzzy-if(winWidget||gtkWidget,0-4,0-6) fuzzy-if(d2d,0-16,0-99) fuzzy-if(skiaContent,0-42,0-154) fuzzy-if(webrender,56-60,449-1251) == 456219-1b.html 456219-1-ref.html # bug 1128229
fuzzy-if(Android,0-11,0-41) fuzzy-if(winWidget||gtkWidget,0-4,0-6) fuzzy-if(d2d,0-16,0-99) fuzzy-if(skiaContent,0-42,0-154) fuzzy-if(webrender,56-60,449-497) fuzzy-if(geckoview&&webrender&&device,60-60,499-4421) == 456219-1c.html 456219-1-ref.html # bug 1128229
-@@ -1387,8 +1381,6 @@ fuzzy-if(Android,0-5,0-1656) fuzzy-if(sk
+@@ -1384,8 +1378,6 @@ fuzzy-if(Android,0-5,0-1656) fuzzy-if(sk
== 512631-1.html 512631-1-ref.html
fuzzy-if(Android,0-1,0-2) == 513153-1a.html 513153-1-ref.html
fuzzy-if(Android,0-1,0-2) == 513153-1b.html 513153-1-ref.html
@@ -235,7 +237,7 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
== chrome://reftest/content/bugs/513318-1.xhtml chrome://reftest/content/bugs/513318-1-ref.xhtml
fails-if(Android&&(!asyncPan)) != chrome://reftest/content/bugs/513318-2.xhtml chrome://reftest/content/bugs/513318-2-ref.xhtml
== 514917-1.html 514917-1-ref.html
-@@ -1831,7 +1823,6 @@ pref(layout.css.moz-document.content.ena
+@@ -1828,7 +1820,6 @@ pref(layout.css.moz-document.content.ena
fails-if(webrender) == 1059498-1.html 1059498-1-ref.html # WebRender: see bug 1504290
fails-if(webrender) == 1059498-2.html 1059498-1-ref.html # WebRender: see bug 1504290
fails-if(webrender) == 1059498-3.html 1059498-1-ref.html # WebRender: see bug 1499113
@@ -243,7 +245,7 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
== 1062792-1.html 1062792-1-ref.html
== 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
== 1066554-1.html 1066554-1-ref.html
-@@ -2032,8 +2023,6 @@ needs-focus != 1377447-1.html 1377447-2.
+@@ -2029,8 +2020,6 @@ needs-focus != 1377447-1.html 1377447-2.
== 1401317.html 1401317-ref.html
== 1401992.html 1401992-ref.html
== 1405878-1.xml 1405878-1-ref.xml
@@ -252,7 +254,7 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
fuzzy-if(webrender,0-129,0-48) == 1406179.html 1406179-ref.html
== 1406183-1.html 1406183-1-ref.html
== 1410028.html 1410028-ref.html
-@@ -2077,7 +2066,6 @@ fuzzy-if(!webrender,1-5,66-547) fuzzy-if
+@@ -2074,7 +2063,6 @@ fuzzy-if(!webrender,1-5,66-547) fuzzy-if
fuzzy-if(!webrender,0-6,0-34) fuzzy-if(Android,9-14,44-60) fails-if(webrender) == 1529992-2.html 1529992-2-ref.html
== 1535040-1.html 1535040-1-ref.html
== 1545360-1.xhtml 1545360-1-ref.xhtml
@@ -260,7 +262,7 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
== 1546856-1.html 1546856-ref.html
== 1546856-2.html 1546856-ref.html
== 1547759-1.html 1547759-1-ref.html
-@@ -2088,7 +2076,6 @@ pref(image.downscale-during-decode.enabl
+@@ -2085,7 +2073,6 @@ pref(image.downscale-during-decode.enabl
!= 1563484.html 1563484-notref.html
== 1563484.html 1563484-ref.html
fuzzy-if(!webrender||!winWidget,251-255,464-1613) fuzzy-if(geckoview&&webrender,251-255,1392-1405) skip-if(Android&&webrender) == 1562733-rotated-nastaliq-1.html 1562733-rotated-nastaliq-1-ref.html #Bug 1604765
@@ -268,9 +270,9 @@ diff -up firefox-84.0.2/layout/reftests/bugs/reftest.list.firefox-tests-reftest
test-pref(plain_text.wrap_long_lines,false) != 1565129.txt 1565129.txt
fuzzy(0-32,0-8) fuzzy-if(Android&&webrender,0-32,0-1458) == 1576553-1.html 1576553-1-ref.html
fuzzy(0-1,0-10000) == 1577566-1.html 1577566-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/canvas/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/canvas/reftest.list
---- firefox-84.0.2/layout/reftests/canvas/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/canvas/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/canvas/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/canvas/reftest.list
+--- firefox-85.0/layout/reftests/canvas/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/canvas/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -48,10 +48,7 @@ fuzzy-if(azureSkiaGL,0-10,0-400) == text
!= text-bidi-ltr-test.html text-bidi-ltr-notref.html # for bug 698185
== text-bidi-rtl-test.html text-bidi-rtl-ref.html
@@ -282,9 +284,9 @@ diff -up firefox-84.0.2/layout/reftests/canvas/reftest.list.firefox-tests-reftes
random-if(!d2d) != text-subpixel-1.html text-subpixel-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/columns/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/columns/reftest.list
---- firefox-84.0.2/layout/reftests/columns/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/columns/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/columns/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/columns/reftest.list
+--- firefox-85.0/layout/reftests/columns/reftest.list.firefox-tests-reftest 2021-01-18 19:30:05.000000000 +0100
++++ firefox-85.0/layout/reftests/columns/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -5,7 +5,6 @@
== min-width-1a.html pref-width-1-ref.html
== min-width-1b.html min-width-1-ref.html
@@ -293,9 +295,9 @@ diff -up firefox-84.0.2/layout/reftests/columns/reftest.list.firefox-tests-refte
== column-balancing-overflow-000.html column-balancing-overflow-000.ref.html
== column-balancing-overflow-001.html column-balancing-overflow-000.ref.html
== column-balancing-overflow-002.html column-balancing-overflow-002.ref.html
-diff -up firefox-84.0.2/layout/reftests/css-blending/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/css-blending/reftest.list
---- firefox-84.0.2/layout/reftests/css-blending/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/css-blending/reftest.list 2021-01-12 20:30:45.683412265 +0100
+diff -up firefox-85.0/layout/reftests/css-blending/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/css-blending/reftest.list
+--- firefox-85.0/layout/reftests/css-blending/reftest.list.firefox-tests-reftest 2021-01-18 19:29:50.000000000 +0100
++++ firefox-85.0/layout/reftests/css-blending/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -87,9 +87,6 @@ test-pref(image.animation_mode,"none") =
== background-blending-background-attachement-fixed.html background-blending-background-attachement-fixed-ref.html
== background-blending-background-attachement-fixed-scroll.html background-blending-background-attachement-fixed-scroll-ref.html
@@ -306,9 +308,9 @@ diff -up firefox-84.0.2/layout/reftests/css-blending/reftest.list.firefox-tests-
== background-blending-moz-element.html background-blending-moz-element-ref.html
fuzzy(0-1,0-40000) == mix-blend-mode-soft-light.html mix-blend-mode-soft-light-ref.html
-diff -up firefox-84.0.2/layout/reftests/css-break/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/css-break/reftest.list
---- firefox-84.0.2/layout/reftests/css-break/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/css-break/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/css-break/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/css-break/reftest.list
+--- firefox-85.0/layout/reftests/css-break/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/css-break/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -1,6 +1,3 @@
-== box-decoration-break-1.html box-decoration-break-1-ref.html
-fuzzy(0-1,0-20) fuzzy-if(skiaContent,0-1,0-700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
@@ -316,9 +318,9 @@ diff -up firefox-84.0.2/layout/reftests/css-break/reftest.list.firefox-tests-ref
== box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
== box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
== box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
-diff -up firefox-84.0.2/layout/reftests/css-grid/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/css-grid/reftest.list
---- firefox-84.0.2/layout/reftests/css-grid/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/css-grid/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/css-grid/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/css-grid/reftest.list
+--- firefox-85.0/layout/reftests/css-grid/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/css-grid/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -71,7 +71,6 @@ random-if(/^Windows\x20NT\x206\.1/.test(
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-content-min-sizing-transferred-size-003.html grid-min-content-min-sizing-transferred-size-003-ref.html # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-content-min-sizing-transferred-size-004.html grid-min-content-min-sizing-transferred-size-004-ref.html # Bug 1392106
@@ -327,9 +329,9 @@ diff -up firefox-84.0.2/layout/reftests/css-grid/reftest.list.firefox-tests-reft
fuzzy-if(webrender&&winWidget,0-1,0-75) == grid-track-intrinsic-sizing-002.html grid-track-intrinsic-sizing-002-ref.html
fuzzy-if(webrender&&winWidget,0-1,0-75) == grid-track-intrinsic-sizing-003.html grid-track-intrinsic-sizing-003-ref.html
== grid-track-intrinsic-sizing-004.html grid-track-intrinsic-sizing-004-ref.html
-diff -up firefox-84.0.2/layout/reftests/css-ruby/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/css-ruby/reftest.list
---- firefox-84.0.2/layout/reftests/css-ruby/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/css-ruby/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/css-ruby/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/css-ruby/reftest.list
+--- firefox-85.0/layout/reftests/css-ruby/reftest.list.firefox-tests-reftest 2021-01-18 19:29:51.000000000 +0100
++++ firefox-85.0/layout/reftests/css-ruby/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -14,18 +14,12 @@ test-pref(font.minimum-size.ja,16) == mi
== line-height-3.html line-height-3-ref.html
== line-height-4.html line-height-4-ref.html
@@ -349,9 +351,9 @@ diff -up firefox-84.0.2/layout/reftests/css-ruby/reftest.list.firefox-tests-reft
pref(layout.css.ruby.intercharacter.enabled,false) != ruby-intercharacter-2.htm ruby-intercharacter-2-ref.htm
# Testing a specific bug for RTL handling.
-diff -up firefox-84.0.2/layout/reftests/font-face/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/font-face/reftest.list
---- firefox-84.0.2/layout/reftests/font-face/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/font-face/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/font-face/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/font-face/reftest.list
+--- firefox-85.0/layout/reftests/font-face/reftest.list.firefox-tests-reftest 2021-01-18 19:29:50.000000000 +0100
++++ firefox-85.0/layout/reftests/font-face/reftest.list 2021-01-21 09:52:08.486439705 +0100
@@ -6,7 +6,6 @@ random-if(winWidget||gtkWidget) == downl
asserts-if(Android&&!asyncPan,1-8) != download-3-notref.html download-3.html # bug 1019192
asserts-if(Android,0-8) == download-3-ref.html download-3.html # same bugs as above
@@ -398,9 +400,9 @@ diff -up firefox-84.0.2/layout/reftests/font-face/reftest.list.firefox-tests-ref
HTTP(..) == bug-1481905-cancel-load.html bug-1481905-cancel-load-ref.html
-diff -up firefox-84.0.2/layout/reftests/font-matching/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/font-matching/reftest.list
---- firefox-84.0.2/layout/reftests/font-matching/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/font-matching/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/font-matching/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/font-matching/reftest.list
+--- firefox-85.0/layout/reftests/font-matching/reftest.list.firefox-tests-reftest 2021-01-18 19:29:51.000000000 +0100
++++ firefox-85.0/layout/reftests/font-matching/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -117,14 +117,10 @@ skip-if(!cocoaWidget) != apple-symbols-1
# distinguish between italic and oblique
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == simple-oblique.html simple-oblique-ref.html # Bug 1392106
@@ -416,9 +418,9 @@ diff -up firefox-84.0.2/layout/reftests/font-matching/reftest.list.firefox-tests
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) != italic-oblique-kinnari.html italic-oblique-kinnari-ref.html # Bug 1392106
# GTK and Windows 7 don't have full emoji and symbol font, so emoji-fallback-2
-diff -up firefox-84.0.2/layout/reftests/forms/fieldset/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/forms/fieldset/reftest.list
---- firefox-84.0.2/layout/reftests/forms/fieldset/reftest.list.firefox-tests-reftest 2021-01-05 19:12:27.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/forms/fieldset/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/forms/fieldset/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/forms/fieldset/reftest.list
+--- firefox-85.0/layout/reftests/forms/fieldset/reftest.list.firefox-tests-reftest 2021-01-18 19:29:59.000000000 +0100
++++ firefox-85.0/layout/reftests/forms/fieldset/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -5,7 +5,6 @@ fuzzy-if(skiaContent,0-2,0-13) == dynami
== fieldset-scroll-1.html fieldset-scroll-1-ref.html
== fieldset-scrolled-1.html fieldset-scrolled-1-ref.html
@@ -427,18 +429,18 @@ diff -up firefox-84.0.2/layout/reftests/forms/fieldset/reftest.list.firefox-test
== relpos-legend-1.html relpos-legend-1-ref.html
== relpos-legend-2.html relpos-legend-2-ref.html
== relpos-legend-3.html relpos-legend-3-ref.html
-diff -up firefox-84.0.2/layout/reftests/forms/input/text/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/forms/input/text/reftest.list
---- firefox-84.0.2/layout/reftests/forms/input/text/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/forms/input/text/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/forms/input/text/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/forms/input/text/reftest.list
+--- firefox-85.0/layout/reftests/forms/input/text/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/forms/input/text/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -1,5 +1,4 @@
== bounds-1.html bounds-1-ref.html
-fuzzy-if(asyncPan&&!layersGPUAccelerated,0-151,0-111) fuzzy-if(webrender,0-65,0-3) == size-1.html size-1-ref.html
== size-2.html size-2-ref.html
== baseline-1.html baseline-1-ref.html
== chrome://reftest/content/forms/input/text/centering-1.xhtml chrome://reftest/content/forms/input/text/centering-1-ref.xhtml
-diff -up firefox-84.0.2/layout/reftests/forms/placeholder/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/forms/placeholder/reftest.list
---- firefox-84.0.2/layout/reftests/forms/placeholder/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/forms/placeholder/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/forms/placeholder/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/forms/placeholder/reftest.list
+--- firefox-85.0/layout/reftests/forms/placeholder/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/forms/placeholder/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -17,9 +17,6 @@
== placeholder-4.html placeholder-overridden-ref.html
== placeholder-5.html placeholder-visible-ref.html
@@ -449,9 +451,9 @@ diff -up firefox-84.0.2/layout/reftests/forms/placeholder/reftest.list.firefox-t
skip-if(Android&&asyncPan) == placeholder-6-textarea.html placeholder-overflow-textarea-ref.html
# needs-focus == placeholder-7.html placeholder-focus-ref.html
# needs-focus == placeholder-8.html placeholder-focus-ref.html
-diff -up firefox-84.0.2/layout/reftests/forms/textbox/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/forms/textbox/reftest.list
---- firefox-84.0.2/layout/reftests/forms/textbox/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/forms/textbox/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/forms/textbox/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/forms/textbox/reftest.list
+--- firefox-85.0/layout/reftests/forms/textbox/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/forms/textbox/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -1,11 +1,9 @@
# access-key tests are no use on OS X because access keys are not indicated visually
# no real XUL theme on Android so we just skip
@@ -464,9 +466,9 @@ diff -up firefox-84.0.2/layout/reftests/forms/textbox/reftest.list.firefox-tests
skip-if(cocoaWidget||Android) != chrome://reftest/content/forms/textbox/accesskey-4.xhtml chrome://reftest/content/forms/textbox/accesskey-4-notref.xhtml
skip-if(Android) == chrome://reftest/content/forms/textbox/align-baseline-1.xhtml chrome://reftest/content/forms/textbox/align-baseline-1-ref.xhtml # test for bug 494901
skip-if(Android) == chrome://reftest/content/forms/textbox/setsize.xhtml chrome://reftest/content/forms/textbox/setsize-ref.xhtml
-diff -up firefox-84.0.2/layout/reftests/image-element/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/image-element/reftest.list
---- firefox-84.0.2/layout/reftests/image-element/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/image-element/reftest.list 2021-01-14 10:44:36.106810339 +0100
+diff -up firefox-85.0/layout/reftests/image-element/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/image-element/reftest.list
+--- firefox-85.0/layout/reftests/image-element/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/image-element/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -7,7 +7,6 @@ random == bug-364968.html bug-364968-ref
== canvas-outside-document-invalidate-01.html about:blank
fails-if(azureSkia&&!(webrender&&winWidget)) fails-if(cocoaWidget) == canvas-outside-document-invalidate-02.html about:blank # See bug 666800
@@ -483,9 +485,9 @@ diff -up firefox-84.0.2/layout/reftests/image-element/reftest.list.firefox-tests
fails-if(usesRepeatResampling&&!(webrender&&winWidget)) == element-paint-subimage-sampling-restriction.html about:blank
== element-paint-clippath.html element-paint-clippath-ref.html
fuzzy-if(webrender,36-36,712-738) == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
-diff -up firefox-84.0.2/layout/reftests/mathml/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/mathml/reftest.list
---- firefox-84.0.2/layout/reftests/mathml/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/mathml/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/mathml/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/mathml/reftest.list
+--- firefox-85.0/layout/reftests/mathml/reftest.list.firefox-tests-reftest 2021-01-18 19:29:51.000000000 +0100
++++ firefox-85.0/layout/reftests/mathml/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -23,7 +23,6 @@ fuzzy-if(cocoaWidget,0-135,0-56) == dir-
== css-spacing-1.html css-spacing-1-ref.html
pref(mathml.disabled,true) == disabled-scriptlevel-1.html disabled-scriptlevel-1-ref.html
@@ -510,26 +512,26 @@ diff -up firefox-84.0.2/layout/reftests/mathml/reftest.list.firefox-tests-reftes
fails-if(Android&&emulator) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mathvariant-1a.html mathvariant-1a-ref.html # Bug 1010679, Bug 1392106
fails-if(Android&&emulator) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mathvariant-1b.html mathvariant-1b-ref.html # Bug 1010679, Bug 1392106
fails-if(Android&&emulator) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mathvariant-1c.html mathvariant-1c-ref.html # Bug 1010679, Bug 1392106
-diff -up firefox-84.0.2/layout/reftests/outline/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/outline/reftest.list
---- firefox-84.0.2/layout/reftests/outline/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/outline/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/outline/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/outline/reftest.list
+--- firefox-85.0/layout/reftests/outline/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/outline/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -15,4 +15,3 @@ pref(layout.css.outline-style-auto.enabl
== outline-on-table.html outline-on-table-ref.html
== outline-table-caption.html outline-table-caption-ref.html
== outline-table-caption-invisible.html about:blank
-== outline-wrapped-span-1.html outline-wrapped-span-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/position-dynamic-changes/relative/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/position-dynamic-changes/relative/reftest.list
---- firefox-84.0.2/layout/reftests/position-dynamic-changes/relative/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/position-dynamic-changes/relative/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/position-dynamic-changes/relative/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/position-dynamic-changes/relative/reftest.list
+--- firefox-85.0/layout/reftests/position-dynamic-changes/relative/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/position-dynamic-changes/relative/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -1,5 +1 @@
-fuzzy-if(cocoaWidget,0-1,0-2) fuzzy-if(d2d,0-47,0-26) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-169,0-970) == move-right-bottom.html move-right-bottom-ref.html
-fuzzy-if(cocoaWidget,0-1,0-2) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-169,0-970) == move-top-left.html move-top-left-ref.html # Bug 688545
-fuzzy-if(cocoaWidget,0-1,0-3) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-144,0-580) == move-right-bottom-table.html move-right-bottom-table-ref.html
-fuzzy-if(cocoaWidget,0-1,0-3) fuzzy-if(asyncPan&&!layersGPUAccelerated,0-144,0-580) == move-top-left-table.html move-top-left-table-ref.html # Bug 688545
== percent.html percent-ref.html
-diff -up firefox-84.0.2/layout/reftests/position-sticky/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/position-sticky/reftest.list
---- firefox-84.0.2/layout/reftests/position-sticky/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/position-sticky/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/position-sticky/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/position-sticky/reftest.list
+--- firefox-85.0/layout/reftests/position-sticky/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/position-sticky/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -50,6 +50,5 @@ fuzzy-if(Android,0-8,0-630) fuzzy-if(OSX
== block-in-inline-continuations.html block-in-inline-continuations-ref.html
== iframe-1.html iframe-1-ref.html
@@ -537,9 +539,9 @@ diff -up firefox-84.0.2/layout/reftests/position-sticky/reftest.list.firefox-tes
-fuzzy-if(Android,0-4,0-4) fuzzy-if(webrender&&gtkWidget,16-17,28-32) fuzzy-if(webrender&&cocoaWidget,8-8,38-42) skip-if(!asyncPan) == transformed-2.html transformed-2-ref.html # Bug 1604644
skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(webrender&&gtkWidget,29-30,30-32) fuzzy-if(webrender&&cocoaWidget,15-16,44-44) == nested-sticky-1.html nested-sticky-1-ref.html # Bug 1604644
skip-if(!asyncPan) fuzzy-if(Android,0-10,0-4) fuzzy-if(webrender&&gtkWidget,29-30,30-32) fuzzy-if(webrender&&cocoaWidget,15-16,44-44) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),0-4,0-104) == nested-sticky-2.html nested-sticky-2-ref.html # Bug 1604644
-diff -up firefox-84.0.2/layout/reftests/reftest-sanity/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/reftest-sanity/reftest.list
---- firefox-84.0.2/layout/reftests/reftest-sanity/reftest.list.firefox-tests-reftest 2021-01-05 19:12:27.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/reftest-sanity/reftest.list 2021-01-12 20:30:45.684412292 +0100
+diff -up firefox-85.0/layout/reftests/reftest-sanity/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/reftest-sanity/reftest.list
+--- firefox-85.0/layout/reftests/reftest-sanity/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/reftest-sanity/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -128,12 +128,12 @@ pref(font.size.variable.x-western,24) !=
fails pref(font.size.variable.x-western,false) == font-size-16.html font-default.html
fails pref(font.size.variable.x-western,"foo") == font-size-16.html font-default.html
@@ -559,10 +561,10 @@ diff -up firefox-84.0.2/layout/reftests/reftest-sanity/reftest.list.firefox-test
# tests for ref-pref, and test-pref
ref-pref(font.size.variable.x-western,16) == font-size-16.html font-default.html
ref-pref(font.size.variable.x-western,16) != font-size-24.html font-default.html
-diff -up firefox-84.0.2/layout/reftests/svg/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/svg/reftest.list
---- firefox-84.0.2/layout/reftests/svg/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/svg/reftest.list 2021-01-12 20:30:45.685412320 +0100
-@@ -477,9 +477,7 @@ random-if(/^Windows\x20NT\x206\.1/.test(
+diff -up firefox-85.0/layout/reftests/svg/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/svg/reftest.list
+--- firefox-85.0/layout/reftests/svg/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/svg/reftest.list 2021-01-21 09:52:08.487439735 +0100
+@@ -478,9 +478,7 @@ random-if(/^Windows\x20NT\x206\.1/.test(
== text-in-link-02.svg text-in-link-02-ref.svg
== text-in-link-03.svg text-in-link-03-ref.svg
# Tests for bug 546813: sanity-check using HTML text, then test SVG behavior.
@@ -572,7 +574,7 @@ diff -up firefox-84.0.2/layout/reftests/svg/reftest.list.firefox-tests-reftest f
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-02.svg text-layout-02-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-03.svg text-layout-03-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-04.svg text-layout-04-ref.svg # Bug 1392106
-@@ -487,7 +485,6 @@ random-if(/^Windows\x20NT\x206\.1/.test(
+@@ -488,7 +486,6 @@ random-if(/^Windows\x20NT\x206\.1/.test(
fuzzy-if(cocoaWidget&&layersGPUAccelerated,0-1,0-3) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-06.svg text-layout-06-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-07.svg text-layout-07-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-08.svg text-layout-08-ref.svg # Bug 1392106
@@ -580,9 +582,9 @@ diff -up firefox-84.0.2/layout/reftests/svg/reftest.list.firefox-tests-reftest f
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-scale-01.svg text-scale-01-ref.svg # Bug 1392106
fuzzy-if(skiaContent,0-2,0-1000) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-scale-02.svg text-scale-02-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-scale-03.svg text-scale-03-ref.svg # Bug 1392106
-diff -up firefox-84.0.2/layout/reftests/svg/svg-integration/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/svg/svg-integration/reftest.list
---- firefox-84.0.2/layout/reftests/svg/svg-integration/reftest.list.firefox-tests-reftest 2021-01-05 19:12:27.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/svg/svg-integration/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/svg/svg-integration/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/svg/svg-integration/reftest.list
+--- firefox-85.0/layout/reftests/svg/svg-integration/reftest.list.firefox-tests-reftest 2021-01-18 19:29:51.000000000 +0100
++++ firefox-85.0/layout/reftests/svg/svg-integration/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -47,6 +47,5 @@ fuzzy(0-1,0-5000) == mask-clipPath-opaci
== transform-outer-svg-01.xhtml transform-outer-svg-01-ref.xhtml
@@ -590,9 +592,9 @@ diff -up firefox-84.0.2/layout/reftests/svg/svg-integration/reftest.list.firefox
-fuzzy-if(Android,0-4,0-10) == box-decoration-break-01.xhtml box-decoration-break-01-ref.xhtml
fuzzy(0-119,0-16) == box-decoration-break-02.xhtml box-decoration-break-02-ref.xhtml
fuzzy(0-67,0-238) == box-decoration-break-03.xhtml box-decoration-break-01-ref.xhtml
-diff -up firefox-84.0.2/layout/reftests/svg/text/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/svg/text/reftest.list
---- firefox-84.0.2/layout/reftests/svg/text/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/svg/text/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/svg/text/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/svg/text/reftest.list
+--- firefox-85.0/layout/reftests/svg/text/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/svg/text/reftest.list 2021-01-21 09:52:08.487439735 +0100
@@ -1,14 +1,5 @@
-random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(webrender&&winWidget,122-127,221-254) == simple.svg simple-ref.html # Bug 1392106
== simple-2.svg simple.svg
@@ -637,7 +639,7 @@ diff -up firefox-84.0.2/layout/reftests/svg/text/reftest.list.firefox-tests-reft
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == textpath-a.svg textpath-a-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == textpath-anchor-middle.svg textpath-anchor-middle-ref.svg # Bug 1392106
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == textpath-anchor-end.svg textpath-anchor-end-ref.svg # Bug 1392106
-@@ -196,13 +183,7 @@ needs-focus == deselectAll.svg deselectA
+@@ -198,13 +185,7 @@ needs-focus == deselectAll.svg deselectA
fuzzy-if(skiaContent,0-1,0-250) needs-focus == selectSubString.svg selectSubString-ref.svg
fuzzy-if(skiaContent,0-1,0-600) needs-focus == selectSubString-2.svg selectSubString-2-ref.svg
fuzzy-if(skiaContent,0-1,0-250) needs-focus == selectSubString-3.svg selectSubString-3-ref.svg
@@ -651,9 +653,9 @@ diff -up firefox-84.0.2/layout/reftests/svg/text/reftest.list.firefox-tests-reft
# letter-spacing and word-spacing
pref(svg.text-spacing.enabled,true) == simple-letter-spacing.svg simple-letter-spacing-ref.svg
-diff -up firefox-84.0.2/layout/reftests/tab-size/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/tab-size/reftest.list
---- firefox-84.0.2/layout/reftests/tab-size/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/tab-size/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/tab-size/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/tab-size/reftest.list
+--- firefox-85.0/layout/reftests/tab-size/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/tab-size/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -1,10 +1,4 @@
== tab-size-8.html tab-size-initial.html
-== tab-size-8.html spaces-8.html
@@ -665,18 +667,18 @@ diff -up firefox-84.0.2/layout/reftests/tab-size/reftest.list.firefox-tests-reft
== tab-size-0.html spaces-0.html
== tab-size-negative.html tab-size-initial.html
== tab-size-change-1a.html tab-size-change-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/text-decoration/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/text-decoration/reftest.list
---- firefox-84.0.2/layout/reftests/text-decoration/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/text-decoration/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/text-decoration/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/text-decoration/reftest.list
+--- firefox-85.0/layout/reftests/text-decoration/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/text-decoration/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -1,5 +1,3 @@
-fuzzy-if(webrender&&gtkWidget,0-208,0-12) == complex-decoration-style-quirks.html complex-decoration-style-quirks-ref.html
-fuzzy-if(webrender&&gtkWidget,0-208,0-12) == complex-decoration-style-standards.html complex-decoration-style-standards-ref.html
== decoration-color-quirks.html decoration-color-quirks-ref.html
== decoration-color-standards.html decoration-color-standards-ref.html
== decoration-style-quirks.html decoration-style-quirks-ref.html
-diff -up firefox-84.0.2/layout/reftests/text-overflow/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/text-overflow/reftest.list
---- firefox-84.0.2/layout/reftests/text-overflow/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/text-overflow/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/text-overflow/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/text-overflow/reftest.list
+--- firefox-85.0/layout/reftests/text-overflow/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/text-overflow/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -3,7 +3,6 @@
fuzzy-if(Android,0-16,0-244) fuzzy-if(webrender,0-47,0-6) == marker-basic.html marker-basic-ref.html # Bug 1128229
== marker-string.html marker-string-ref.html
@@ -693,9 +695,9 @@ diff -up firefox-84.0.2/layout/reftests/text-overflow/reftest.list.firefox-tests
# The vertical-text pref setting can be removed after bug 1138384 lands
== vertical-decorations-1.html vertical-decorations-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/text/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/text/reftest.list
---- firefox-84.0.2/layout/reftests/text/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/text/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/text/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/text/reftest.list
+--- firefox-85.0/layout/reftests/text/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/text/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -34,7 +34,6 @@ fuzzy-if(Android,0-255,0-325) == pre-lin
== pre-line-3.html pre-line-3-ref.html
== pre-line-4.html pre-line-4-ref.html
@@ -758,9 +760,9 @@ diff -up firefox-84.0.2/layout/reftests/text/reftest.list.firefox-tests-reftest
# osx-font-smoothing - with and without subpixel AA, only under OSX
fails-if(!cocoaWidget) != osx-font-smoothing.html osx-font-smoothing-ref.html
-diff -up firefox-84.0.2/layout/reftests/text-shadow/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/text-shadow/reftest.list
---- firefox-84.0.2/layout/reftests/text-shadow/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/text-shadow/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/text-shadow/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/text-shadow/reftest.list
+--- firefox-85.0/layout/reftests/text-shadow/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/text-shadow/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -27,9 +27,7 @@ fuzzy-if(webrender&&swgl,2-2,6320-6320)
fuzzy-if(cocoaWidget,0-27,0-2) fuzzy-if(winWidget,0-47,0-2) == overflow-clip.html overflow-clip-ref.html
@@ -771,9 +773,9 @@ diff -up firefox-84.0.2/layout/reftests/text-shadow/reftest.list.firefox-tests-r
# bug 692744
fuzzy-if(webrender,0-19,0-2872) == text-shadow-on-space-1.html text-shadow-on-space-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/text-transform/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/text-transform/reftest.list
---- firefox-84.0.2/layout/reftests/text-transform/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/text-transform/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/text-transform/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/text-transform/reftest.list
+--- firefox-85.0/layout/reftests/text-transform/reftest.list.firefox-tests-reftest 2021-01-18 19:30:14.000000000 +0100
++++ firefox-85.0/layout/reftests/text-transform/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -9,9 +9,6 @@
== capitalize-8.html capitalize-8-ref.html
== lowercase-1.html lowercase-ref.html
@@ -784,9 +786,9 @@ diff -up firefox-84.0.2/layout/reftests/text-transform/reftest.list.firefox-test
!= opentype-small-caps-1.html opentype-small-caps-1-notref.html
== graphite-small-caps-1.html graphite-small-caps-1-ref.html
!= graphite-small-caps-1.html graphite-small-caps-1-notref.html
-diff -up firefox-84.0.2/layout/reftests/transform-3d/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/transform-3d/reftest.list
---- firefox-84.0.2/layout/reftests/transform-3d/reftest.list.firefox-tests-reftest 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/transform-3d/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/transform-3d/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/transform-3d/reftest.list
+--- firefox-85.0/layout/reftests/transform-3d/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/transform-3d/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -11,7 +11,6 @@ fuzzy-if(webrender,0-1,0-6) == rotatey-1
== rotatex-perspective-1c.html rotatex-1-ref.html
== rotatex-perspective-3a.html rotatex-perspective-3-ref.html
@@ -804,9 +806,9 @@ diff -up firefox-84.0.2/layout/reftests/transform-3d/reftest.list.firefox-tests-
== scale3d-xz.html scale3d-1-ref.html
== translatez-1a.html translatez-1-ref.html
!= translatez-1b.html translatez-1-ref.html
-diff -up firefox-84.0.2/layout/reftests/writing-mode/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/writing-mode/reftest.list
---- firefox-84.0.2/layout/reftests/writing-mode/reftest.list.firefox-tests-reftest 2021-01-05 19:12:26.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/writing-mode/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/writing-mode/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/writing-mode/reftest.list
+--- firefox-85.0/layout/reftests/writing-mode/reftest.list.firefox-tests-reftest 2021-01-18 19:30:10.000000000 +0100
++++ firefox-85.0/layout/reftests/writing-mode/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -31,7 +31,6 @@ random-if(/^Windows\x20NT\x206\.1/.test(
== 1105268-2-min-max-dimensions.html 1105268-2-min-max-dimensions-ref.html
== 1106669-1-intrinsic-for-container.html 1106669-1-intrinsic-for-container-ref.html
@@ -823,9 +825,9 @@ diff -up firefox-84.0.2/layout/reftests/writing-mode/reftest.list.firefox-tests-
fuzzy-if(winWidget,0-255,0-163) fuzzy-if(skiaContent,0-159,0-111) == 1136557-1-nested-spans.html 1136557-1-nested-spans-ref.html
fuzzy-if(winWidget,0-255,0-221) fuzzy-if(skiaContent,0-159,0-111) == 1136557-2-nested-spans.html 1136557-2-nested-spans-ref.html
fuzzy-if(winWidget,0-255,0-236) == 1136557-3-nested-spans.html 1136557-3-nested-spans-ref.html
-diff -up firefox-84.0.2/layout/reftests/xul/reftest.list.firefox-tests-reftest firefox-84.0.2/layout/reftests/xul/reftest.list
---- firefox-84.0.2/layout/reftests/xul/reftest.list.firefox-tests-reftest 2021-01-05 20:58:39.000000000 +0100
-+++ firefox-84.0.2/layout/reftests/xul/reftest.list 2021-01-12 20:30:45.685412320 +0100
+diff -up firefox-85.0/layout/reftests/xul/reftest.list.firefox-tests-reftest firefox-85.0/layout/reftests/xul/reftest.list
+--- firefox-85.0/layout/reftests/xul/reftest.list.firefox-tests-reftest 2021-01-18 19:29:51.000000000 +0100
++++ firefox-85.0/layout/reftests/xul/reftest.list 2021-01-21 09:52:08.488439764 +0100
@@ -12,7 +12,6 @@ pref(layout.css.xul-tree-pseudos.content
skip-if(!cocoaWidget) fails-if(webrender&&cocoaWidget) == chrome://reftest/content/xul/mac-tab-toolbar.xhtml chrome://reftest/content/xul/mac-tab-toolbar-ref.xhtml
pref(layout.css.xul-tree-pseudos.content.enabled,true) != chrome://reftest/content/xul/tree-row-outline-1.xhtml chrome://reftest/content/xul/tree-row-outline-1-notref.xhtml
@@ -834,4 +836,3 @@ diff -up firefox-84.0.2/layout/reftests/xul/reftest.list.firefox-tests-reftest f
fuzzy-if(skiaContent,0-1,0-60) fuzzy-if(cocoaWidget&&browserIsRemote&&!skiaContent,0-1,0-31) fuzzy-if(winWidget&&browserIsRemote&&layersGPUAccelerated,0-1,0-50) fuzzy-if(webrender,0-1,350-1050) == chrome://reftest/content/xul/inactive-fixed-bg-bug1205630.xhtml inactive-fixed-bg-bug1205630-ref.html
fuzzy-if(skiaContent,0-1,0-60) fuzzy-if(cocoaWidget&&browserIsRemote&&!skiaContent,0-1,0-31) fuzzy-if(winWidget&&browserIsRemote&&layersGPUAccelerated,0-1,0-50) fuzzy-if(webrender,0-1,450-1100) == chrome://reftest/content/xul/inactive-fixed-bg-bug1272525.xhtml inactive-fixed-bg-bug1272525-ref.html
-
diff --git a/firefox-tests-xpcshell.patch b/firefox-tests-xpcshell.patch
index 96c27b8..8f9edf8 100644
--- a/firefox-tests-xpcshell.patch
+++ b/firefox-tests-xpcshell.patch
@@ -1,6 +1,6 @@
-diff -up firefox-84.0.2/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini
---- firefox-84.0.2/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-05 19:12:21.000000000 +0100
-+++ firefox-84.0.2/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini 2021-01-12 20:30:45.681412210 +0100
+diff -up firefox-85.0/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini
+--- firefox-85.0/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:29:32.000000000 +0100
++++ firefox-85.0/browser/components/enterprisepolicies/tests/xpcshell/xpcshell.ini 2021-01-21 09:49:44.587178226 +0100
@@ -6,7 +6,6 @@ support-files =
[test_3rdparty.js]
@@ -9,9 +9,9 @@ diff -up firefox-84.0.2/browser/components/enterprisepolicies/tests/xpcshell/xpc
[test_bug1658259.js]
[test_cleanup.js]
[test_clear_blocked_cookies.js]
-diff -up firefox-84.0.2/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini
---- firefox-84.0.2/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-05 19:12:22.000000000 +0100
-+++ firefox-84.0.2/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini 2021-01-12 20:30:45.681412210 +0100
+diff -up firefox-85.0/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini
+--- firefox-85.0/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:29:32.000000000 +0100
++++ firefox-85.0/devtools/client/shared/remote-debugging/adb/xpcshell/xpcshell.ini 2021-01-21 09:49:44.587178226 +0100
@@ -6,6 +6,5 @@ skip-if = toolkit == 'android' || socket
support-files =
adb.py
@@ -19,9 +19,9 @@ diff -up firefox-84.0.2/devtools/client/shared/remote-debugging/adb/xpcshell/xpc
-[test_adb.js]
run-sequentially = An extension having the same id is installed/uninstalled in different tests
[test_prepare-tcp-connection.js]
-diff -up firefox-84.0.2/netwerk/test/unit_ipc/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/netwerk/test/unit_ipc/xpcshell.ini
---- firefox-84.0.2/netwerk/test/unit_ipc/xpcshell.ini.firefox-tests-xpcshell 2021-01-14 11:03:10.741711483 +0100
-+++ firefox-84.0.2/netwerk/test/unit_ipc/xpcshell.ini 2021-01-14 11:03:17.498910928 +0100
+diff -up firefox-85.0/netwerk/test/unit_ipc/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/netwerk/test/unit_ipc/xpcshell.ini
+--- firefox-85.0/netwerk/test/unit_ipc/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:29:59.000000000 +0100
++++ firefox-85.0/netwerk/test/unit_ipc/xpcshell.ini 2021-01-21 09:49:44.587178226 +0100
@@ -70,7 +70,6 @@ support-files =
[test_channel_close_wrap.js]
[test_cookiejars_wrap.js]
@@ -30,9 +30,9 @@ diff -up firefox-84.0.2/netwerk/test/unit_ipc/xpcshell.ini.firefox-tests-xpcshel
[test_duplicate_headers_wrap.js]
[test_event_sink_wrap.js]
[test_head_wrap.js]
-diff -up firefox-84.0.2/netwerk/test/unit/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/netwerk/test/unit/xpcshell.ini
---- firefox-84.0.2/netwerk/test/unit/xpcshell.ini.firefox-tests-xpcshell 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/netwerk/test/unit/xpcshell.ini 2021-01-14 11:02:39.939802295 +0100
+diff -up firefox-85.0/netwerk/test/unit/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/netwerk/test/unit/xpcshell.ini
+--- firefox-85.0/netwerk/test/unit/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:30:19.000000000 +0100
++++ firefox-85.0/netwerk/test/unit/xpcshell.ini 2021-01-21 09:50:27.536450133 +0100
@@ -199,7 +199,6 @@ skip-if = true # Bug 863738
[test_cookies_upgrade_10.js]
[test_dns_cancel.js]
@@ -77,15 +77,15 @@ diff -up firefox-84.0.2/netwerk/test/unit/xpcshell.ini.firefox-tests-xpcshell fi
@@ -409,7 +403,6 @@ skip-if = tsan || socketprocess_networki
run-sequentially = node server exceptions dont replay well
skip-if = socketprocess_networking
- [test_esni_dns_fetch.js]
+ [test_dns_by_type_resolve.js]
-[test_network_connectivity_service.js]
[test_suspend_channel_on_authRetry.js]
[test_suspend_channel_on_examine_merged_response.js]
[test_bug1527293.js]
-diff -up firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell.ini
---- firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell.ini.firefox-tests-xpcshell 2021-01-14 11:05:59.458691431 +0100
-+++ firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell.ini 2021-01-14 11:06:51.073214918 +0100
-@@ -175,7 +175,6 @@ run-sequentially = hardcoded ports
+diff -up firefox-85.0/security/manager/ssl/tests/unit/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/security/manager/ssl/tests/unit/xpcshell.ini
+--- firefox-85.0/security/manager/ssl/tests/unit/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:29:59.000000000 +0100
++++ firefox-85.0/security/manager/ssl/tests/unit/xpcshell.ini 2021-01-21 09:49:44.588178255 +0100
+@@ -180,7 +180,6 @@ run-sequentially = hardcoded ports
run-sequentially = hardcoded ports
[test_ocsp_url.js]
run-sequentially = hardcoded ports
@@ -93,9 +93,9 @@ diff -up firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell.ini.firefox-tes
[test_osreauthenticator.js]
# Reauthentication has been implemented on Windows and MacOS, so running this
# test results in the OS popping up a dialog, which means we can't run it in
-diff -up firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell-smartcards.ini.firefox-tests-xpcshell firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell-smartcards.ini
---- firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell-smartcards.ini.firefox-tests-xpcshell 2021-01-05 19:12:27.000000000 +0100
-+++ firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell-smartcards.ini 2021-01-12 20:30:45.681412210 +0100
+diff -up firefox-85.0/security/manager/ssl/tests/unit/xpcshell-smartcards.ini.firefox-tests-xpcshell firefox-85.0/security/manager/ssl/tests/unit/xpcshell-smartcards.ini
+--- firefox-85.0/security/manager/ssl/tests/unit/xpcshell-smartcards.ini.firefox-tests-xpcshell 2021-01-18 19:29:59.000000000 +0100
++++ firefox-85.0/security/manager/ssl/tests/unit/xpcshell-smartcards.ini 2021-01-21 09:49:44.588178255 +0100
@@ -7,7 +7,6 @@ support-files =
[test_osclientcerts_module.js]
@@ -104,18 +104,18 @@ diff -up firefox-84.0.2/security/manager/ssl/tests/unit/xpcshell-smartcards.ini.
[test_pkcs11_moduleDB.js]
[test_pkcs11_safe_mode.js]
[test_pkcs11_slot.js]
-diff -up firefox-84.0.2/toolkit/components/commandlines/test/unit/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/toolkit/components/commandlines/test/unit/xpcshell.ini
---- firefox-84.0.2/toolkit/components/commandlines/test/unit/xpcshell.ini.firefox-tests-xpcshell 2021-01-05 19:12:33.000000000 +0100
-+++ firefox-84.0.2/toolkit/components/commandlines/test/unit/xpcshell.ini 2021-01-12 20:30:45.681412210 +0100
+diff -up firefox-85.0/toolkit/components/commandlines/test/unit/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/toolkit/components/commandlines/test/unit/xpcshell.ini
+--- firefox-85.0/toolkit/components/commandlines/test/unit/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:31:16.000000000 +0100
++++ firefox-85.0/toolkit/components/commandlines/test/unit/xpcshell.ini 2021-01-21 09:49:44.588178255 +0100
@@ -7,4 +7,3 @@ support-files =
[test_classinfo.js]
[test_bug666224.js]
-[test_resolvefile.js]
-diff -up firefox-84.0.2/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini.firefox-tests-xpcshell firefox-84.0.2/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
---- firefox-84.0.2/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini.firefox-tests-xpcshell 2021-01-14 11:07:47.513880856 +0100
-+++ firefox-84.0.2/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini 2021-01-14 11:08:33.169228446 +0100
-@@ -69,8 +69,6 @@ skip-if = socketprocess_networking
+diff -up firefox-85.0/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini.firefox-tests-xpcshell firefox-85.0/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
+--- firefox-85.0/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini.firefox-tests-xpcshell 2021-01-18 19:31:16.000000000 +0100
++++ firefox-85.0/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini 2021-01-21 09:49:44.588178255 +0100
+@@ -73,8 +73,6 @@ skip-if = socketprocess_networking || os
skip-if = os == "android" # downloads API needs to be implemented in GeckoView - bug 1538348
[test_ext_downloads_download.js]
skip-if = appname == "thunderbird" || os == "android" || tsan # tsan: bug 1612707
@@ -124,7 +124,7 @@ diff -up firefox-84.0.2/toolkit/components/extensions/test/xpcshell/xpcshell-com
[test_ext_downloads_private.js]
skip-if = os == "android"
[test_ext_downloads_search.js]
-@@ -230,8 +228,6 @@ skip-if = appname == "thunderbird" || os
+@@ -241,8 +239,6 @@ skip-if = appname == "thunderbird" || os
skip-if = appname == "thunderbird" || os == "android" # Bug 1350559
[test_ext_permissions_uninstall.js]
skip-if = appname == "thunderbird" || os == "android" # Bug 1350559
@@ -133,9 +133,9 @@ diff -up firefox-84.0.2/toolkit/components/extensions/test/xpcshell/xpcshell-com
[test_proxy_incognito.js]
skip-if = os == "android" # incognito not supported on android
[test_proxy_info_results.js]
-diff -up firefox-84.0.2/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini
---- firefox-84.0.2/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-05 19:12:34.000000000 +0100
-+++ firefox-84.0.2/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini 2021-01-12 20:30:45.681412210 +0100
+diff -up firefox-85.0/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini
+--- firefox-85.0/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:30:38.000000000 +0100
++++ firefox-85.0/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini 2021-01-21 09:49:44.588178255 +0100
@@ -7,6 +7,5 @@ support-files =
data_text_file.txt
data_test_script.py
@@ -143,10 +143,10 @@ diff -up firefox-84.0.2/toolkit/modules/subprocess/test/xpcshell/xpcshell.ini.fi
-[test_subprocess.js]
[test_subprocess_getEnvironment.js]
[test_subprocess_pathSearch.js]
-diff -up firefox-84.0.2/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-84.0.2/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
---- firefox-84.0.2/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-05 21:29:48.000000000 +0100
-+++ firefox-84.0.2/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini 2021-01-12 20:30:45.681412210 +0100
-@@ -97,7 +97,6 @@ tags = webextensions
+diff -up firefox-85.0/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell firefox-85.0/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+--- firefox-85.0/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini.firefox-tests-xpcshell 2021-01-18 19:30:38.000000000 +0100
++++ firefox-85.0/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini 2021-01-21 09:49:44.588178255 +0100
+@@ -94,7 +94,6 @@ tags = webextensions
head = head_addons.js head_sideload.js
skip-if = os == "linux" # Bug 1613268
[test_sideloads.js]
diff --git a/firefox-vaapi-extra-frames.patch b/firefox-vaapi-extra-frames.patch
deleted file mode 100644
index e26158a..0000000
--- a/firefox-vaapi-extra-frames.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -up firefox-76.0.1/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp.old firefox-76.0.1/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
---- firefox-76.0.1/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp.old 2020-05-13 14:28:26.556800474 +0200
-+++ firefox-76.0.1/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp 2020-05-13 14:28:31.562768959 +0200
-@@ -43,7 +43,7 @@ typedef int VAStatus;
- #endif
-
- // Use some extra HW frames for potential rendering lags.
--#define EXTRA_HW_FRAMES 6
-+#define EXTRA_HW_FRAMES 20
-
- typedef mozilla::layers::Image Image;
- typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
diff --git a/firefox.spec b/firefox.spec
index 956e39c..2f84ea8 100644
--- a/firefox.spec
+++ b/firefox.spec
@@ -14,7 +14,7 @@
# as the build is *very* slow.
%global debug_build 0
-%global system_nss 1
+%global system_nss 0
%global build_with_clang 0
%global build_with_asan 0
%global test_offscreen 1
@@ -146,13 +146,13 @@ ExcludeArch: s390x
Summary: Mozilla Firefox Web browser
Name: firefox
-Version: 84.0.2
-Release: 8%{?pre_tag}%{?dist}
+Version: 85.0
+Release: 1%{?pre_tag}%{?dist}
URL: https://www.mozilla.org/firefox/
License: MPLv1.1 or GPLv2+ or LGPLv2+
Source0: https://archive.mozilla.org/pub/firefox/releases/%{version}%{?pre_version}/source/firefox-%{version}%{?pre_version}.source.tar.xz
%if %{with langpacks}
-Source1: firefox-langpacks-%{version}%{?pre_version}-20210106.tar.xz
+Source1: firefox-langpacks-%{version}%{?pre_version}-20210120.tar.xz
%endif
Source2: cbindgen-vendor.tar.xz
Source10: firefox-mozconfig
@@ -226,19 +226,7 @@ Patch422: mozilla-1631061.patch
Patch423: mozilla-1681107.patch
Patch424: firefox-wayland-fix-mzbz-1642949-regression.patch
Patch425: mozilla-1645695.patch
-
-# Upstream patches from mozbz#1672944
-Patch450: pw1.patch
-Patch451: pw2.patch
-Patch452: pw3.patch
-Patch453: pw4.patch
-Patch454: pw5.patch
-Patch455: pw6.patch
-
-Patch500: ffvpx.patch
-
-#VA-API patches
-Patch585: firefox-vaapi-extra-frames.patch
+Patch426: mozilla-1687931.patch
# PGO/LTO patches
Patch600: pgo.patch
@@ -414,7 +402,7 @@ This package contains results of tests executed during build.
%endif
%patch3 -p1 -b .arm
%patch44 -p1 -b .build-arm-libopus
-%patch46 -p1 -b .nss-version
+#%patch46 -p1 -b .nss-version
%patch47 -p1 -b .fedora-shebang
%patch48 -p1 -b .build-arm-wasm
%patch49 -p1 -b .build-arm-libaom
@@ -445,24 +433,10 @@ This package contains results of tests executed during build.
%patch415 -p1 -b .1670333
%patch418 -p1 -b .1556931-s390x-hidden-syms
-#%patch450 -p1 -b .pw1
-#%patch451 -p1 -b .pw2
-#%patch452 -p1 -b .pw3
-#%patch453 -p1 -b .pw4
-#%patch454 -p1 -b .pw5
-%patch455 -p1 -b .pw6
-%patch420 -p1 -b .1678680
-%patch421 -p1 -b .1680505
-#%patch422 -p1 -b .1631061
%patch423 -p1 -b .1681107
%patch424 -p1 -b .fix-mzbz-1642949-regression
%patch425 -p1 -b .1645695
-
-%patch500 -p1 -b .ffvpx
-
-# VA-API fixes
-# merged with ffvpx
-# %patch585 -p1 -b .firefox-vaapi-extra-frames
+%patch426 -p1 -b .1687931
# PGO patches
%if %{build_with_pgo}
@@ -1043,6 +1017,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
#---------------------------------------------------------------------
%changelog
+* Wed Jan 20 2021 Martin Stransky <stransky@redhat.com> - 85.0-1
+- Update to 85.0.
+
* Wed Jan 20 2021 Jan Horak <jhorak@redhat.com> - 84.0.2-8
- Fixing package requires/provides
diff --git a/mozilla-1667096.patch b/mozilla-1667096.patch
index cbe8aea..981ced4 100644
--- a/mozilla-1667096.patch
+++ b/mozilla-1667096.patch
@@ -1,6 +1,6 @@
-diff -up firefox-84.0/media/ffvpx/libavcodec/codec_list.c.1667096 firefox-84.0/media/ffvpx/libavcodec/codec_list.c
---- firefox-84.0/media/ffvpx/libavcodec/codec_list.c.1667096 2020-12-07 23:33:03.000000000 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/codec_list.c 2020-12-10 12:57:14.722762321 +0100
+diff -up firefox-85.0/media/ffvpx/libavcodec/codec_list.c.1667096 firefox-85.0/media/ffvpx/libavcodec/codec_list.c
+--- firefox-85.0/media/ffvpx/libavcodec/codec_list.c.1667096 2021-01-18 19:29:51.000000000 +0100
++++ firefox-85.0/media/ffvpx/libavcodec/codec_list.c 2021-01-21 09:56:17.637831802 +0100
@@ -11,4 +11,8 @@ static const AVCodec * const codec_list[
#if CONFIG_MP3_DECODER
&ff_mp3_decoder,
@@ -10,9 +10,9 @@ diff -up firefox-84.0/media/ffvpx/libavcodec/codec_list.c.1667096 firefox-84.0/m
+#endif
+
NULL };
-diff -up firefox-84.0/media/ffvpx/libavcodec/libfdk-aacdec.c.1667096 firefox-84.0/media/ffvpx/libavcodec/libfdk-aacdec.c
---- firefox-84.0/media/ffvpx/libavcodec/libfdk-aacdec.c.1667096 2020-12-10 12:57:14.722762321 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/libfdk-aacdec.c 2020-12-10 12:57:14.722762321 +0100
+diff -up firefox-85.0/media/ffvpx/libavcodec/libfdk-aacdec.c.1667096 firefox-85.0/media/ffvpx/libavcodec/libfdk-aacdec.c
+--- firefox-85.0/media/ffvpx/libavcodec/libfdk-aacdec.c.1667096 2021-01-21 09:56:17.638831832 +0100
++++ firefox-85.0/media/ffvpx/libavcodec/libfdk-aacdec.c 2021-01-21 09:56:17.638831832 +0100
@@ -0,0 +1,409 @@
+/*
+ * AAC decoder wrapper
@@ -423,12 +423,12 @@ diff -up firefox-84.0/media/ffvpx/libavcodec/libfdk-aacdec.c.1667096 firefox-84.
+ FF_CODEC_CAP_INIT_CLEANUP,
+ .wrapper_name = "libfdk",
+};
-diff -up firefox-84.0/media/ffvpx/libavcodec/moz.build.1667096 firefox-84.0/media/ffvpx/libavcodec/moz.build
---- firefox-84.0/media/ffvpx/libavcodec/moz.build.1667096 2020-12-08 00:35:05.000000000 +0100
-+++ firefox-84.0/media/ffvpx/libavcodec/moz.build 2020-12-10 12:57:14.722762321 +0100
-@@ -97,6 +97,12 @@ if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
- 'vp9recon.c'
- ]
+diff -up firefox-85.0/media/ffvpx/libavcodec/moz.build.1667096 firefox-85.0/media/ffvpx/libavcodec/moz.build
+--- firefox-85.0/media/ffvpx/libavcodec/moz.build.1667096 2021-01-21 09:56:17.638831832 +0100
++++ firefox-85.0/media/ffvpx/libavcodec/moz.build 2021-01-21 10:06:18.958716728 +0100
+@@ -104,6 +104,12 @@ if not CONFIG['MOZ_FFVPX_AUDIOONLY']:
+ ]
+ USE_LIBS += ['mozva']
+if CONFIG['MOZ_FDK_AAC']:
+ SOURCES += [
@@ -439,9 +439,9 @@ diff -up firefox-84.0/media/ffvpx/libavcodec/moz.build.1667096 firefox-84.0/medi
if CONFIG['MOZ_LIBAV_FFT']:
SOURCES += [
'avfft.c',
-diff -up firefox-84.0/toolkit/moz.configure.1667096 firefox-84.0/toolkit/moz.configure
---- firefox-84.0/toolkit/moz.configure.1667096 2020-12-10 12:57:14.723762349 +0100
-+++ firefox-84.0/toolkit/moz.configure 2020-12-10 12:58:29.051855203 +0100
+diff -up firefox-85.0/toolkit/moz.configure.1667096 firefox-85.0/toolkit/moz.configure
+--- firefox-85.0/toolkit/moz.configure.1667096 2021-01-21 09:56:17.603830793 +0100
++++ firefox-85.0/toolkit/moz.configure 2021-01-21 09:56:17.638831832 +0100
@@ -1868,6 +1868,14 @@ with only_when(compile_environment):
set_define("MOZ_LIBAV_FFT", depends(when=libav_fft)(lambda: True))
set_config("LIBAV_FFT_ASFLAGS", libav_fft.flags)
diff --git a/mozilla-1678680.patch b/mozilla-1678680.patch
deleted file mode 100644
index 5c4953a..0000000
--- a/mozilla-1678680.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-changeset: 560838:7a5a1784b5d1
-tag: tip
-parent: 560835:7184fb5a42fb
-user: Martin Stransky <stransky@redhat.com>
-date: Fri Nov 27 17:29:07 2020 +0100
-files: third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
-description:
-Bug 1678680 [PipeWire] Lock current_frame_ access as it can be used from multiple threads, r?dminor
-
-Differential Revision: https://phabricator.services.mozilla.com/D98080
-
-
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
-@@ -396,16 +396,17 @@ void BaseCapturerPipeWire::HandleBuffer(
- DesktopSize video_size_prev = video_size_;
- if (video_metadata_use_) {
- video_size_ = DesktopSize(video_metadata->region.size.width,
- video_metadata->region.size.height);
- } else {
- video_size_ = desktop_size_;
- }
-
-+ rtc::CritScope lock(&current_frame_lock_);
- if (!current_frame_ ||
- (video_metadata_use_ && !video_size_.equals(video_size_prev))) {
- current_frame_ =
- std::make_unique<uint8_t[]>
- (video_size_.width() * video_size_.height() * kBytesPerPixel);
- }
-
- const int32_t dstStride = video_size_.width() * kBytesPerPixel;
-@@ -872,16 +873,17 @@ void BaseCapturerPipeWire::Start(Callbac
- }
-
- void BaseCapturerPipeWire::CaptureFrame() {
- if (portal_init_failed_) {
- callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
- return;
- }
-
-+ rtc::CritScope lock(&current_frame_lock_);
- if (!current_frame_) {
- callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
- return;
- }
-
- DesktopSize frame_size = desktop_size_;
- if (video_metadata_use_) {
- frame_size = video_size_;
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
-@@ -79,16 +79,17 @@ class BaseCapturerPipeWire : public Desk
- guint sources_request_signal_id_ = 0;
- guint start_request_signal_id_ = 0;
-
- bool video_metadata_use_ = false;
- DesktopSize video_size_;
- DesktopSize desktop_size_ = {};
- DesktopCaptureOptions options_ = {};
-
-+ rtc::CriticalSection current_frame_lock_;
- std::unique_ptr<uint8_t[]> current_frame_;
- Callback* callback_ = nullptr;
-
- bool portal_init_failed_ = false;
-
- void InitPortal();
- void InitPipeWire();
-
-
diff --git a/mozilla-1680505.patch b/mozilla-1680505.patch
deleted file mode 100644
index dba9b7c..0000000
--- a/mozilla-1680505.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-diff --git a/widget/GfxInfoX11.cpp b/widget/GfxInfoX11.cpp
---- a/widget/GfxInfoX11.cpp
-+++ b/widget/GfxInfoX11.cpp
-@@ -705,6 +705,14 @@
- DRIVER_GREATER_THAN_OR_EQUAL, V(18, 0, 0, 0),
- "FEATURE_ROLLOUT_INTEL_GNOME_X11_MESA", "Mesa 18.0.0.0");
-
-+ APPEND_TO_DRIVER_BLOCKLIST_EXT(
-+ OperatingSystem::Linux, ScreenSizeStatus::SmallAndMedium,
-+ BatteryStatus::All, DesktopEnvironment::GNOME, WindowProtocol::Wayland,
-+ DriverVendor::MesaAll, DeviceFamily::IntelRolloutWebRender,
-+ nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
-+ DRIVER_GREATER_THAN_OR_EQUAL, V(18, 0, 0, 0),
-+ "FEATURE_ROLLOUT_INTEL_GNOME_WAYLAND_MESA", "Mesa 18.0.0.0");
-+
- // ATI Mesa baseline, chosen arbitrarily.
- APPEND_TO_DRIVER_BLOCKLIST_EXT(
- OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
-@@ -713,6 +721,14 @@
- nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL,
- V(18, 0, 0, 0), "FEATURE_ROLLOUT_ATI_GNOME_X11_MESA", "Mesa 18.0.0.0");
-
-+ APPEND_TO_DRIVER_BLOCKLIST_EXT(
-+ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
-+ DesktopEnvironment::GNOME, WindowProtocol::Wayland,
-+ DriverVendor::MesaAll, DeviceFamily::AtiRolloutWebRender,
-+ nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
-+ DRIVER_GREATER_THAN_OR_EQUAL, V(18, 0, 0, 0),
-+ "FEATURE_ROLLOUT_ATI_GNOME_WAYLAND_MESA", "Mesa 18.0.0.0");
-+
- #ifdef EARLY_BETA_OR_EARLIER
- // Intel Mesa baseline, chosen arbitrarily.
- APPEND_TO_DRIVER_BLOCKLIST_EXT(
-
diff --git a/mozilla-1687931.patch b/mozilla-1687931.patch
new file mode 100644
index 0000000..91f7e9c
--- /dev/null
+++ b/mozilla-1687931.patch
@@ -0,0 +1,28 @@
+changeset: 565888:91903b2fd4ab
+tag: tip
+parent: 565886:1a895ef04f9f
+user: stransky <stransky@redhat.com>
+date: Thu Jan 21 12:27:43 2021 +0100
+files: widget/gtk/nsWindow.cpp
+description:
+Bug 1687931 [Wayland] Don't cache monitor scale factor, r?jhorak
+
+Differential Revision: https://phabricator.services.mozilla.com/D102590
+
+
+diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
+--- a/widget/gtk/nsWindow.cpp
++++ b/widget/gtk/nsWindow.cpp
+@@ -7714,10 +7714,10 @@ gint nsWindow::GdkScaleFactor() {
+ (gint(*)(GdkWindow*))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
+ if (sGdkWindowGetScaleFactorPtr && scaledGdkWindow) {
+ mWindowScaleFactor = (*sGdkWindowGetScaleFactorPtr)(scaledGdkWindow);
++ mWindowScaleFactorChanged = false;
+ } else {
+ mWindowScaleFactor = ScreenHelperGTK::GetGTKMonitorScaleFactor();
+ }
+- mWindowScaleFactorChanged = false;
+
+ return mWindowScaleFactor;
+ }
+
diff --git a/pgo.patch b/pgo.patch
index f6b4953..12b8940 100644
--- a/pgo.patch
+++ b/pgo.patch
@@ -1,7 +1,7 @@
-diff -up firefox-84.0/build/moz.configure/lto-pgo.configure.pgo firefox-84.0/build/moz.configure/lto-pgo.configure
---- firefox-84.0/build/moz.configure/lto-pgo.configure.pgo 2020-12-10 15:55:41.932635998 +0100
-+++ firefox-84.0/build/moz.configure/lto-pgo.configure 2020-12-10 16:01:24.674052547 +0100
-@@ -228,13 +228,13 @@ def lto(value, c_compiler, ld64_known_go
+diff -up firefox-85.0/build/moz.configure/lto-pgo.configure.pgo firefox-85.0/build/moz.configure/lto-pgo.configure
+--- firefox-85.0/build/moz.configure/lto-pgo.configure.pgo 2021-01-18 19:29:32.000000000 +0100
++++ firefox-85.0/build/moz.configure/lto-pgo.configure 2021-01-21 10:23:59.499111297 +0100
+@@ -240,13 +240,13 @@ def lto(
cflags.append("-flto")
ldflags.append("-flto")
else:
@@ -18,18 +18,9 @@ diff -up firefox-84.0/build/moz.configure/lto-pgo.configure.pgo firefox-84.0/bui
# With clang-cl, -flto can only be used with -c or -fuse-ld=lld.
# AC_TRY_LINKs during configure don't have -c, so pass -fuse-ld=lld.
cflags.append("-fuse-ld=lld")
-@@ -268,7 +268,7 @@ def lto(value, c_compiler, ld64_known_go
- if len(value) and value[0].lower() == "full":
- cflags.append("-flto")
- else:
-- cflags.append("-flto=thin")
-+ cflags.append("-flto")
- cflags.append("-flifetime-dse=1")
-
- ldflags.append("-flto=%s" % num_cores)
-diff -up firefox-84.0/build/pgo/profileserver.py.pgo firefox-84.0/build/pgo/profileserver.py
---- firefox-84.0/build/pgo/profileserver.py.pgo 2020-12-07 23:32:58.000000000 +0100
-+++ firefox-84.0/build/pgo/profileserver.py 2020-12-10 16:05:16.278668657 +0100
+diff -up firefox-85.0/build/pgo/profileserver.py.pgo firefox-85.0/build/pgo/profileserver.py
+--- firefox-85.0/build/pgo/profileserver.py.pgo 2021-01-18 19:29:32.000000000 +0100
++++ firefox-85.0/build/pgo/profileserver.py 2021-01-21 10:23:59.499111297 +0100
@@ -11,7 +11,7 @@ import glob
import subprocess
@@ -76,9 +67,9 @@ diff -up firefox-84.0/build/pgo/profileserver.py.pgo firefox-84.0/build/pgo/prof
llvm_profdata = env.get("LLVM_PROFDATA")
if llvm_profdata:
profraw_files = glob.glob("*.profraw")
-diff -up firefox-84.0/build/unix/mozconfig.unix.pgo firefox-84.0/build/unix/mozconfig.unix
---- firefox-84.0/build/unix/mozconfig.unix.pgo 2020-12-07 23:32:58.000000000 +0100
-+++ firefox-84.0/build/unix/mozconfig.unix 2020-12-10 15:55:41.933636031 +0100
+diff -up firefox-85.0/build/unix/mozconfig.unix.pgo firefox-85.0/build/unix/mozconfig.unix
+--- firefox-85.0/build/unix/mozconfig.unix.pgo 2021-01-18 19:29:32.000000000 +0100
++++ firefox-85.0/build/unix/mozconfig.unix 2021-01-21 10:23:59.499111297 +0100
@@ -6,6 +6,15 @@ if [ -n "$FORCE_GCC" ]; then
CC="$MOZ_FETCHES_DIR/gcc/bin/gcc"
CXX="$MOZ_FETCHES_DIR/gcc/bin/g++"
@@ -95,34 +86,19 @@ diff -up firefox-84.0/build/unix/mozconfig.unix.pgo firefox-84.0/build/unix/mozc
# We want to make sure we use binutils and other binaries in the tooltool
# package.
mk_add_options "export PATH=$MOZ_FETCHES_DIR/gcc/bin:$PATH"
-diff -up firefox-84.0/extensions/spellcheck/src/moz.build.pgo firefox-84.0/extensions/spellcheck/src/moz.build
---- firefox-84.0/extensions/spellcheck/src/moz.build.pgo 2020-12-10 15:55:41.933636031 +0100
-+++ firefox-84.0/extensions/spellcheck/src/moz.build 2020-12-10 16:16:05.897011122 +0100
+diff -up firefox-85.0/extensions/spellcheck/src/moz.build.pgo firefox-85.0/extensions/spellcheck/src/moz.build
+--- firefox-85.0/extensions/spellcheck/src/moz.build.pgo 2021-01-18 19:29:38.000000000 +0100
++++ firefox-85.0/extensions/spellcheck/src/moz.build 2021-01-21 10:23:59.499111297 +0100
@@ -31,3 +31,5 @@ EXPORTS.mozilla += [
if CONFIG["CC_TYPE"] in ("clang", "gcc"):
CXXFLAGS += ["-Wno-error=shadow"]
+
+CXXFLAGS += ['-fno-devirtualize']
-diff -up firefox-84.0/python/mozbuild/mozbuild/build_commands.py.pgo firefox-84.0/python/mozbuild/mozbuild/build_commands.py
---- firefox-84.0/python/mozbuild/mozbuild/build_commands.py.pgo 2020-12-10 15:55:41.933636031 +0100
-+++ firefox-84.0/python/mozbuild/mozbuild/build_commands.py 2020-12-10 16:14:30.017272529 +0100
-@@ -126,9 +126,8 @@ class Build(MachCommandBase):
- return status
-
- pgo_env = os.environ.copy()
-- pgo_env["LLVM_PROFDATA"] = instr.config_environment.substs.get(
-- "LLVM_PROFDATA"
-- )
-+ if instr.config_environment.substs.get('CC_TYPE') != 'gcc':
-+ pgo_env["LLVM_PROFDATA"] = instr.config_environment.substs.get("LLVM_PROFDATA")
- pgo_env["JARLOG_FILE"] = mozpath.join(orig_topobjdir, "jarlog/en-US.log")
- pgo_cmd = [
- instr.virtualenv_manager.python_path,
-diff -up firefox-84.0/toolkit/components/terminator/nsTerminator.cpp.pgo firefox-84.0/toolkit/components/terminator/nsTerminator.cpp
---- firefox-84.0/toolkit/components/terminator/nsTerminator.cpp.pgo 2020-12-07 23:33:08.000000000 +0100
-+++ firefox-84.0/toolkit/components/terminator/nsTerminator.cpp 2020-12-10 15:55:41.933636031 +0100
-@@ -418,6 +418,11 @@ void nsTerminator::StartWatchdog() {
+diff -up firefox-85.0/toolkit/components/terminator/nsTerminator.cpp.pgo firefox-85.0/toolkit/components/terminator/nsTerminator.cpp
+--- firefox-85.0/toolkit/components/terminator/nsTerminator.cpp.pgo 2021-01-18 19:31:16.000000000 +0100
++++ firefox-85.0/toolkit/components/terminator/nsTerminator.cpp 2021-01-21 10:23:59.500111327 +0100
+@@ -430,6 +430,11 @@ void nsTerminator::StartWatchdog() {
}
#endif
diff --git a/pw1.patch b/pw1.patch
deleted file mode 100644
index 1f88545..0000000
--- a/pw1.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-
-# HG changeset patch
-# User stransky <stransky@redhat.com>
-# Date 1604562416 0
-# Node ID 1c126b520042591194e88618ae11a6adc1da9a08
-# Parent 6e2e4f0e4a95b0cae777dda9369a9e9bf49a51b1
-Bug 1672987 Use PipeWire when Wayland display is actually used, r=dminor
-
-Right now PipeWire is enabled when Wayland session is used regardless of an active Gtk backend (X11/Wayland).
-Let's use PipeWire only when Wayland Gtk backend is used and disable it for X11 one to avoid possible regressions.
-
-Differential Revision: https://phabricator.services.mozilla.com/D94588
-
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc
-@@ -8,16 +8,21 @@
- * be found in the AUTHORS file in the root of the source tree.
- */
-
- #include "modules/desktop_capture/desktop_capturer.h"
-
- #include "modules/desktop_capture/desktop_capture_options.h"
- #include "modules/desktop_capture/desktop_capturer_differ_wrapper.h"
-
-+#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
-+#include <gtk/gtk.h>
-+#include <gtk/gtkx.h>
-+#endif
-+
- namespace webrtc {
-
- DesktopCapturer::~DesktopCapturer() = default;
-
- void DesktopCapturer::SetSharedMemoryFactory(
- std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {}
-
- void DesktopCapturer::SetExcludedWindow(WindowId window) {}
-@@ -67,21 +72,37 @@ std::unique_ptr<DesktopCapturer> Desktop
- if (capturer && options.detect_updated_region()) {
- capturer.reset(new DesktopCapturerDifferWrapper(std::move(capturer)));
- }
-
- return capturer;
- }
-
- #if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
--bool DesktopCapturer::IsRunningUnderWayland() {
-+// Return true if Firefox is actually running with Wayland backend.
-+static bool IsWaylandDisplayUsed() {
-+ const auto display = gdk_display_get_default();
-+ if (display == nullptr) {
-+ // We're running in headless mode.
-+ return false;
-+ }
-+ return !GDK_IS_X11_DISPLAY(display);
-+}
-+
-+// Return true if Firefox is actually running on Wayland enabled session.
-+// It means some screensharing capabilities may be limited.
-+static bool IsWaylandSessionUsed() {
- const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
- if (!xdg_session_type || strncmp(xdg_session_type, "wayland", 7) != 0)
- return false;
-
- if (!(getenv("WAYLAND_DISPLAY")))
- return false;
-
- return true;
- }
-+
-+bool DesktopCapturer::IsRunningUnderWayland() {
-+ return IsWaylandSessionUsed() ? IsWaylandDisplayUsed() : false;
-+}
- #endif // defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
-
- } // namespace webrtc
-
diff --git a/pw2.patch b/pw2.patch
deleted file mode 100644
index 9390460..0000000
--- a/pw2.patch
+++ /dev/null
@@ -1,901 +0,0 @@
-
-# HG changeset patch
-# User stransky <stransky@redhat.com>
-# Date 1604560111 0
-# Node ID 998e6d0b24e4a560e5664aaef87307e9c069ad87
-# Parent 1c126b520042591194e88618ae11a6adc1da9a08
-Bug 1672947 Update PipeWire WebRTC code to PipeWire 0.3, r=ng
-
-Differential Revision: https://phabricator.services.mozilla.com/D94589
-
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
-@@ -10,18 +10,20 @@
-
- #include "modules/desktop_capture/linux/base_capturer_pipewire.h"
-
- #include <gio/gunixfdlist.h>
- #include <glib-object.h>
-
- #include <spa/param/format-utils.h>
- #include <spa/param/props.h>
--#include <spa/param/video/raw-utils.h>
--#include <spa/support/type-map.h>
-+
-+#include <sys/mman.h>
-+#include <sys/ioctl.h>
-+#include <sys/syscall.h>
-
- #include <memory>
- #include <utility>
-
- #include "modules/desktop_capture/desktop_capture_options.h"
- #include "modules/desktop_capture/desktop_capturer.h"
- #include "rtc_base/checks.h"
- #include "rtc_base/logging.h"
-@@ -32,180 +34,166 @@ const char kDesktopBusName[] = "org.free
- const char kDesktopObjectPath[] = "/org/freedesktop/portal/desktop";
- const char kDesktopRequestObjectPath[] =
- "/org/freedesktop/portal/desktop/request";
- const char kSessionInterfaceName[] = "org.freedesktop.portal.Session";
- const char kRequestInterfaceName[] = "org.freedesktop.portal.Request";
- const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
-
- // static
--void BaseCapturerPipeWire::OnStateChanged(void* data,
-- pw_remote_state old_state,
-- pw_remote_state state,
-- const char* error_message) {
-- BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
-- RTC_DCHECK(that);
-+struct dma_buf_sync {
-+ uint64_t flags;
-+};
-+#define DMA_BUF_SYNC_READ (1 << 0)
-+#define DMA_BUF_SYNC_START (0 << 2)
-+#define DMA_BUF_SYNC_END (1 << 2)
-+#define DMA_BUF_BASE 'b'
-+#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
-
-- switch (state) {
-- case PW_REMOTE_STATE_ERROR:
-- RTC_LOG(LS_ERROR) << "PipeWire remote state error: " << error_message;
-+static void SyncDmaBuf(int fd, uint64_t start_or_end) {
-+ struct dma_buf_sync sync = { 0 };
-+
-+ sync.flags = start_or_end | DMA_BUF_SYNC_READ;
-+
-+ while(true) {
-+ int ret;
-+ ret = ioctl (fd, DMA_BUF_IOCTL_SYNC, &sync);
-+ if (ret == -1 && errno == EINTR) {
-+ continue;
-+ } else if (ret == -1) {
-+ RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: " << g_strerror(errno);
- break;
-- case PW_REMOTE_STATE_CONNECTED:
-- RTC_LOG(LS_INFO) << "PipeWire remote state: connected.";
-- that->CreateReceivingStream();
-+ } else {
- break;
-- case PW_REMOTE_STATE_CONNECTING:
-- RTC_LOG(LS_INFO) << "PipeWire remote state: connecting.";
-- break;
-- case PW_REMOTE_STATE_UNCONNECTED:
-- RTC_LOG(LS_INFO) << "PipeWire remote state: unconnected.";
-- break;
-+ }
- }
- }
-
- // static
-+void BaseCapturerPipeWire::OnCoreError(void *data,
-+ uint32_t id,
-+ int seq,
-+ int res,
-+ const char *message) {
-+ RTC_LOG(LS_ERROR) << "core error: " << message;
-+}
-+
-+// static
- void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
- pw_stream_state old_state,
- pw_stream_state state,
- const char* error_message) {
- BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
- RTC_DCHECK(that);
-
- switch (state) {
- case PW_STREAM_STATE_ERROR:
- RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
- break;
-- case PW_STREAM_STATE_CONFIGURE:
-- pw_stream_set_active(that->pw_stream_, true);
-- break;
-+ case PW_STREAM_STATE_PAUSED:
-+ case PW_STREAM_STATE_STREAMING:
- case PW_STREAM_STATE_UNCONNECTED:
- case PW_STREAM_STATE_CONNECTING:
-- case PW_STREAM_STATE_READY:
-- case PW_STREAM_STATE_PAUSED:
-- case PW_STREAM_STATE_STREAMING:
- break;
- }
- }
-
- // static
--void BaseCapturerPipeWire::OnStreamFormatChanged(void* data,
-- const struct spa_pod* format) {
-+void BaseCapturerPipeWire::OnStreamParamChanged(void *data, uint32_t id,
-+ const struct spa_pod *format) {
- BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
- RTC_DCHECK(that);
-
-- RTC_LOG(LS_INFO) << "PipeWire stream format changed.";
-+ RTC_LOG(LS_INFO) << "PipeWire stream param changed.";
-
-- if (!format) {
-- pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr,
-- /*n_params=*/0);
-+ if (!format || id != SPA_PARAM_Format) {
- return;
- }
-
-- that->spa_video_format_ = new spa_video_info_raw();
-- spa_format_video_raw_parse(format, that->spa_video_format_,
-- &that->pw_type_->format_video);
-+ spa_format_video_raw_parse(format, &that->spa_video_format_);
-
-- auto width = that->spa_video_format_->size.width;
-- auto height = that->spa_video_format_->size.height;
-+ auto width = that->spa_video_format_.size.width;
-+ auto height = that->spa_video_format_.size.height;
- auto stride = SPA_ROUND_UP_N(width * kBytesPerPixel, 4);
- auto size = height * stride;
-
-+ that->desktop_size_ = DesktopSize(width, height);
-+
- uint8_t buffer[1024] = {};
- auto builder = spa_pod_builder{buffer, sizeof(buffer)};
-
- // Setup buffers and meta header for new format.
-- const struct spa_pod* params[2];
-- params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
-- &builder,
-- // id to enumerate buffer requirements
-- that->pw_core_type_->param.idBuffers,
-- that->pw_core_type_->param_buffers.Buffers,
-- // Size: specified as integer (i) and set to specified size
-- ":", that->pw_core_type_->param_buffers.size, "i", size,
-- // Stride: specified as integer (i) and set to specified stride
-- ":", that->pw_core_type_->param_buffers.stride, "i", stride,
-- // Buffers: specifies how many buffers we want to deal with, set as
-- // integer (i) where preferred number is 8, then allowed number is defined
-- // as range (r) from min and max values and it is undecided (u) to allow
-- // negotiation
-- ":", that->pw_core_type_->param_buffers.buffers, "iru", 8,
-- SPA_POD_PROP_MIN_MAX(1, 32),
-- // Align: memory alignment of the buffer, set as integer (i) to specified
-- // value
-- ":", that->pw_core_type_->param_buffers.align, "i", 16));
-- params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
-- &builder,
-- // id to enumerate supported metadata
-- that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta,
-- // Type: specified as id or enum (I)
-- ":", that->pw_core_type_->param_meta.type, "I",
-- that->pw_core_type_->meta.Header,
-- // Size: size of the metadata, specified as integer (i)
-- ":", that->pw_core_type_->param_meta.size, "i",
-- sizeof(struct spa_meta_header)));
--
-- pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2);
-+ const struct spa_pod* params[3];
-+ params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
-+ SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
-+ SPA_PARAM_BUFFERS_size, SPA_POD_Int(size),
-+ SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride),
-+ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, 32)));
-+ params[1] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
-+ SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
-+ SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
-+ SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))));
-+ params[2] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
-+ SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
-+ SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoCrop),
-+ SPA_PARAM_META_size, SPA_POD_Int (sizeof(struct spa_meta_region))));
-+ pw_stream_update_params(that->pw_stream_, params, 3);
- }
-
- // static
- void BaseCapturerPipeWire::OnStreamProcess(void* data) {
- BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
- RTC_DCHECK(that);
-
-- pw_buffer* buf = nullptr;
-+ struct pw_buffer *next_buffer;
-+ struct pw_buffer *buffer = nullptr;
-
-- if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) {
-+ next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
-+ while (next_buffer) {
-+ buffer = next_buffer;
-+ next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
-+
-+ if (next_buffer) {
-+ pw_stream_queue_buffer (that->pw_stream_, buffer);
-+ }
-+ }
-+
-+ if (!buffer) {
- return;
- }
-
-- that->HandleBuffer(buf);
-+ that->HandleBuffer(buffer);
-
-- pw_stream_queue_buffer(that->pw_stream_, buf);
-+ pw_stream_queue_buffer(that->pw_stream_, buffer);
- }
-
- BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type)
- : capture_source_type_(source_type) {}
-
- BaseCapturerPipeWire::~BaseCapturerPipeWire() {
- if (pw_main_loop_) {
- pw_thread_loop_stop(pw_main_loop_);
- }
-
-- if (pw_type_) {
-- delete pw_type_;
-- }
--
-- if (spa_video_format_) {
-- delete spa_video_format_;
-- }
--
- if (pw_stream_) {
- pw_stream_destroy(pw_stream_);
- }
-
-- if (pw_remote_) {
-- pw_remote_destroy(pw_remote_);
-+ if (pw_core_) {
-+ pw_core_disconnect(pw_core_);
- }
-
-- if (pw_core_) {
-- pw_core_destroy(pw_core_);
-+ if (pw_context_) {
-+ pw_context_destroy(pw_context_);
- }
-
- if (pw_main_loop_) {
- pw_thread_loop_destroy(pw_main_loop_);
- }
-
-- if (pw_loop_) {
-- pw_loop_destroy(pw_loop_);
-- }
--
-- if (current_frame_) {
-- free(current_frame_);
-- }
--
- if (start_request_signal_id_) {
- g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
- }
- if (sources_request_signal_id_) {
- g_dbus_connection_signal_unsubscribe(connection_,
- sources_request_signal_id_);
- }
- if (session_request_signal_id_) {
-@@ -245,143 +233,210 @@ void BaseCapturerPipeWire::InitPortal()
- kDesktopBusName, kDesktopObjectPath, kScreenCastInterfaceName,
- /*cancellable=*/nullptr,
- reinterpret_cast<GAsyncReadyCallback>(OnProxyRequested), this);
- }
-
- void BaseCapturerPipeWire::InitPipeWire() {
- pw_init(/*argc=*/nullptr, /*argc=*/nullptr);
-
-- pw_loop_ = pw_loop_new(/*properties=*/nullptr);
-- pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop");
-+ pw_main_loop_ = pw_thread_loop_new("pipewire-main-loop", nullptr);
-+ pw_context_ = pw_context_new(pw_thread_loop_get_loop(pw_main_loop_), nullptr, 0);
-+ if (!pw_context_) {
-+ RTC_LOG(LS_ERROR) << "Failed to create PipeWire context";
-+ return;
-+ }
-
-- pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr);
-- pw_core_type_ = pw_core_get_type(pw_core_);
-- pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0);
--
-- InitPipeWireTypes();
-+ pw_core_ = pw_context_connect(pw_context_, nullptr, 0);
-+ if (!pw_core_) {
-+ RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context";
-+ return;
-+ }
-
- // Initialize event handlers, remote end and stream-related.
-- pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS;
-- pw_remote_events_.state_changed = &OnStateChanged;
-+ pw_core_events_.version = PW_VERSION_CORE_EVENTS;
-+ pw_core_events_.error = &OnCoreError;
-
- pw_stream_events_.version = PW_VERSION_STREAM_EVENTS;
- pw_stream_events_.state_changed = &OnStreamStateChanged;
-- pw_stream_events_.format_changed = &OnStreamFormatChanged;
-+ pw_stream_events_.param_changed = &OnStreamParamChanged;
- pw_stream_events_.process = &OnStreamProcess;
-
-- pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_,
-- this);
-- pw_remote_connect_fd(pw_remote_, pw_fd_);
-+ pw_core_add_listener(pw_core_, &spa_core_listener_, &pw_core_events_, this);
-+
-+ pw_stream_ = CreateReceivingStream();
-+ if (!pw_stream_) {
-+ RTC_LOG(LS_ERROR) << "Failed to create PipeWire stream";
-+ return;
-+ }
-
- if (pw_thread_loop_start(pw_main_loop_) < 0) {
- RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop";
- portal_init_failed_ = true;
- }
- }
-
--void BaseCapturerPipeWire::InitPipeWireTypes() {
-- spa_type_map* map = pw_core_type_->map;
-- pw_type_ = new PipeWireType();
--
-- spa_type_media_type_map(map, &pw_type_->media_type);
-- spa_type_media_subtype_map(map, &pw_type_->media_subtype);
-- spa_type_format_video_map(map, &pw_type_->format_video);
-- spa_type_video_format_map(map, &pw_type_->video_format);
--}
-+pw_stream* BaseCapturerPipeWire::CreateReceivingStream() {
-+ spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
-+ spa_rectangle pwMaxScreenBounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
-
--void BaseCapturerPipeWire::CreateReceivingStream() {
-- spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
-- spa_rectangle pwScreenBounds =
-- spa_rectangle{static_cast<uint32_t>(desktop_size_.width()),
-- static_cast<uint32_t>(desktop_size_.height())};
-+ auto stream = pw_stream_new(pw_core_, "webrtc-pipewire-stream", nullptr);
-
-- spa_fraction pwFrameRateMin = spa_fraction{0, 1};
-- spa_fraction pwFrameRateMax = spa_fraction{60, 1};
--
-- pw_properties* reuseProps = pw_properties_new("pipewire.client.reuse", "1",
-- /*end of varargs*/ nullptr);
-- pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
-+ if (!stream) {
-+ RTC_LOG(LS_ERROR) << "Could not create receiving stream.";
-+ return nullptr;
-+ }
-
- uint8_t buffer[1024] = {};
-- const spa_pod* params[1];
-- spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
-- params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
-- &builder,
-- // id to enumerate formats
-- pw_core_type_->param.idEnumFormat, pw_core_type_->spa_format, "I",
-- pw_type_->media_type.video, "I", pw_type_->media_subtype.raw,
-- // Video format: specified as id or enum (I), preferred format is BGRx,
-- // then allowed formats are enumerated (e) and the format is undecided (u)
-- // to allow negotiation
-- ":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx,
-- SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx,
-- pw_type_->video_format.BGRx),
-- // Video size: specified as rectangle (R), preferred size is specified as
-- // first parameter, then allowed size is defined as range (r) from min and
-- // max values and the format is undecided (u) to allow negotiation
-- ":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2,
-- &pwMinScreenBounds, &pwScreenBounds,
-- // Frame rate: specified as fraction (F) and set to minimum frame rate
-- // value
-- ":", pw_type_->format_video.framerate, "F", &pwFrameRateMin,
-- // Max frame rate: specified as fraction (F), preferred frame rate is set
-- // to maximum value, then allowed frame rate is defined as range (r) from
-- // min and max values and it is undecided (u) to allow negotiation
-- ":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2,
-- &pwFrameRateMin, &pwFrameRateMax));
-+ const spa_pod* params[2];
-+ spa_pod_builder builder = SPA_POD_BUILDER_INIT(buffer, sizeof (buffer));
-
-- pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_,
-- this);
-- pw_stream_flags flags = static_cast<pw_stream_flags>(
-- PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE |
-- PW_STREAM_FLAG_MAP_BUFFERS);
-- if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
-- flags, params,
-- /*n_params=*/1) != 0) {
-+ params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
-+ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
-+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
-+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
-+ SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, SPA_VIDEO_FORMAT_RGBA,
-+ SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_BGRA),
-+ SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds,
-+ &pwMinScreenBounds,
-+ &pwMaxScreenBounds),
-+ 0));
-+ pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_, this);
-+
-+ if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_,
-+ PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) {
- RTC_LOG(LS_ERROR) << "Could not connect receiving stream.";
- portal_init_failed_ = true;
-- return;
-+ }
-+
-+ return stream;
-+}
-+
-+static void SpaBufferUnmap(unsigned char *map, int map_size, bool IsDMABuf, int fd) {
-+ if (map) {
-+ if (IsDMABuf) {
-+ SyncDmaBuf(fd, DMA_BUF_SYNC_END);
-+ }
-+ munmap(map, map_size);
- }
- }
-
- void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
- spa_buffer* spaBuffer = buffer->buffer;
-- void* src = nullptr;
-+ uint8_t *map = nullptr;
-+ uint8_t* src = nullptr;
-
-- if (!(src = spaBuffer->datas[0].data)) {
-+ if (spaBuffer->datas[0].chunk->size == 0) {
-+ RTC_LOG(LS_ERROR) << "Failed to get video stream: Zero size.";
- return;
- }
-
-- uint32_t maxSize = spaBuffer->datas[0].maxsize;
-- int32_t srcStride = spaBuffer->datas[0].chunk->stride;
-- if (srcStride != (desktop_size_.width() * kBytesPerPixel)) {
-- RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
-- << srcStride
-- << " != " << (desktop_size_.width() * kBytesPerPixel);
-- portal_init_failed_ = true;
-+ switch (spaBuffer->datas[0].type) {
-+ case SPA_DATA_MemFd:
-+ case SPA_DATA_DmaBuf:
-+ map = static_cast<uint8_t*>(mmap(
-+ nullptr, spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
-+ PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0));
-+ if (map == MAP_FAILED) {
-+ RTC_LOG(LS_ERROR) << "Failed to mmap memory: " << std::strerror(errno);
-+ return;
-+ }
-+ if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
-+ SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_START);
-+ }
-+ src = SPA_MEMBER(map, spaBuffer->datas[0].mapoffset, uint8_t);
-+ break;
-+ case SPA_DATA_MemPtr:
-+ map = nullptr;
-+ src = static_cast<uint8_t*>(spaBuffer->datas[0].data);
-+ break;
-+ default:
-+ return;
-+ }
-+
-+ if (!src) {
-+ RTC_LOG(LS_ERROR) << "Failed to get video stream: Wrong data after mmap()";
-+ SpaBufferUnmap(map,
-+ spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
-+ spaBuffer->datas[0].type == SPA_DATA_DmaBuf, spaBuffer->datas[0].fd);
-+ return;
-+ }
-+
-+ struct spa_meta_region* video_metadata =
-+ static_cast<struct spa_meta_region*>(
-+ spa_buffer_find_meta_data(spaBuffer, SPA_META_VideoCrop, sizeof(*video_metadata)));
-+
-+ // Video size from metada is bigger than an actual video stream size.
-+ // The metadata are wrong or we should up-scale te video...in both cases
-+ // just quit now.
-+ if (video_metadata &&
-+ (video_metadata->region.size.width > (uint32_t)desktop_size_.width() ||
-+ video_metadata->region.size.height > (uint32_t)desktop_size_.height())) {
-+ RTC_LOG(LS_ERROR) << "Stream metadata sizes are wrong!";
-+ SpaBufferUnmap(map,
-+ spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
-+ spaBuffer->datas[0].type == SPA_DATA_DmaBuf, spaBuffer->datas[0].fd);
- return;
- }
-
-- if (!current_frame_) {
-- current_frame_ = static_cast<uint8_t*>(malloc(maxSize));
-+ // Use video metada when video size from metadata is set and smaller than
-+ // video stream size, so we need to adjust it.
-+ video_metadata_use_ = (video_metadata &&
-+ video_metadata->region.size.width != 0 &&
-+ video_metadata->region.size.height != 0 &&
-+ (video_metadata->region.size.width < (uint32_t)desktop_size_.width() ||
-+ video_metadata->region.size.height < (uint32_t)desktop_size_.height()));
-+
-+ DesktopSize video_size_prev = video_size_;
-+ if (video_metadata_use_) {
-+ video_size_ = DesktopSize(video_metadata->region.size.width,
-+ video_metadata->region.size.height);
-+ } else {
-+ video_size_ = desktop_size_;
- }
-- RTC_DCHECK(current_frame_ != nullptr);
-+
-+ if (!current_frame_ ||
-+ (video_metadata_use_ && !video_size_.equals(video_size_prev))) {
-+ current_frame_ =
-+ std::make_unique<uint8_t[]>
-+ (video_size_.width() * video_size_.height() * kBytesPerPixel);
-+ }
-+
-+ const int32_t dstStride = video_size_.width() * kBytesPerPixel;
-+ const int32_t srcStride = spaBuffer->datas[0].chunk->stride;
-
-- // If both sides decided to go with the RGBx format we need to convert it to
-- // BGRx to match color format expected by WebRTC.
-- if (spa_video_format_->format == pw_type_->video_format.RGBx) {
-- uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize));
-- std::memcpy(tempFrame, src, maxSize);
-- ConvertRGBxToBGRx(tempFrame, maxSize);
-- std::memcpy(current_frame_, tempFrame, maxSize);
-- free(tempFrame);
-- } else {
-- std::memcpy(current_frame_, src, maxSize);
-+ // Adjust source content based on metadata video position
-+ if (video_metadata_use_ &&
-+ (video_metadata->region.position.y + video_size_.height() <= desktop_size_.height())) {
-+ src += srcStride * video_metadata->region.position.y;
- }
-+ const int xOffset =
-+ video_metadata_use_ &&
-+ (video_metadata->region.position.x + video_size_.width() <= desktop_size_.width())
-+ ? video_metadata->region.position.x * kBytesPerPixel
-+ : 0;
-+
-+ uint8_t* dst = current_frame_.get();
-+ for (int i = 0; i < video_size_.height(); ++i) {
-+ // Adjust source content based on crop video position if needed
-+ src += xOffset;
-+ std::memcpy(dst, src, dstStride);
-+ // If both sides decided to go with the RGBx format we need to convert it to
-+ // BGRx to match color format expected by WebRTC.
-+ if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx ||
-+ spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) {
-+ ConvertRGBxToBGRx(dst, dstStride);
-+ }
-+ src += srcStride - xOffset;
-+ dst += dstStride;
-+ }
-+
-+ SpaBufferUnmap(map,
-+ spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
-+ spaBuffer->datas[0].type == SPA_DATA_DmaBuf, spaBuffer->datas[0].fd);
- }
-
- void BaseCapturerPipeWire::ConvertRGBxToBGRx(uint8_t* frame, uint32_t size) {
- // Change color format for KDE KWin which uses RGBx and not BGRx
- for (uint32_t i = 0; i < size; i += 4) {
- uint8_t tempR = frame[i];
- uint8_t tempB = frame[i + 2];
- frame[i] = tempB;
-@@ -713,27 +768,22 @@ void BaseCapturerPipeWire::OnStartReques
- // Array of PipeWire streams. See
- // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml
- // documentation for <method name="Start">.
- if (g_variant_lookup(response_data, "streams", "a(ua{sv})", &iter)) {
- GVariant* variant;
-
- while (g_variant_iter_next(iter, "@(ua{sv})", &variant)) {
- guint32 stream_id;
-- gint32 width;
-- gint32 height;
- GVariant* options;
-
- g_variant_get(variant, "(u@a{sv})", &stream_id, &options);
- RTC_DCHECK(options != nullptr);
-
-- g_variant_lookup(options, "size", "(ii)", &width, &height);
--
-- that->desktop_size_.set(width, height);
--
-+ that->pw_stream_node_id_ = stream_id;
- g_variant_unref(options);
- g_variant_unref(variant);
- }
- }
- g_variant_iter_free(iter);
- g_variant_unref(response_data);
-
- that->OpenPipeWireRemote();
-@@ -808,20 +858,25 @@ void BaseCapturerPipeWire::CaptureFrame(
- return;
- }
-
- if (!current_frame_) {
- callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
- return;
- }
-
-- std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_));
-+ DesktopSize frame_size = desktop_size_;
-+ if (video_metadata_use_) {
-+ frame_size = video_size_;
-+ }
-+
-+ std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size));
- result->CopyPixelsFrom(
-- current_frame_, (desktop_size_.width() * kBytesPerPixel),
-- DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height()));
-+ current_frame_.get(), (frame_size.width() * kBytesPerPixel),
-+ DesktopRect::MakeWH(frame_size.width(), frame_size.height()));
- if (!result) {
- callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
- return;
- }
- callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
- }
-
- bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) {
-@@ -832,9 +887,27 @@ bool BaseCapturerPipeWire::GetSourceList
- return true;
- }
-
- bool BaseCapturerPipeWire::SelectSource(SourceId id) {
- // Screen selection is handled by the xdg-desktop-portal.
- return true;
- }
-
-+// static
-+std::unique_ptr<DesktopCapturer>
-+BaseCapturerPipeWire::CreateRawScreenCapturer(
-+ const DesktopCaptureOptions& options) {
-+ std::unique_ptr<BaseCapturerPipeWire> capturer =
-+ std::make_unique<BaseCapturerPipeWire>(BaseCapturerPipeWire::CaptureSourceType::kAny);
-+ return std::move(capturer);}
-+
-+// static
-+std::unique_ptr<DesktopCapturer>
-+BaseCapturerPipeWire::CreateRawWindowCapturer(
-+ const DesktopCaptureOptions& options) {
-+
-+ std::unique_ptr<BaseCapturerPipeWire> capturer =
-+ std::make_unique<BaseCapturerPipeWire>(BaseCapturerPipeWire::CaptureSourceType::kAny);
-+ return std::move(capturer);
-+}
-+
- } // namespace webrtc
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
-@@ -17,99 +17,102 @@
- #include <spa/param/video/format-utils.h>
-
- #include "modules/desktop_capture/desktop_capture_options.h"
- #include "modules/desktop_capture/desktop_capturer.h"
- #include "rtc_base/constructormagic.h"
-
- namespace webrtc {
-
--class PipeWireType {
-- public:
-- spa_type_media_type media_type;
-- spa_type_media_subtype media_subtype;
-- spa_type_format_video format_video;
-- spa_type_video_format video_format;
--};
--
- class BaseCapturerPipeWire : public DesktopCapturer {
- public:
-- enum CaptureSourceType { Screen = 1, Window };
-+ enum CaptureSourceType : uint32_t {
-+ kScreen = 0b01,
-+ kWindow = 0b10,
-+ kAny = 0b11
-+ };
-
- explicit BaseCapturerPipeWire(CaptureSourceType source_type);
- ~BaseCapturerPipeWire() override;
-
- // DesktopCapturer interface.
- void Start(Callback* delegate) override;
- void CaptureFrame() override;
- bool GetSourceList(SourceList* sources) override;
- bool SelectSource(SourceId id) override;
-
-+ static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(
-+ const DesktopCaptureOptions& options);
-+
-+ static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
-+ const DesktopCaptureOptions& options);
-+
- private:
- // PipeWire types -->
-+ pw_context* pw_context_ = nullptr;
- pw_core* pw_core_ = nullptr;
-- pw_type* pw_core_type_ = nullptr;
- pw_stream* pw_stream_ = nullptr;
-- pw_remote* pw_remote_ = nullptr;
-- pw_loop* pw_loop_ = nullptr;
- pw_thread_loop* pw_main_loop_ = nullptr;
-- PipeWireType* pw_type_ = nullptr;
-
-+ spa_hook spa_core_listener_ = {};
- spa_hook spa_stream_listener_ = {};
-- spa_hook spa_remote_listener_ = {};
-
-+ pw_core_events pw_core_events_ = {};
- pw_stream_events pw_stream_events_ = {};
-- pw_remote_events pw_remote_events_ = {};
-
-- spa_video_info_raw* spa_video_format_ = nullptr;
-+ struct spa_video_info_raw spa_video_format_;
-
-+ guint32 pw_stream_node_id_ = 0;
- gint32 pw_fd_ = -1;
-
- CaptureSourceType capture_source_type_ =
-- BaseCapturerPipeWire::CaptureSourceType::Screen;
-+ BaseCapturerPipeWire::CaptureSourceType::kAny;
-
- // <-- end of PipeWire types
-
- GDBusConnection* connection_ = nullptr;
- GDBusProxy* proxy_ = nullptr;
- gchar* portal_handle_ = nullptr;
- gchar* session_handle_ = nullptr;
- gchar* sources_handle_ = nullptr;
- gchar* start_handle_ = nullptr;
- guint session_request_signal_id_ = 0;
- guint sources_request_signal_id_ = 0;
- guint start_request_signal_id_ = 0;
-
-+ bool video_metadata_use_ = false;
-+ DesktopSize video_size_;
- DesktopSize desktop_size_ = {};
- DesktopCaptureOptions options_ = {};
-
-- uint8_t* current_frame_ = nullptr;
-+ std::unique_ptr<uint8_t[]> current_frame_;
- Callback* callback_ = nullptr;
-
- bool portal_init_failed_ = false;
-
- void InitPortal();
- void InitPipeWire();
-- void InitPipeWireTypes();
-
-- void CreateReceivingStream();
-+ pw_stream* CreateReceivingStream();
- void HandleBuffer(pw_buffer* buffer);
-
- void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
-
-- static void OnStateChanged(void* data,
-- pw_remote_state old_state,
-- pw_remote_state state,
-- const char* error);
-+ static void OnCoreError(void *data,
-+ uint32_t id,
-+ int seq,
-+ int res,
-+ const char *message);
-+ static void OnStreamParamChanged(void *data,
-+ uint32_t id,
-+ const struct spa_pod *format);
- static void OnStreamStateChanged(void* data,
- pw_stream_state old_state,
- pw_stream_state state,
- const char* error_message);
--
-- static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
- static void OnStreamProcess(void* data);
- static void OnNewBuffer(void* data, uint32_t id);
-
- guint SetupRequestResponseSignal(const gchar* object_path,
- GDBusSignalCallback callback);
-
- static void OnProxyRequested(GObject* object,
- GAsyncResult* result,
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc
-@@ -10,17 +10,17 @@
-
- #include "modules/desktop_capture/linux/screen_capturer_pipewire.h"
-
- #include <memory>
-
- namespace webrtc {
-
- ScreenCapturerPipeWire::ScreenCapturerPipeWire()
-- : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {}
-+ : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::kScreen) {}
- ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {}
-
- // static
- std::unique_ptr<DesktopCapturer>
- ScreenCapturerPipeWire::CreateRawScreenCapturer(
- const DesktopCaptureOptions& options) {
- return std::make_unique<ScreenCapturerPipeWire>();
- }
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc
-@@ -10,17 +10,17 @@
-
- #include "modules/desktop_capture/linux/window_capturer_pipewire.h"
-
- #include <memory>
-
- namespace webrtc {
-
- WindowCapturerPipeWire::WindowCapturerPipeWire()
-- : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {}
-+ : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::kWindow) {}
- WindowCapturerPipeWire::~WindowCapturerPipeWire() {}
-
- // static
- std::unique_ptr<DesktopCapturer>
- WindowCapturerPipeWire::CreateRawWindowCapturer(
- const DesktopCaptureOptions& options) {
- return std::make_unique<WindowCapturerPipeWire>();
- }
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc
-@@ -21,17 +21,17 @@
-
- namespace webrtc {
-
- // static
- std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
- const DesktopCaptureOptions& options) {
- #if defined(WEBRTC_USE_PIPEWIRE)
- if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
-- return ScreenCapturerPipeWire::CreateRawScreenCapturer(options);
-+ return BaseCapturerPipeWire::CreateRawScreenCapturer(options);
- }
- #endif // defined(WEBRTC_USE_PIPEWIRE)
-
- #if defined(USE_X11)
- return ScreenCapturerX11::CreateRawScreenCapturer(options);
- #endif // defined(USE_X11)
-
- return nullptr;
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc
-@@ -21,17 +21,17 @@
-
- namespace webrtc {
-
- // static
- std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
- const DesktopCaptureOptions& options) {
- #if defined(WEBRTC_USE_PIPEWIRE)
- if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
-- return WindowCapturerPipeWire::CreateRawWindowCapturer(options);
-+ return BaseCapturerPipeWire::CreateRawWindowCapturer(options);
- }
- #endif // defined(WEBRTC_USE_PIPEWIRE)
-
- #if defined(USE_X11)
- return WindowCapturerX11::CreateRawWindowCapturer(options);
- #endif // defined(USE_X11)
-
- return nullptr;
-
diff --git a/pw3.patch b/pw3.patch
deleted file mode 100644
index 82d451e..0000000
--- a/pw3.patch
+++ /dev/null
@@ -1,183 +0,0 @@
-
-# HG changeset patch
-# User stransky <stransky@redhat.com>
-# Date 1604562423 0
-# Node ID d1a244822d7811575f5bb3cd024f8f324275aec2
-# Parent 998e6d0b24e4a560e5664aaef87307e9c069ad87
-Bug 1672989 Build PipeWire as a part of default builds, r=dminor
-
-Differential Revision: https://phabricator.services.mozilla.com/D94590
-
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn b/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn
-@@ -152,22 +152,17 @@ if (rtc_include_tests) {
- "../../rtc_base:rtc_base_approved",
- "../../test:test_support",
- ]
- }
- }
-
- if (is_linux) {
- if (rtc_use_pipewire) {
-- pkg_config("pipewire") {
-- packages = [ "libpipewire-0.2" ]
--
-- defines = [ "WEBRTC_USE_PIPEWIRE" ]
-- }
--
-+ defines = [ "WEBRTC_USE_PIPEWIRE" ]
- pkg_config("gio") {
- packages = [
- "gio-2.0",
- "gio-unix-2.0",
- ]
- }
- }
- }
-@@ -326,16 +321,17 @@ rtc_static_library("desktop_capture_gene
- } else {
- sources += [
- "fake_desktop_capturer.cc",
- "fake_desktop_capturer.h",
- ]
- }
-
- if (use_x11 || rtc_use_pipewire) {
-+ include_dirs = [ "/third_party/libwebrtc/third_party/pipewire" ]
- sources += [
- "mouse_cursor_monitor_linux.cc",
- "screen_capturer_linux.cc",
- "window_capturer_linux.cc",
- ]
- }
-
- if (use_x11) {
-@@ -367,16 +363,17 @@ rtc_static_library("desktop_capture_gene
- "linux/desktop_device_info_x11.h",
- "linux/shared_x_util.cc",
- "linux/shared_x_util.h",
- ]
- }
- }
-
- if (rtc_use_pipewire) {
-+ include_dirs = [ "/third_party/libwebrtc/third_party/pipewire" ]
- sources += [
- "linux/base_capturer_pipewire.cc",
- "linux/base_capturer_pipewire.h",
- "linux/screen_capturer_pipewire.cc",
- "linux/screen_capturer_pipewire.h",
- "linux/window_capturer_pipewire.cc",
- "linux/window_capturer_pipewire.h",
- ]
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build
-@@ -20,17 +20,18 @@ DEFINES["WEBRTC_RESTRICT_LOGGING"] = Tru
- FINAL_LIBRARY = "webrtc"
-
-
- LOCAL_INCLUDES += [
- "!/ipc/ipdl/_ipdlheaders",
- "/ipc/chromium/src",
- "/ipc/glue",
- "/media/libyuv/libyuv/include/",
-- "/third_party/libwebrtc/webrtc/"
-+ "/third_party/libwebrtc/webrtc/",
-+ "/third_party/pipewire"
- ]
-
- UNIFIED_SOURCES += [
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/capture_result_desktop_capturer_wrapper.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/cropped_desktop_frame.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/cropping_window_capturer.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc",
-@@ -156,16 +157,17 @@ if CONFIG["OS_TARGET"] == "FreeBSD":
-
- if CONFIG["OS_TARGET"] == "Linux":
-
- DEFINES["USE_NSS_CERTS"] = "1"
- DEFINES["USE_X11"] = "1"
- DEFINES["WEBRTC_LINUX"] = True
- DEFINES["WEBRTC_POSIX"] = True
- DEFINES["_FILE_OFFSET_BITS"] = "64"
-+ DEFINES["WEBRTC_USE_PIPEWIRE"] = "1"
-
- OS_LIBS += [
- "rt",
- "X11",
- "X11-xcb",
- "xcb",
- "Xcomposite",
- "Xcursor",
-@@ -188,16 +190,24 @@ if CONFIG["OS_TARGET"] == "Linux":
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/x_atom_cache.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/x_error_trap.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/x_server_pixel_buffer.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc"
- ]
-
-+ CXXFLAGS += CONFIG['TK_CFLAGS']
-+
-+ UNIFIED_SOURCES += [
-+ "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc",
-+ "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc",
-+ "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc"
-+ ]
-+
- if CONFIG["OS_TARGET"] == "NetBSD":
-
- DEFINES["USE_X11"] = "1"
- DEFINES["WEBRTC_BSD"] = True
- DEFINES["WEBRTC_POSIX"] = True
- DEFINES["_FILE_OFFSET_BITS"] = "64"
-
- OS_LIBS += [
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h
-@@ -136,15 +136,15 @@ class DesktopCaptureOptions {
- #if defined(USE_X11)
- bool use_update_notifications_ = false;
- #else
- bool use_update_notifications_ = true;
- #endif
- bool disable_effects_ = true;
- bool detect_updated_region_ = false;
- #if defined(WEBRTC_USE_PIPEWIRE)
-- bool allow_pipewire_ = false;
-+ bool allow_pipewire_ = true;
- #endif
- };
-
- } // namespace webrtc
-
- #endif // MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_
-diff --git a/third_party/libwebrtc/webrtc/moz.build b/third_party/libwebrtc/webrtc/moz.build
---- a/third_party/libwebrtc/webrtc/moz.build
-+++ b/third_party/libwebrtc/webrtc/moz.build
-@@ -181,16 +181,19 @@ if CONFIG["OS_TARGET"] == "Linux":
-
- DIRS += [
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_gn",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/primitives_gn",
- "/third_party/libwebrtc/webrtc/modules/video_capture/video_capture_internal_impl_gn",
- "/third_party/libwebrtc/webrtc/system_wrappers/cpu_features_linux_gn"
- ]
-+ DIRS += [
-+ "/third_party/pipewire/libpipewire"
-+ ]
-
- if CONFIG["OS_TARGET"] == "NetBSD":
-
- DIRS += [
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_gn",
- "/third_party/libwebrtc/webrtc/modules/desktop_capture/primitives_gn",
- "/third_party/libwebrtc/webrtc/modules/video_capture/video_capture_internal_impl_gn"
-
diff --git a/pw4.patch b/pw4.patch
deleted file mode 100644
index 03bda37..0000000
--- a/pw4.patch
+++ /dev/null
@@ -1,18928 +0,0 @@
-
-# HG changeset patch
-# User stransky <stransky@redhat.com>
-# Date 1604009732 0
-# Node ID e5e706b532041baa3ef46420c9bf10629b0cb3ba
-# Parent 7dad14e6de1a80a5c6a194df8a7b16504fb3d617
-Bug 1672945 Ship PipeWire 0.3 headers and library wrapper to build PW support out of the box, r=dminor
-
-- Ship PipeWire 0.3 headers at third_party/pipewire/pipewire
-- Ship SPA 0.2 headers at third_party/pipewire/spa
-- Ship PipeWire library wrapper at third_party/pipewire/libpipewire
-
-Differential Revision: https://phabricator.services.mozilla.com/D94580
-
-diff --git a/third_party/pipewire/README b/third_party/pipewire/README
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/README
-@@ -0,0 +1,4 @@
-+Libpipewire is a pipewire library wrapper needed to build and run Firefox with
-+Pipewire support on Linux (https://pipewire.org/).
-+
-+Pipewire directory stores headers of pipewire-0.2 and spa-0.2 needed for build only.
-diff --git a/third_party/pipewire/libpipewire/moz.build b/third_party/pipewire/libpipewire/moz.build
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/libpipewire/moz.build
-@@ -0,0 +1,15 @@
-+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-+# vim: set filetype=python:
-+# This Source Code Form is subject to the terms of the Mozilla Public
-+# License, v. 2.0. If a copy of the MPL was not distributed with this
-+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-+
-+SOURCES += [
-+ 'mozpipewire.cpp',
-+]
-+
-+CXXFLAGS += CONFIG['TK_CFLAGS']
-+
-+LOCAL_INCLUDES += ['/third_party/pipewire']
-+
-+FINAL_LIBRARY = 'xul'
-diff --git a/third_party/pipewire/libpipewire/mozpipewire.cpp b/third_party/pipewire/libpipewire/mozpipewire.cpp
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/libpipewire/mozpipewire.cpp
-@@ -0,0 +1,312 @@
-+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-+/* vim:expandtab:shiftwidth=4:tabstop=4:
-+ */
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+#include <glib.h>
-+#include "mozilla/Types.h"
-+#include "prlink.h"
-+
-+#include <pipewire/pipewire.h>
-+
-+#define GET_FUNC(func, lib) \
-+ func##_fn = \
-+ (decltype(func##_fn))PR_FindFunctionSymbol(lib, #func) \
-+
-+#define IS_FUNC_LOADED(func) \
-+ (func != nullptr) \
-+
-+struct GUnixFDList;
-+
-+extern "C" gint
-+g_unix_fd_list_get(struct GUnixFDList *list,
-+ gint index_,
-+ GError **error)
-+{
-+ static PRLibrary* gioLib = nullptr;
-+ static bool gioInitialized = false;
-+ static gint (*g_unix_fd_list_get_fn)(struct GUnixFDList *list,
-+ gint index_, GError **error) = nullptr;
-+
-+ if (!gioInitialized) {
-+ gioInitialized = true;
-+ gioLib = PR_LoadLibrary("libgio-2.0.so.0");
-+ if (!gioLib) {
-+ return -1;
-+ }
-+ GET_FUNC(g_unix_fd_list_get, gioLib);
-+ }
-+
-+ if (!g_unix_fd_list_get_fn) {
-+ return -1;
-+ }
-+
-+ return g_unix_fd_list_get_fn(list, index_, error);
-+}
-+
-+static struct pw_core * (*pw_context_connect_fn)(struct pw_context *context,
-+ struct pw_properties *properties,
-+ size_t user_data_size);
-+static void (*pw_context_destroy_fn)(struct pw_context *context);
-+struct pw_context * (*pw_context_new_fn)(struct pw_loop *main_loop,
-+ struct pw_properties *props,
-+ size_t user_data_size);
-+static int (*pw_core_disconnect_fn)(struct pw_core *core);
-+static void (*pw_init_fn)(int *argc, char **argv[]);
-+static void (*pw_stream_add_listener_fn)(struct pw_stream *stream,
-+ struct spa_hook *listener,
-+ const struct pw_stream_events *events,
-+ void *data);
-+static int (*pw_stream_connect_fn)(struct pw_stream *stream,
-+ enum pw_direction direction,
-+ uint32_t target_id,
-+ enum pw_stream_flags flags,
-+ const struct spa_pod **params,
-+ uint32_t n_params);
-+static struct pw_buffer* (*pw_stream_dequeue_buffer_fn)(struct pw_stream *stream);
-+static void (*pw_stream_destroy_fn)(struct pw_stream *stream);
-+static struct pw_stream* (*pw_stream_new_fn)(struct pw_core *core,
-+ const char *name,
-+ struct pw_properties *props);
-+static int (*pw_stream_queue_buffer_fn)(struct pw_stream *stream,
-+ struct pw_buffer *buffer);
-+static int (*pw_stream_update_params_fn)(struct pw_stream *stream,
-+ const struct spa_pod **params,
-+ uint32_t n_params);
-+static void (*pw_thread_loop_destroy_fn)(struct pw_thread_loop *loop);
-+static struct pw_loop* (*pw_thread_loop_get_loop_fn)(struct pw_thread_loop *loop);
-+static struct pw_thread_loop* (*pw_thread_loop_new_fn)(const char *name,
-+ const struct spa_dict *props);
-+static int (*pw_thread_loop_start_fn)(struct pw_thread_loop *loop);
-+static void (*pw_thread_loop_stop_fn)(struct pw_thread_loop *loop);
-+
-+bool IsPwLibraryLoaded() {
-+ static bool isLoaded =
-+ (IS_FUNC_LOADED(pw_context_connect_fn) &&
-+ IS_FUNC_LOADED(pw_context_destroy_fn) &&
-+ IS_FUNC_LOADED(pw_context_new_fn) &&
-+ IS_FUNC_LOADED(pw_core_disconnect_fn) &&
-+ IS_FUNC_LOADED(pw_init_fn) &&
-+ IS_FUNC_LOADED(pw_stream_add_listener_fn) &&
-+ IS_FUNC_LOADED(pw_stream_connect_fn) &&
-+ IS_FUNC_LOADED(pw_stream_dequeue_buffer_fn) &&
-+ IS_FUNC_LOADED(pw_stream_destroy_fn) &&
-+ IS_FUNC_LOADED(pw_stream_new_fn) &&
-+ IS_FUNC_LOADED(pw_stream_queue_buffer_fn) &&
-+ IS_FUNC_LOADED(pw_stream_update_params_fn) &&
-+ IS_FUNC_LOADED(pw_thread_loop_destroy_fn) &&
-+ IS_FUNC_LOADED(pw_thread_loop_get_loop_fn) &&
-+ IS_FUNC_LOADED(pw_thread_loop_new_fn) &&
-+ IS_FUNC_LOADED(pw_thread_loop_start_fn) &&
-+ IS_FUNC_LOADED(pw_thread_loop_stop_fn));
-+
-+ return isLoaded;
-+}
-+
-+bool LoadPWLibrary() {
-+ static PRLibrary* pwLib = nullptr;
-+ static bool pwInitialized = false;
-+
-+ //TODO Thread safe
-+ if (!pwInitialized) {
-+ pwInitialized = true;
-+ pwLib = PR_LoadLibrary("libpipewire-0.3.so.0");
-+ if (!pwLib) {
-+ return false;
-+ }
-+
-+ GET_FUNC(pw_context_connect, pwLib);
-+ GET_FUNC(pw_context_destroy, pwLib);
-+ GET_FUNC(pw_context_new, pwLib);
-+ GET_FUNC(pw_core_disconnect, pwLib);
-+ GET_FUNC(pw_init, pwLib);
-+ GET_FUNC(pw_stream_add_listener, pwLib);
-+ GET_FUNC(pw_stream_connect, pwLib);
-+ GET_FUNC(pw_stream_dequeue_buffer, pwLib);
-+ GET_FUNC(pw_stream_destroy, pwLib);
-+ GET_FUNC(pw_stream_new, pwLib);
-+ GET_FUNC(pw_stream_queue_buffer, pwLib);
-+ GET_FUNC(pw_stream_update_params, pwLib);
-+ GET_FUNC(pw_thread_loop_destroy, pwLib);
-+ GET_FUNC(pw_thread_loop_get_loop, pwLib);
-+ GET_FUNC(pw_thread_loop_new, pwLib);
-+ GET_FUNC(pw_thread_loop_start, pwLib);
-+ GET_FUNC(pw_thread_loop_stop, pwLib);
-+ }
-+
-+ return IsPwLibraryLoaded();
-+}
-+
-+struct pw_core *
-+pw_context_connect(struct pw_context *context,
-+ struct pw_properties *properties,
-+ size_t user_data_size)
-+{
-+ if (!LoadPWLibrary()) {
-+ return nullptr;
-+ }
-+ return pw_context_connect_fn(context, properties, user_data_size);
-+}
-+
-+void
-+pw_context_destroy(struct pw_context *context)
-+{
-+ if (!LoadPWLibrary()) {
-+ return;
-+ }
-+ pw_context_destroy_fn(context);
-+}
-+
-+struct pw_context *
-+pw_context_new(struct pw_loop *main_loop,
-+ struct pw_properties *props,
-+ size_t user_data_size)
-+{
-+ if (!LoadPWLibrary()) {
-+ return nullptr;
-+ }
-+ return pw_context_new_fn(main_loop, props, user_data_size);
-+}
-+
-+int
-+pw_core_disconnect(struct pw_core *core)
-+{
-+ if (!LoadPWLibrary()) {
-+ return 0;
-+ }
-+ return pw_core_disconnect_fn(core);
-+}
-+
-+void
-+pw_init(int *argc, char **argv[])
-+{
-+ if (!LoadPWLibrary()) {
-+ return;
-+ }
-+ return pw_init_fn(argc, argv);
-+}
-+
-+void
-+pw_stream_add_listener(struct pw_stream *stream,
-+ struct spa_hook *listener,
-+ const struct pw_stream_events *events,
-+ void *data)
-+{
-+ if (!LoadPWLibrary()) {
-+ return;
-+ }
-+ return pw_stream_add_listener_fn(stream, listener, events, data);
-+}
-+
-+int
-+pw_stream_connect(struct pw_stream *stream,
-+ enum pw_direction direction,
-+ uint32_t target_id,
-+ enum pw_stream_flags flags,
-+ const struct spa_pod **params,
-+ uint32_t n_params)
-+{
-+ if (!LoadPWLibrary()) {
-+ return 0;
-+ }
-+ return pw_stream_connect_fn(stream, direction, target_id, flags,
-+ params, n_params);
-+}
-+
-+struct pw_buffer *
-+pw_stream_dequeue_buffer(struct pw_stream *stream)
-+{
-+ if (!LoadPWLibrary()) {
-+ return nullptr;
-+ }
-+ return pw_stream_dequeue_buffer_fn(stream);
-+}
-+
-+void
-+pw_stream_destroy(struct pw_stream *stream)
-+{
-+ if (!LoadPWLibrary()) {
-+ return;
-+ }
-+ return pw_stream_destroy_fn(stream);
-+}
-+
-+struct pw_stream *
-+pw_stream_new(struct pw_core *core,
-+ const char *name,
-+ struct pw_properties *props)
-+{
-+ if (!LoadPWLibrary()) {
-+ return nullptr;
-+ }
-+ return pw_stream_new_fn(core, name, props);
-+}
-+
-+int
-+pw_stream_queue_buffer(struct pw_stream *stream,
-+ struct pw_buffer *buffer)
-+{
-+ if (!LoadPWLibrary()) {
-+ return 0;
-+ }
-+ return pw_stream_queue_buffer_fn(stream, buffer);
-+}
-+
-+int
-+pw_stream_update_params(struct pw_stream *stream,
-+ const struct spa_pod **params,
-+ uint32_t n_params)
-+{
-+ if (!LoadPWLibrary()) {
-+ return 0;
-+ }
-+ return pw_stream_update_params_fn(stream, params, n_params);
-+}
-+
-+void
-+pw_thread_loop_destroy(struct pw_thread_loop *loop)
-+{
-+ if (!LoadPWLibrary()) {
-+ return;
-+ }
-+ return pw_thread_loop_destroy_fn(loop);
-+}
-+
-+struct pw_loop *
-+pw_thread_loop_get_loop(struct pw_thread_loop *loop)
-+{
-+ if (!LoadPWLibrary()) {
-+ return nullptr;
-+ }
-+ return pw_thread_loop_get_loop_fn(loop);
-+}
-+
-+struct pw_thread_loop *
-+pw_thread_loop_new(const char *name,
-+ const struct spa_dict *props)
-+{
-+ if (!LoadPWLibrary()) {
-+ return nullptr;
-+ }
-+ return pw_thread_loop_new_fn(name, props);
-+}
-+
-+int
-+pw_thread_loop_start(struct pw_thread_loop *loop)
-+{
-+ if (!LoadPWLibrary()) {
-+ return 0;
-+ }
-+ return pw_thread_loop_start_fn(loop);
-+}
-+
-+void
-+pw_thread_loop_stop(struct pw_thread_loop *loop)
-+{
-+ if (!LoadPWLibrary()) {
-+ return;
-+ }
-+ return pw_thread_loop_stop_fn(loop);
-+}
-diff --git a/third_party/pipewire/pipewire/array.h b/third_party/pipewire/pipewire/array.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/array.h
-@@ -0,0 +1,165 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_ARRAY_H
-+#define PIPEWIRE_ARRAY_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <errno.h>
-+
-+#include <spa/utils/defs.h>
-+
-+/** \class pw_array
-+ *
-+ * \brief An array object
-+ *
-+ * The array is a dynamically resizable data structure that can
-+ * hold items of the same size.
-+ */
-+struct pw_array {
-+ void *data; /**< pointer to array data */
-+ size_t size; /**< length of array in bytes */
-+ size_t alloc; /**< number of allocated memory in \a data */
-+ size_t extend; /**< number of bytes to extend with */
-+};
-+
-+#define PW_ARRAY_INIT(extend) (struct pw_array) { NULL, 0, 0, extend }
-+
-+#define pw_array_get_len_s(a,s) ((a)->size / (s))
-+#define pw_array_get_unchecked_s(a,idx,s,t) SPA_MEMBER((a)->data,(idx)*(s),t)
-+#define pw_array_check_index_s(a,idx,s) ((idx) < pw_array_get_len_s(a,s))
-+
-+/** Get the number of items of type \a t in array \memberof pw_array */
-+#define pw_array_get_len(a,t) pw_array_get_len_s(a,sizeof(t))
-+/** Get the item with index \a idx and type \a t from array \memberof pw_array */
-+#define pw_array_get_unchecked(a,idx,t) pw_array_get_unchecked_s(a,idx,sizeof(t),t)
-+/** Check if an item with index \a idx and type \a t exist in array \memberof pw_array */
-+#define pw_array_check_index(a,idx,t) pw_array_check_index_s(a,idx,sizeof(t))
-+
-+#define pw_array_first(a) ((a)->data)
-+#define pw_array_end(a) SPA_MEMBER((a)->data, (a)->size, void)
-+#define pw_array_check(a,p) (SPA_MEMBER(p,sizeof(*p),void) <= pw_array_end(a))
-+
-+#define pw_array_for_each(pos, array) \
-+ for (pos = (__typeof__(pos)) pw_array_first(array); \
-+ pw_array_check(array, pos); \
-+ (pos)++)
-+
-+#define pw_array_consume(pos, array) \
-+ for (pos = (__typeof__(pos)) pw_array_first(array); \
-+ pw_array_check(array, pos); \
-+ pos = (__typeof__(pos)) pw_array_first(array))
-+
-+#define pw_array_remove(a,p) \
-+({ \
-+ (a)->size -= sizeof(*(p)); \
-+ memmove(p, SPA_MEMBER((p), sizeof(*(p)), void), \
-+ SPA_PTRDIFF(pw_array_end(a),(p))); \
-+})
-+
-+/** Initialize the array with given extend \memberof pw_array */
-+static inline void pw_array_init(struct pw_array *arr, size_t extend)
-+{
-+ arr->data = NULL;
-+ arr->size = arr->alloc = 0;
-+ arr->extend = extend;
-+}
-+
-+/** Clear the array */
-+static inline void pw_array_clear(struct pw_array *arr)
-+{
-+ free(arr->data);
-+}
-+
-+/** Reset the array */
-+static inline void pw_array_reset(struct pw_array *arr)
-+{
-+ arr->size = 0;
-+}
-+
-+/** Make sure \a size bytes can be added to the array \memberof pw_array */
-+static inline int pw_array_ensure_size(struct pw_array *arr, size_t size)
-+{
-+ size_t alloc, need;
-+
-+ alloc = arr->alloc;
-+ need = arr->size + size;
-+
-+ if (SPA_UNLIKELY(alloc < need)) {
-+ void *data;
-+ alloc = SPA_MAX(alloc, arr->extend);
-+ while (alloc < need)
-+ alloc *= 2;
-+ if (SPA_UNLIKELY((data = realloc(arr->data, alloc)) == NULL))
-+ return -errno;
-+ arr->data = data;
-+ arr->alloc = alloc;
-+ }
-+ return 0;
-+}
-+
-+/** Add \a ref size bytes to \a arr. A pointer to memory that can
-+ * hold at least \a size bytes is returned \memberof pw_array */
-+static inline void *pw_array_add(struct pw_array *arr, size_t size)
-+{
-+ void *p;
-+
-+ if (pw_array_ensure_size(arr, size) < 0)
-+ return NULL;
-+
-+ p = SPA_MEMBER(arr->data, arr->size, void);
-+ arr->size += size;
-+
-+ return p;
-+}
-+
-+/** Add \a ref size bytes to \a arr. When there is not enough memory to
-+ * hold \a size bytes, NULL is returned \memberof pw_array */
-+static inline void *pw_array_add_fixed(struct pw_array *arr, size_t size)
-+{
-+ void *p;
-+
-+ if (SPA_UNLIKELY(arr->alloc < arr->size + size)) {
-+ errno = ENOSPC;
-+ return NULL;
-+ }
-+
-+ p = SPA_MEMBER(arr->data, arr->size, void);
-+ arr->size += size;
-+
-+ return p;
-+}
-+
-+/** Add a pointer to array \memberof pw_array */
-+#define pw_array_add_ptr(a,p) \
-+ *((void**) pw_array_add(a, sizeof(void*))) = (p)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_ARRAY_H */
-diff --git a/third_party/pipewire/pipewire/buffers.h b/third_party/pipewire/pipewire/buffers.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/buffers.h
-@@ -0,0 +1,60 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_BUFFERS_H
-+#define PIPEWIRE_BUFFERS_H
-+
-+#include <spa/node/node.h>
-+
-+#include <pipewire/context.h>
-+#include <pipewire/mem.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define PW_BUFFERS_FLAG_NONE 0
-+#define PW_BUFFERS_FLAG_NO_MEM (1<<0) /**< don't allocate buffer memory */
-+#define PW_BUFFERS_FLAG_SHARED (1<<1) /**< buffers can be shared */
-+#define PW_BUFFERS_FLAG_DYNAMIC (1<<2) /**< buffers have dynamic data */
-+
-+struct pw_buffers {
-+ struct pw_memblock *mem; /**< allocated buffer memory */
-+ struct spa_buffer **buffers; /**< port buffers */
-+ uint32_t n_buffers; /**< number of port buffers */
-+ uint32_t flags; /**< flags */
-+};
-+
-+int pw_buffers_negotiate(struct pw_context *context, uint32_t flags,
-+ struct spa_node *outnode, uint32_t out_port_id,
-+ struct spa_node *innode, uint32_t in_port_id,
-+ struct pw_buffers *result);
-+
-+void pw_buffers_clear(struct pw_buffers *buffers);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_BUFFERS_H */
-diff --git a/third_party/pipewire/pipewire/client.h b/third_party/pipewire/pipewire/client.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/client.h
-@@ -0,0 +1,171 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_CLIENT_H
-+#define PIPEWIRE_CLIENT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/param/param.h>
-+
-+#include <pipewire/proxy.h>
-+#include <pipewire/permission.h>
-+
-+#define PW_TYPE_INTERFACE_Client PW_TYPE_INFO_INTERFACE_BASE "Client"
-+
-+#define PW_VERSION_CLIENT 3
-+struct pw_client;
-+
-+/* default ID of the current client after connect */
-+#define PW_ID_CLIENT 1
-+
-+/** The client information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_client_info {
-+ uint32_t id; /**< id of the global */
-+#define PW_CLIENT_CHANGE_MASK_PROPS (1 << 0)
-+#define PW_CLIENT_CHANGE_MASK_ALL ((1 << 1)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ struct spa_dict *props; /**< extra properties */
-+};
-+
-+/** Update and existing \ref pw_client_info with \a update \memberof pw_introspect */
-+struct pw_client_info *
-+pw_client_info_update(struct pw_client_info *info,
-+ const struct pw_client_info *update);
-+
-+/** Free a \ref pw_client_info \memberof pw_introspect */
-+void pw_client_info_free(struct pw_client_info *info);
-+
-+
-+#define PW_CLIENT_EVENT_INFO 0
-+#define PW_CLIENT_EVENT_PERMISSIONS 1
-+#define PW_CLIENT_EVENT_NUM 2
-+
-+/** Client events */
-+struct pw_client_events {
-+#define PW_VERSION_CLIENT_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify client info
-+ *
-+ * \param info info about the client
-+ */
-+ void (*info) (void *object, const struct pw_client_info *info);
-+ /**
-+ * Notify a client permission
-+ *
-+ * Event emitted as a result of the get_permissions method.
-+ *
-+ * \param default_permissions the default permissions
-+ * \param index the index of the first permission entry
-+ * \param n_permissions the number of permissions
-+ * \param permissions the permissions
-+ */
-+ void (*permissions) (void *object,
-+ uint32_t index,
-+ uint32_t n_permissions,
-+ const struct pw_permission *permissions);
-+};
-+
-+
-+#define PW_CLIENT_METHOD_ADD_LISTENER 0
-+#define PW_CLIENT_METHOD_ERROR 1
-+#define PW_CLIENT_METHOD_UPDATE_PROPERTIES 2
-+#define PW_CLIENT_METHOD_GET_PERMISSIONS 3
-+#define PW_CLIENT_METHOD_UPDATE_PERMISSIONS 4
-+#define PW_CLIENT_METHOD_NUM 5
-+
-+/** Client methods */
-+struct pw_client_methods {
-+#define PW_VERSION_CLIENT_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_client_events *events,
-+ void *data);
-+ /**
-+ * Send an error to a client
-+ *
-+ * \param id the global id to report the error on
-+ * \param res an errno style error code
-+ * \param message an error string
-+ */
-+ int (*error) (void *object, uint32_t id, int res, const char *message);
-+ /**
-+ * Update client properties
-+ *
-+ * \param props new properties
-+ */
-+ int (*update_properties) (void *object, const struct spa_dict *props);
-+
-+ /**
-+ * Get client permissions
-+ *
-+ * A permissions event will be emitted with the permissions.
-+ *
-+ * \param index the first index to query, 0 for first
-+ * \param num the maximum number of items to get
-+ */
-+ int (*get_permissions) (void *object, uint32_t index, uint32_t num);
-+ /**
-+ * Manage the permissions of the global objects for this
-+ * client
-+ *
-+ * Update the permissions of the global objects using the
-+ * provided array with permissions
-+ *
-+ * Globals can use the default permissions or can have specific
-+ * permissions assigned to them.
-+ *
-+ * \param n_permissions number of permissions
-+ * \param permissions array of permissions
-+ */
-+ int (*update_permissions) (void *object, uint32_t n_permissions,
-+ const struct pw_permission *permissions);
-+};
-+
-+#define pw_client_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_client_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_client_add_listener(c,...) pw_client_method(c,add_listener,0,__VA_ARGS__)
-+#define pw_client_error(c,...) pw_client_method(c,error,0,__VA_ARGS__)
-+#define pw_client_update_properties(c,...) pw_client_method(c,update_properties,0,__VA_ARGS__)
-+#define pw_client_get_permissions(c,...) pw_client_method(c,get_permissions,0,__VA_ARGS__)
-+#define pw_client_update_permissions(c,...) pw_client_method(c,update_permissions,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_CLIENT_H */
-diff --git a/third_party/pipewire/pipewire/context.h b/third_party/pipewire/pipewire/context.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/context.h
-@@ -0,0 +1,188 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_CONTEXT_H
-+#define PIPEWIRE_CONTEXT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+/** \class pw_context
-+ *
-+ * \brief the PipeWire context
-+ *
-+ * The context object manages all locally available resources. It
-+ * is used by both clients and servers.
-+ *
-+ * The context is used to:
-+ *
-+ * - Load modules and extend the functionality. This includes
-+ * extending the protocol with new object types or creating
-+ * any of the available objects.
-+ *
-+ * - Create implementations of various objects like nodes,
-+ * devices, factories, modules, etc.. This will usually also
-+ * create pw_global objects that can then be shared with
-+ * clients.
-+ *
-+ * - Connect to another PipeWire instance (the main daemon, for
-+ * example) and interact with it (See \subpage page_core_api).
-+ *
-+ * - Export a local implementation of an object to another
-+ * instance.
-+ */
-+struct pw_context;
-+
-+struct pw_global;
-+struct pw_impl_client;
-+
-+#include <pipewire/core.h>
-+#include <pipewire/loop.h>
-+#include <pipewire/properties.h>
-+
-+/** \page page_context_api Core API
-+ *
-+ * \section page_context_overview Overview
-+ *
-+ * \subpage page_context
-+ *
-+ * \subpage page_global
-+ *
-+ * \subpage page_client
-+ *
-+ * \subpage page_resource
-+ *
-+ * \subpage page_node
-+ *
-+ * \subpage page_port
-+ *
-+ * \subpage page_link
-+ */
-+
-+/** \page page_context Context
-+ *
-+ * \section page_context_overview Overview
-+ *
-+ * The context object is an object that manages the state and
-+ * resources of a PipeWire instance.
-+ */
-+
-+/** context events emitted by the context object added with \ref pw_context_add_listener */
-+struct pw_context_events {
-+#define PW_VERSION_CONTEXT_EVENTS 0
-+ uint32_t version;
-+
-+ /** The context is being destroyed */
-+ void (*destroy) (void *data);
-+ /** The context is being freed */
-+ void (*free) (void *data);
-+ /** a new client object is added */
-+ void (*check_access) (void *data, struct pw_impl_client *client);
-+ /** a new global object was added */
-+ void (*global_added) (void *data, struct pw_global *global);
-+ /** a global object was removed */
-+ void (*global_removed) (void *data, struct pw_global *global);
-+};
-+
-+/** Make a new context object for a given main_loop. Ownership of the properties is taken */
-+struct pw_context * pw_context_new(struct pw_loop *main_loop, /**< a main loop to run in */
-+ struct pw_properties *props, /**< extra properties */
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** destroy a context object, all resources except the main_loop will be destroyed */
-+void pw_context_destroy(struct pw_context *context);
-+
-+/** Get the context user data */
-+void *pw_context_get_user_data(struct pw_context *context);
-+
-+/** Add a new event listener to a context */
-+void pw_context_add_listener(struct pw_context *context,
-+ struct spa_hook *listener,
-+ const struct pw_context_events *events,
-+ void *data);
-+
-+/** Get the context properties */
-+const struct pw_properties *pw_context_get_properties(struct pw_context *context);
-+
-+/** Update the context properties */
-+int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict);
-+
-+/** Get the context support objects */
-+const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support);
-+
-+/** get the context main loop */
-+struct pw_loop *pw_context_get_main_loop(struct pw_context *context);
-+
-+/** Iterate the globals of the context. The callback should return
-+ * 0 to fetch the next item, any other value stops the iteration and returns
-+ * the value. When all callbacks return 0, this function returns 0 when all
-+ * globals are iterated. */
-+int pw_context_for_each_global(struct pw_context *context, /**< the context */
-+ int (*callback) (void *data, struct pw_global *global),
-+ void *data);
-+
-+/** Find a context global by id */
-+struct pw_global *pw_context_find_global(struct pw_context *context, /**< the context */
-+ uint32_t id /**< the global id */);
-+
-+/** add a spa library for the given factory_name regex */
-+int pw_context_add_spa_lib(struct pw_context *context, const char *factory_regex, const char *lib);
-+
-+/** find the library name for a spa factory */
-+const char * pw_context_find_spa_lib(struct pw_context *context, const char *factory_name);
-+
-+struct spa_handle *pw_context_load_spa_handle(struct pw_context *context,
-+ const char *factory_name,
-+ const struct spa_dict *info);
-+
-+
-+/** data for registering export functions */
-+struct pw_export_type {
-+ struct spa_list link;
-+ const char *type;
-+ struct pw_proxy * (*func) (struct pw_core *core,
-+ const char *type, const struct spa_dict *props, void *object,
-+ size_t user_data_size);
-+};
-+
-+/** register a type that can be exported on a context_proxy. This is usually used by
-+ * extension modules */
-+int pw_context_register_export_type(struct pw_context *context, struct pw_export_type *type);
-+/** find information about registered export type */
-+const struct pw_export_type *pw_context_find_export_type(struct pw_context *context, const char *type);
-+
-+/** add an object to the context */
-+int pw_context_set_object(struct pw_context *context, const char *type, void *value);
-+/** get an object from the context */
-+void *pw_context_get_object(struct pw_context *context, const char *type);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_CONTEXT_H */
-diff --git a/third_party/pipewire/pipewire/control.h b/third_party/pipewire/pipewire/control.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/control.h
-@@ -0,0 +1,79 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_CONTROL_H
-+#define PIPEWIRE_CONTROL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+/** \page page_control Control
-+ *
-+ * \section page_control_overview Overview
-+ *
-+ * A control can be used to control a port property.
-+ */
-+/** \class pw_control
-+ *
-+ * The control object
-+ */
-+struct pw_control;
-+
-+#include <pipewire/impl.h>
-+
-+/** Port events, use \ref pw_control_add_listener */
-+struct pw_control_events {
-+#define PW_VERSION_CONTROL_EVENTS 0
-+ uint32_t version;
-+
-+ /** The control is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** The control is freed */
-+ void (*free) (void *data);
-+
-+ /** control is linked to another control */
-+ void (*linked) (void *data, struct pw_control *other);
-+ /** control is unlinked from another control */
-+ void (*unlinked) (void *data, struct pw_control *other);
-+
-+};
-+
-+/** Get the control parent port or NULL when not set */
-+struct pw_impl_port *pw_control_get_port(struct pw_control *control);
-+
-+/** Add an event listener on the control */
-+void pw_control_add_listener(struct pw_control *control,
-+ struct spa_hook *listener,
-+ const struct pw_control_events *events,
-+ void *data);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_CONTROL_H */
-diff --git a/third_party/pipewire/pipewire/core.h b/third_party/pipewire/pipewire/core.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/core.h
-@@ -0,0 +1,584 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_CORE_H
-+#define PIPEWIRE_CORE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+#include <errno.h>
-+
-+#include <spa/utils/hook.h>
-+
-+#define PW_TYPE_INTERFACE_Core PW_TYPE_INFO_INTERFACE_BASE "Core"
-+#define PW_TYPE_INTERFACE_Registry PW_TYPE_INFO_INTERFACE_BASE "Registry"
-+
-+#define PW_VERSION_CORE 3
-+struct pw_core;
-+#define PW_VERSION_REGISTRY 3
-+struct pw_registry;
-+
-+/* the default remote name to connect to */
-+#define PW_DEFAULT_REMOTE "pipewire-0"
-+
-+/* default ID for the core object after connect */
-+#define PW_ID_CORE 0
-+
-+/* invalid ID that matches any object when used for permissions */
-+#define PW_ID_ANY (uint32_t)(0xffffffff)
-+
-+/** The core information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_core_info {
-+ uint32_t id; /**< id of the global */
-+ uint32_t cookie; /**< a random cookie for identifying this instance of PipeWire */
-+ const char *user_name; /**< name of the user that started the core */
-+ const char *host_name; /**< name of the machine the core is running on */
-+ const char *version; /**< version of the core */
-+ const char *name; /**< name of the core */
-+#define PW_CORE_CHANGE_MASK_PROPS (1 << 0)
-+#define PW_CORE_CHANGE_MASK_ALL ((1 << 1)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ struct spa_dict *props; /**< extra properties */
-+};
-+
-+#include <pipewire/context.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/proxy.h>
-+
-+/** Update and existing \ref pw_core_info with \a update \memberof pw_introspect */
-+struct pw_core_info *
-+pw_core_info_update(struct pw_core_info *info,
-+ const struct pw_core_info *update);
-+
-+/** Free a \ref pw_core_info \memberof pw_introspect */
-+void pw_core_info_free(struct pw_core_info *info);
-+
-+/**
-+ * \page page_iface_pw_core pw_core
-+ * \section page_iface_pw_core_desc Description
-+ *
-+ * The core global object. This is a special singleton object. It
-+ * is used for internal PipeWire protocol features.
-+ * \section page_iface_pw_core API
-+ */
-+
-+/** Core */
-+
-+#define PW_CORE_EVENT_INFO 0
-+#define PW_CORE_EVENT_DONE 1
-+#define PW_CORE_EVENT_PING 2
-+#define PW_CORE_EVENT_ERROR 3
-+#define PW_CORE_EVENT_REMOVE_ID 4
-+#define PW_CORE_EVENT_BOUND_ID 5
-+#define PW_CORE_EVENT_ADD_MEM 6
-+#define PW_CORE_EVENT_REMOVE_MEM 7
-+#define PW_CORE_EVENT_NUM 8
-+
-+/** \struct pw_core_events
-+ * \brief Core events
-+ * \ingroup pw_core_interface The pw_core interface
-+ */
-+struct pw_core_events {
-+#define PW_VERSION_CORE_EVENTS 0
-+ uint32_t version;
-+
-+ /**
-+ * Notify new core info
-+ *
-+ * This event is emitted when first bound to the core or when the
-+ * hello method is called.
-+ *
-+ * \param info new core info
-+ */
-+ void (*info) (void *object, const struct pw_core_info *info);
-+ /**
-+ * Emit a done event
-+ *
-+ * The done event is emitted as a result of a sync method with the
-+ * same seq number.
-+ *
-+ * \param seq the seq number passed to the sync method call
-+ */
-+ void (*done) (void *object, uint32_t id, int seq);
-+
-+ /** Emit a ping event
-+ *
-+ * The client should reply with a pong reply with the same seq
-+ * number.
-+ */
-+ void (*ping) (void *object, uint32_t id, int seq);
-+
-+ /**
-+ * Fatal error event
-+ *
-+ * The error event is sent out when a fatal (non-recoverable)
-+ * error has occurred. The id argument is the proxy object where
-+ * the error occurred, most often in response to a request to that
-+ * object. The message is a brief description of the error,
-+ * for (debugging) convenience.
-+ *
-+ * This event is usually also emitted on the proxy object with
-+ * \a id.
-+ *
-+ * \param id object where the error occurred
-+ * \param seq the sequence number that generated the error
-+ * \param res error code
-+ * \param message error description
-+ */
-+ void (*error) (void *object, uint32_t id, int seq, int res, const char *message);
-+ /**
-+ * Remove an object ID
-+ *
-+ * This event is used internally by the object ID management
-+ * logic. When a client deletes an object, the server will send
-+ * this event to acknowledge that it has seen the delete request.
-+ * When the client receives this event, it will know that it can
-+ * safely reuse the object ID.
-+ *
-+ * \param id deleted object ID
-+ */
-+ void (*remove_id) (void *object, uint32_t id);
-+
-+ /**
-+ * Notify an object binding
-+ *
-+ * This event is emitted when a local object ID is bound to a
-+ * global ID. It is emitted before the global becomes visible in the
-+ * registry.
-+ *
-+ * \param id bound object ID
-+ * \param global_id the global id bound to
-+ */
-+ void (*bound_id) (void *object, uint32_t id, uint32_t global_id);
-+
-+ /**
-+ * Add memory for a client
-+ *
-+ * Memory is given to a client as \a fd of a certain
-+ * memory \a type.
-+ *
-+ * Further references to this fd will be made with the per memory
-+ * unique identifier \a id.
-+ *
-+ * \param id the unique id of the memory
-+ * \param type the memory type, one of enum spa_data_type
-+ * \param fd the file descriptor
-+ * \param flags extra flags
-+ */
-+ void (*add_mem) (void *object, uint32_t id, uint32_t type, int fd, uint32_t flags);
-+
-+ /**
-+ * Remove memory for a client
-+ *
-+ * \param id the memory id to remove
-+ */
-+ void (*remove_mem) (void *object, uint32_t id);
-+};
-+
-+#define PW_CORE_METHOD_ADD_LISTENER 0
-+#define PW_CORE_METHOD_HELLO 1
-+#define PW_CORE_METHOD_SYNC 2
-+#define PW_CORE_METHOD_PONG 3
-+#define PW_CORE_METHOD_ERROR 4
-+#define PW_CORE_METHOD_GET_REGISTRY 5
-+#define PW_CORE_METHOD_CREATE_OBJECT 6
-+#define PW_CORE_METHOD_DESTROY 7
-+#define PW_CORE_METHOD_NUM 8
-+
-+/**
-+ * \struct pw_core_methods
-+ * \brief Core methods
-+ *
-+ * The core global object. This is a singleton object used for
-+ * creating new objects in the remote PipeWire instance. It is
-+ * also used for internal features.
-+ */
-+struct pw_core_methods {
-+#define PW_VERSION_CORE_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_core_events *events,
-+ void *data);
-+ /**
-+ * Start a conversation with the server. This will send
-+ * the core info and will destroy all resources for the client
-+ * (except the core and client resource).
-+ */
-+ int (*hello) (void *object, uint32_t version);
-+ /**
-+ * Do server roundtrip
-+ *
-+ * Ask the server to emit the 'done' event with \a seq.
-+ *
-+ * Since methods are handled in-order and events are delivered
-+ * in-order, this can be used as a barrier to ensure all previous
-+ * methods and the resulting events have been handled.
-+ *
-+ * \param seq the seq number passed to the done event
-+ */
-+ int (*sync) (void *object, uint32_t id, int seq);
-+ /**
-+ * Reply to a server ping event.
-+ *
-+ * Reply to the server ping event with the same seq.
-+ *
-+ * \param seq the seq number received in the ping event
-+ */
-+ int (*pong) (void *object, uint32_t id, int seq);
-+ /**
-+ * Fatal error event
-+ *
-+ * The error method is sent out when a fatal (non-recoverable)
-+ * error has occurred. The id argument is the proxy object where
-+ * the error occurred, most often in response to an event on that
-+ * object. The message is a brief description of the error,
-+ * for (debugging) convenience.
-+ *
-+ * This method is usually also emitted on the resource object with
-+ * \a id.
-+ *
-+ * \param id object where the error occurred
-+ * \param res error code
-+ * \param message error description
-+ */
-+ int (*error) (void *object, uint32_t id, int seq, int res, const char *message);
-+ /**
-+ * Get the registry object
-+ *
-+ * Create a registry object that allows the client to list and bind
-+ * the global objects available from the PipeWire server
-+ * \param version the client version
-+ * \param user_data_size extra size
-+ */
-+ struct pw_registry * (*get_registry) (void *object, uint32_t version,
-+ size_t user_data_size);
-+
-+ /**
-+ * Create a new object on the PipeWire server from a factory.
-+ *
-+ * \param factory_name the factory name to use
-+ * \param type the interface to bind to
-+ * \param version the version of the interface
-+ * \param props extra properties
-+ * \param user_data_size extra size
-+ */
-+ void * (*create_object) (void *object,
-+ const char *factory_name,
-+ const char *type,
-+ uint32_t version,
-+ const struct spa_dict *props,
-+ size_t user_data_size);
-+ /**
-+ * Destroy an resource
-+ *
-+ * Destroy the server resource for the given proxy.
-+ *
-+ * \param obj the proxy to destroy
-+ */
-+ int (*destroy) (void *object, void *proxy);
-+};
-+
-+#define pw_core_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_core_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_core_add_listener(c,...) pw_core_method(c,add_listener,0,__VA_ARGS__)
-+#define pw_core_hello(c,...) pw_core_method(c,hello,0,__VA_ARGS__)
-+#define pw_core_sync(c,...) pw_core_method(c,sync,0,__VA_ARGS__)
-+#define pw_core_pong(c,...) pw_core_method(c,pong,0,__VA_ARGS__)
-+#define pw_core_error(c,...) pw_core_method(c,error,0,__VA_ARGS__)
-+
-+
-+static inline
-+SPA_PRINTF_FUNC(5, 0) int
-+pw_core_errorv(struct pw_core *core, uint32_t id, int seq,
-+ int res, const char *message, va_list args)
-+{
-+ char buffer[1024];
-+ vsnprintf(buffer, sizeof(buffer), message, args);
-+ buffer[1023] = '\0';
-+ return pw_core_error(core, id, seq, res, buffer);
-+}
-+
-+static inline
-+SPA_PRINTF_FUNC(5, 6) int
-+pw_core_errorf(struct pw_core *core, uint32_t id, int seq,
-+ int res, const char *message, ...)
-+{
-+ va_list args;
-+ int r;
-+ va_start(args, message);
-+ r = pw_core_errorv(core, id, seq, res, message, args);
-+ va_end(args);
-+ return r;
-+}
-+
-+static inline struct pw_registry *
-+pw_core_get_registry(struct pw_core *core, uint32_t version, size_t user_data_size)
-+{
-+ struct pw_registry *res = NULL;
-+ spa_interface_call_res((struct spa_interface*)core,
-+ struct pw_core_methods, res,
-+ get_registry, 0, version, user_data_size);
-+ return res;
-+}
-+
-+static inline void *
-+pw_core_create_object(struct pw_core *core,
-+ const char *factory_name,
-+ const char *type,
-+ uint32_t version,
-+ const struct spa_dict *props,
-+ size_t user_data_size)
-+{
-+ void *res = NULL;
-+ spa_interface_call_res((struct spa_interface*)core,
-+ struct pw_core_methods, res,
-+ create_object, 0, factory_name,
-+ type, version, props, user_data_size);
-+ return res;
-+}
-+
-+#define pw_core_destroy(c,...) pw_core_method(c,destroy,0,__VA_ARGS__)
-+
-+/** \page page_registry Registry
-+ *
-+ * \section page_registry_overview Overview
-+ *
-+ * The registry object is a singleton object that keeps track of
-+ * global objects on the PipeWire instance. See also \ref page_global.
-+ *
-+ * Global objects typically represent an actual object in PipeWire
-+ * (for example, a module or node) or they are singleton
-+ * objects such as the core.
-+ *
-+ * When a client creates a registry object, the registry object
-+ * will emit a global event for each global currently in the
-+ * registry. Globals come and go as a result of device hotplugs or
-+ * reconfiguration or other events, and the registry will send out
-+ * global and global_remove events to keep the client up to date
-+ * with the changes. To mark the end of the initial burst of
-+ * events, the client can use the pw_core.sync methosd immediately
-+ * after calling pw_core.get_registry.
-+ *
-+ * A client can bind to a global object by using the bind
-+ * request. This creates a client-side proxy that lets the object
-+ * emit events to the client and lets the client invoke methods on
-+ * the object. See \ref page_proxy
-+ *
-+ * Clients can also change the permissions of the global objects that
-+ * it can see. This is interesting when you want to configure a
-+ * pipewire session before handing it to another application. You
-+ * can, for example, hide certain existing or new objects or limit
-+ * the access permissions on an object.
-+ */
-+
-+#define PW_REGISTRY_EVENT_GLOBAL 0
-+#define PW_REGISTRY_EVENT_GLOBAL_REMOVE 1
-+#define PW_REGISTRY_EVENT_NUM 2
-+
-+/** Registry events */
-+struct pw_registry_events {
-+#define PW_VERSION_REGISTRY_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify of a new global object
-+ *
-+ * The registry emits this event when a new global object is
-+ * available.
-+ *
-+ * \param id the global object id
-+ * \param permissions the permissions of the object
-+ * \param type the type of the interface
-+ * \param version the version of the interface
-+ * \param props extra properties of the global
-+ */
-+ void (*global) (void *object, uint32_t id,
-+ uint32_t permissions, const char *type, uint32_t version,
-+ const struct spa_dict *props);
-+ /**
-+ * Notify of a global object removal
-+ *
-+ * Emitted when a global object was removed from the registry.
-+ * If the client has any bindings to the global, it should destroy
-+ * those.
-+ *
-+ * \param id the id of the global that was removed
-+ */
-+ void (*global_remove) (void *object, uint32_t id);
-+};
-+
-+#define PW_REGISTRY_METHOD_ADD_LISTENER 0
-+#define PW_REGISTRY_METHOD_BIND 1
-+#define PW_REGISTRY_METHOD_DESTROY 2
-+#define PW_REGISTRY_METHOD_NUM 3
-+
-+/** Registry methods */
-+struct pw_registry_methods {
-+#define PW_VERSION_REGISTRY_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_registry_events *events,
-+ void *data);
-+ /**
-+ * Bind to a global object
-+ *
-+ * Bind to the global object with \a id and use the client proxy
-+ * with new_id as the proxy. After this call, methods can be
-+ * send to the remote global object and events can be received
-+ *
-+ * \param id the global id to bind to
-+ * \param type the interface type to bind to
-+ * \param version the interface version to use
-+ * \returns the new object
-+ */
-+ void * (*bind) (void *object, uint32_t id, const char *type, uint32_t version,
-+ size_t use_data_size);
-+
-+ /**
-+ * Attempt to destroy a global object
-+ *
-+ * Try to destroy the global object.
-+ *
-+ * \param id the global id to destroy
-+ */
-+ int (*destroy) (void *object, uint32_t id);
-+};
-+
-+#define pw_registry_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_registry_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+/** Registry */
-+#define pw_registry_add_listener(p,...) pw_registry_method(p,add_listener,0,__VA_ARGS__)
-+
-+static inline void *
-+pw_registry_bind(struct pw_registry *registry,
-+ uint32_t id, const char *type, uint32_t version,
-+ size_t user_data_size)
-+{
-+ void *res = NULL;
-+ spa_interface_call_res((struct spa_interface*)registry,
-+ struct pw_registry_methods, res,
-+ bind, 0, id, type, version, user_data_size);
-+ return res;
-+}
-+
-+#define pw_registry_destroy(p,...) pw_registry_method(p,destroy,0,__VA_ARGS__)
-+
-+
-+/** Connect to a PipeWire instance \memberof pw_core
-+ * \return a pw_core on success or NULL with errno set on error. The core
-+ * will have an id of PW_ID_CORE (0) */
-+struct pw_core *
-+pw_context_connect(struct pw_context *context, /**< a \ref pw_context */
-+ struct pw_properties *properties, /**< optional properties, ownership of
-+ * the properties is taken.*/
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** Connect to a PipeWire instance on the given socket \memberof pw_core
-+ * \param fd the connected socket to use, the socket will be closed
-+ * automatically on disconnect or error.
-+ * \return a pw_core on success or NULL with errno set on error */
-+struct pw_core *
-+pw_context_connect_fd(struct pw_context *context, /**< a \ref pw_context */
-+ int fd, /**< an fd */
-+ struct pw_properties *properties, /**< optional properties, ownership of
-+ * the properties is taken.*/
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** Connect to a given PipeWire instance \memberof pw_core
-+ * \return a pw_core on success or NULL with errno set on error */
-+struct pw_core *
-+pw_context_connect_self(struct pw_context *context, /**< a \ref pw_context to connect to */
-+ struct pw_properties *properties, /**< optional properties, ownership of
-+ * the properties is taken.*/
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** Steal the fd of the core connection or < 0 on error. The core
-+ * will be disconnected after this call. */
-+int pw_core_steal_fd(struct pw_core *core);
-+
-+/** Pause or resume the core. When the core is paused, no new events
-+ * will be dispatched until the core is resumed again. */
-+int pw_core_set_paused(struct pw_core *core, bool paused);
-+
-+/** disconnect and destroy a core */
-+int pw_core_disconnect(struct pw_core *core);
-+
-+/** Get the user_data. It is of the size specified when this object was
-+ * constructed */
-+void *pw_core_get_user_data(struct pw_core *core);
-+
-+/** Get the client proxy of the connected core. This will have the id
-+ * of PW_ID_CLIENT (1) */
-+struct pw_client * pw_core_get_client(struct pw_core *core);
-+
-+/** Get the context object used to created this core */
-+struct pw_context * pw_core_get_context(struct pw_core *core);
-+
-+/** Get properties from the core */
-+const struct pw_properties *pw_core_get_properties(struct pw_core *core);
-+
-+/** Update the core properties. This updates the properties
-+ * of the associated client.
-+ * \return the number of properties that were updated */
-+int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict);
-+
-+/** Get the core mempool object */
-+struct pw_mempool * pw_core_get_mempool(struct pw_core *core);
-+
-+/** Get the proxy with the given id */
-+struct pw_proxy *pw_core_find_proxy(struct pw_core *core, uint32_t id);
-+
-+/** Export an object into the PipeWire instance associated with core */
-+struct pw_proxy *pw_core_export(struct pw_core *core, /**< the core */
-+ const char *type, /**< the type of object */
-+ const struct spa_dict *props, /**< extra properties */
-+ void *object, /**< object to export */
-+ size_t user_data_size /**< extra user data */);
-+
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_CORE_H */
-diff --git a/third_party/pipewire/pipewire/data-loop.h b/third_party/pipewire/pipewire/data-loop.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/data-loop.h
-@@ -0,0 +1,95 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_DATA_LOOP_H
-+#define PIPEWIRE_DATA_LOOP_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+/** \class pw_data_loop
-+ *
-+ * PipeWire rt-loop object. This loop starts a new real-time thread that
-+ * is designed to run the processing graph.
-+ */
-+struct pw_data_loop;
-+
-+#include <pipewire/loop.h>
-+#include <pipewire/properties.h>
-+
-+/** Loop events, use \ref pw_data_loop_add_listener to add a listener */
-+struct pw_data_loop_events {
-+#define PW_VERSION_DATA_LOOP_EVENTS 0
-+ uint32_t version;
-+ /** The loop is destroyed */
-+ void (*destroy) (void *data);
-+};
-+
-+/** Make a new loop. */
-+struct pw_data_loop *
-+pw_data_loop_new(const struct spa_dict *props);
-+
-+/** Add an event listener to loop */
-+void pw_data_loop_add_listener(struct pw_data_loop *loop,
-+ struct spa_hook *listener,
-+ const struct pw_data_loop_events *events,
-+ void *data);
-+
-+/** wait for activity on the loop up to \a timeout milliseconds.
-+ * Should be called from the loop function */
-+int pw_data_loop_wait(struct pw_data_loop *loop, int timeout);
-+
-+/** make sure the thread will exit. Can be called from a loop callback */
-+void pw_data_loop_exit(struct pw_data_loop *loop);
-+
-+/** Get the loop implementation of this data loop */
-+struct pw_loop *
-+pw_data_loop_get_loop(struct pw_data_loop *loop);
-+
-+/** Destroy the loop */
-+void pw_data_loop_destroy(struct pw_data_loop *loop);
-+
-+/** Start the processing thread */
-+int pw_data_loop_start(struct pw_data_loop *loop);
-+
-+/** Stop the processing thread */
-+int pw_data_loop_stop(struct pw_data_loop *loop);
-+
-+/** Check if the current thread is the processing thread */
-+bool pw_data_loop_in_thread(struct pw_data_loop *loop);
-+
-+/** invoke func in the context of the thread or in the caller thread when
-+ * the loop is not running. Since 0.3.3 */
-+int pw_data_loop_invoke(struct pw_data_loop *loop,
-+ spa_invoke_func_t func, uint32_t seq, const void *data, size_t size,
-+ bool block, void *user_data);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_DATA_LOOP_H */
-diff --git a/third_party/pipewire/pipewire/device.h b/third_party/pipewire/pipewire/device.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/device.h
-@@ -0,0 +1,162 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_DEVICE_H
-+#define PIPEWIRE_DEVICE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+#include <pipewire/proxy.h>
-+
-+#define PW_TYPE_INTERFACE_Device PW_TYPE_INFO_INTERFACE_BASE "Device"
-+
-+#define PW_VERSION_DEVICE 3
-+struct pw_device;
-+
-+/** The device information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_device_info {
-+ uint32_t id; /**< id of the global */
-+#define PW_DEVICE_CHANGE_MASK_PROPS (1 << 0)
-+#define PW_DEVICE_CHANGE_MASK_PARAMS (1 << 1)
-+#define PW_DEVICE_CHANGE_MASK_ALL ((1 << 2)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ struct spa_dict *props; /**< extra properties */
-+ struct spa_param_info *params; /**< parameters */
-+ uint32_t n_params; /**< number of items in \a params */
-+};
-+
-+/** Update and existing \ref pw_device_info with \a update \memberof pw_introspect */
-+struct pw_device_info *
-+pw_device_info_update(struct pw_device_info *info,
-+ const struct pw_device_info *update);
-+
-+/** Free a \ref pw_device_info \memberof pw_introspect */
-+void pw_device_info_free(struct pw_device_info *info);
-+
-+#define PW_DEVICE_EVENT_INFO 0
-+#define PW_DEVICE_EVENT_PARAM 1
-+#define PW_DEVICE_EVENT_NUM 2
-+
-+/** Device events */
-+struct pw_device_events {
-+#define PW_VERSION_DEVICE_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify device info
-+ *
-+ * \param info info about the device
-+ */
-+ void (*info) (void *object, const struct pw_device_info *info);
-+ /**
-+ * Notify a device param
-+ *
-+ * Event emitted as a result of the enum_params method.
-+ *
-+ * \param seq the sequence number of the request
-+ * \param id the param id
-+ * \param index the param index
-+ * \param next the param index of the next param
-+ * \param param the parameter
-+ */
-+ void (*param) (void *object, int seq,
-+ uint32_t id, uint32_t index, uint32_t next,
-+ const struct spa_pod *param);
-+};
-+
-+
-+#define PW_DEVICE_METHOD_ADD_LISTENER 0
-+#define PW_DEVICE_METHOD_SUBSCRIBE_PARAMS 1
-+#define PW_DEVICE_METHOD_ENUM_PARAMS 2
-+#define PW_DEVICE_METHOD_SET_PARAM 3
-+#define PW_DEVICE_METHOD_NUM 4
-+
-+/** Device methods */
-+struct pw_device_methods {
-+#define PW_VERSION_DEVICE_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_device_events *events,
-+ void *data);
-+ /**
-+ * Subscribe to parameter changes
-+ *
-+ * Automatically emit param events for the given ids when
-+ * they are changed.
-+ *
-+ * \param ids an array of param ids
-+ * \param n_ids the number of ids in \a ids
-+ */
-+ int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
-+
-+ /**
-+ * Enumerate device parameters
-+ *
-+ * Start enumeration of device parameters. For each param, a
-+ * param event will be emitted.
-+ *
-+ * \param seq a sequence number to place in the reply
-+ * \param id the parameter id to enum or PW_ID_ANY for all
-+ * \param start the start index or 0 for the first param
-+ * \param num the maximum number of params to retrieve
-+ * \param filter a param filter or NULL
-+ */
-+ int (*enum_params) (void *object, int seq, uint32_t id, uint32_t start, uint32_t num,
-+ const struct spa_pod *filter);
-+ /**
-+ * Set a parameter on the device
-+ *
-+ * \param id the parameter id to set
-+ * \param flags extra parameter flags
-+ * \param param the parameter to set
-+ */
-+ int (*set_param) (void *object, uint32_t id, uint32_t flags,
-+ const struct spa_pod *param);
-+};
-+
-+#define pw_device_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_device_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_device_add_listener(c,...) pw_device_method(c,add_listener,0,__VA_ARGS__)
-+#define pw_device_subscribe_params(c,...) pw_device_method(c,subscribe_params,0,__VA_ARGS__)
-+#define pw_device_enum_params(c,...) pw_device_method(c,enum_params,0,__VA_ARGS__)
-+#define pw_device_set_param(c,...) pw_device_method(c,set_param,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_DEVICE_H */
-diff --git a/third_party/pipewire/pipewire/factory.h b/third_party/pipewire/pipewire/factory.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/factory.h
-@@ -0,0 +1,109 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_FACTORY_H
-+#define PIPEWIRE_FACTORY_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+#include <errno.h>
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+#include <pipewire/proxy.h>
-+
-+#define PW_TYPE_INTERFACE_Factory PW_TYPE_INFO_INTERFACE_BASE "Factory"
-+
-+#define PW_VERSION_FACTORY 3
-+struct pw_factory;
-+
-+/** The factory information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_factory_info {
-+ uint32_t id; /**< id of the global */
-+ const char *name; /**< name the factory */
-+ const char *type; /**< type of the objects created by this factory */
-+ uint32_t version; /**< version of the objects */
-+#define PW_FACTORY_CHANGE_MASK_PROPS (1 << 0)
-+#define PW_FACTORY_CHANGE_MASK_ALL ((1 << 1)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ struct spa_dict *props; /**< the properties of the factory */
-+};
-+
-+struct pw_factory_info *
-+pw_factory_info_update(struct pw_factory_info *info,
-+ const struct pw_factory_info *update);
-+
-+void
-+pw_factory_info_free(struct pw_factory_info *info);
-+
-+
-+#define PW_FACTORY_EVENT_INFO 0
-+#define PW_FACTORY_EVENT_NUM 1
-+
-+/** Factory events */
-+struct pw_factory_events {
-+#define PW_VERSION_FACTORY_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify factory info
-+ *
-+ * \param info info about the factory
-+ */
-+ void (*info) (void *object, const struct pw_factory_info *info);
-+};
-+
-+#define PW_FACTORY_METHOD_ADD_LISTENER 0
-+#define PW_FACTORY_METHOD_NUM 1
-+
-+/** Factory methods */
-+struct pw_factory_methods {
-+#define PW_VERSION_FACTORY_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_factory_events *events,
-+ void *data);
-+};
-+
-+#define pw_factory_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_factory_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_factory_add_listener(c,...) pw_factory_method(c,add_listener,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_FACTORY_H */
-diff --git a/third_party/pipewire/pipewire/filter.h b/third_party/pipewire/pipewire/filter.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/filter.h
-@@ -0,0 +1,240 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_FILTER_H
-+#define PIPEWIRE_FILTER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_filter
-+ *
-+ * \brief PipeWire filter object class
-+ *
-+ * The filter object provides a convenient way to implement
-+ * processing filters.
-+ *
-+ * See also \ref page_filters and \ref page_core_api
-+ */
-+struct pw_filter;
-+
-+#include <spa/buffer/buffer.h>
-+#include <spa/node/io.h>
-+#include <spa/param/param.h>
-+
-+#include <pipewire/core.h>
-+#include <pipewire/stream.h>
-+
-+/** \enum pw_filter_state The state of a filter \memberof pw_filter */
-+enum pw_filter_state {
-+ PW_FILTER_STATE_ERROR = -1, /**< the strean is in error */
-+ PW_FILTER_STATE_UNCONNECTED = 0, /**< unconnected */
-+ PW_FILTER_STATE_CONNECTING = 1, /**< connection is in progress */
-+ PW_FILTER_STATE_PAUSED = 2, /**< filter is connected and paused */
-+ PW_FILTER_STATE_STREAMING = 3 /**< filter is streaming */
-+};
-+
-+#if 0
-+struct pw_buffer {
-+ struct spa_buffer *buffer; /**< the spa buffer */
-+ void *user_data; /**< user data attached to the buffer */
-+ uint64_t size; /**< For input ports, this field is set by pw_filter
-+ * with the duration of the buffer in ticks.
-+ * For output ports, this field is set by the user.
-+ * This field is added for all queued buffers and
-+ * returned in the time info. */
-+};
-+#endif
-+
-+/** Events for a filter. These events are always called from the mainloop
-+ * unless explicitly documented otherwise. */
-+struct pw_filter_events {
-+#define PW_VERSION_FILTER_EVENTS 0
-+ uint32_t version;
-+
-+ void (*destroy) (void *data);
-+ /** when the filter state changes */
-+ void (*state_changed) (void *data, enum pw_filter_state old,
-+ enum pw_filter_state state, const char *error);
-+
-+ /** when io changed on a port of the filter (when port_data is NULL). */
-+ void (*io_changed) (void *data, void *port_data,
-+ uint32_t id, void *area, uint32_t size);
-+ /** when a parameter changed on a port of the filter (when port_data is NULL). */
-+ void (*param_changed) (void *data, void *port_data,
-+ uint32_t id, const struct spa_pod *param);
-+
-+ /** when a new buffer was created for a port */
-+ void (*add_buffer) (void *data, void *port_data, struct pw_buffer *buffer);
-+ /** when a buffer was destroyed for a port */
-+ void (*remove_buffer) (void *data, void *port_data, struct pw_buffer *buffer);
-+
-+ /** do processing. This is normally called from the
-+ * mainloop but can also be called directly from the realtime data
-+ * thread if the user is prepared to deal with this. */
-+ void (*process) (void *data, struct spa_io_position *position);
-+
-+ /** The filter is drained */
-+ void (*drained) (void *data);
-+};
-+
-+/** Convert a filter state to a readable string \memberof pw_filter */
-+const char * pw_filter_state_as_string(enum pw_filter_state state);
-+
-+/** \enum pw_filter_flags Extra flags that can be used in \ref pw_filter_connect() \memberof pw_filter */
-+enum pw_filter_flags {
-+ PW_FILTER_FLAG_NONE = 0, /**< no flags */
-+ PW_FILTER_FLAG_INACTIVE = (1 << 0), /**< start the filter inactive,
-+ * pw_filter_set_active() needs to be
-+ * called explicitly */
-+ PW_FILTER_FLAG_DRIVER = (1 << 1), /**< be a driver */
-+ PW_FILTER_FLAG_RT_PROCESS = (1 << 2), /**< call process from the realtime
-+ * thread */
-+};
-+
-+enum pw_filter_port_flags {
-+ PW_FILTER_PORT_FLAG_NONE = 0, /**< no flags */
-+ PW_FILTER_PORT_FLAG_MAP_BUFFERS = (1 << 0), /**< mmap the buffers */
-+ PW_FILTER_PORT_FLAG_ALLOC_BUFFERS = (1 << 1), /**< the application will allocate buffer
-+ * memory. In the add_buffer event, the
-+ * data of the buffer should be set */
-+};
-+
-+/** Create a new unconneced \ref pw_filter \memberof pw_filter
-+ * \return a newly allocated \ref pw_filter */
-+struct pw_filter *
-+pw_filter_new(struct pw_core *core, /**< a \ref pw_core */
-+ const char *name, /**< a filter media name */
-+ struct pw_properties *props /**< filter properties, ownership is taken */);
-+
-+struct pw_filter *
-+pw_filter_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */
-+ const char *name, /**< a filter media name */
-+ struct pw_properties *props, /**< filter properties, ownership is taken */
-+ const struct pw_filter_events *events, /**< filter events */
-+ void *data /**< data passed to events */);
-+
-+/** Destroy a filter \memberof pw_filter */
-+void pw_filter_destroy(struct pw_filter *filter);
-+
-+void pw_filter_add_listener(struct pw_filter *filter,
-+ struct spa_hook *listener,
-+ const struct pw_filter_events *events,
-+ void *data);
-+
-+enum pw_filter_state pw_filter_get_state(struct pw_filter *filter, const char **error);
-+
-+const char *pw_filter_get_name(struct pw_filter *filter);
-+
-+struct pw_core *pw_filter_get_core(struct pw_filter *filter);
-+
-+/** Connect a filter for processing. \memberof pw_filter
-+ * \return 0 on success < 0 on error.
-+ *
-+ * You should connect to the process event and use pw_filter_dequeue_buffer()
-+ * to get the latest metadata and data. */
-+int
-+pw_filter_connect(struct pw_filter *filter, /**< a \ref pw_filter */
-+ enum pw_filter_flags flags, /**< filter flags */
-+ const struct spa_pod **params, /**< an array with params. */
-+ uint32_t n_params /**< number of items in \a params */);
-+
-+/** Get the node ID of the filter. \memberof pw_filter
-+ * \return node ID. */
-+uint32_t
-+pw_filter_get_node_id(struct pw_filter *filter);
-+
-+/** Disconnect \a filter \memberof pw_filter */
-+int pw_filter_disconnect(struct pw_filter *filter);
-+
-+/** add a port to the filter, returns user data of port_data_size. */
-+void *pw_filter_add_port(struct pw_filter *filter,
-+ enum pw_direction direction, /**< port direction */
-+ enum pw_filter_port_flags flags, /**< port flags */
-+ size_t port_data_size, /**< allocated and given to the user as port_data */
-+ struct pw_properties *props, /**< port properties, ownership is taken */
-+ const struct spa_pod **params, /**< an array of params. The params should
-+ * ideally contain the supported formats */
-+ uint32_t n_params /**< number of elements in \a params */);
-+
-+/** remove a port from the filter */
-+int pw_filter_remove_port(void *port_data /**< data associated with port */);
-+
-+/** get properties, port_data of NULL will give global properties */
-+const struct pw_properties *pw_filter_get_properties(struct pw_filter *filter,
-+ void *port_data);
-+
-+/** Update properties, use NULL port_data for global filter properties */
-+int pw_filter_update_properties(struct pw_filter *filter,
-+ void *port_data, const struct spa_dict *dict);
-+
-+/** Set the filter in error state */
-+int pw_filter_set_error(struct pw_filter *filter, /**< a \ref pw_filter */
-+ int res, /**< a result code */
-+ const char *error, ... /**< an error message */) SPA_PRINTF_FUNC(3, 4);
-+
-+/** Update params, use NULL port_data for global filter params */
-+int
-+pw_filter_update_params(struct pw_filter *filter, /**< a \ref pw_filter */
-+ void *port_data, /**< data associated with port */
-+ const struct spa_pod **params, /**< an array of params. */
-+ uint32_t n_params /**< number of elements in \a params */);
-+
-+
-+#if 0
-+/** A time structure \memberof pw_filter */
-+struct pw_time {
-+ int64_t now; /**< the monotonic time */
-+ struct spa_fraction rate; /**< the rate of \a ticks and delay */
-+ uint64_t ticks; /**< the ticks at \a now. This is the current time that
-+ * the remote end is reading/writing. */
-+};
-+#endif
-+
-+/** Query the time on the filter \memberof pw_filter */
-+int pw_filter_get_time(struct pw_filter *filter, struct pw_time *time);
-+
-+/** Get a buffer that can be filled for output ports or consumed
-+ * for input ports. */
-+struct pw_buffer *pw_filter_dequeue_buffer(void *port_data);
-+
-+/** Submit a buffer for playback or recycle a buffer for capture. */
-+int pw_filter_queue_buffer(void *port_data, struct pw_buffer *buffer);
-+
-+/** Get a data pointer to the buffer data */
-+void *pw_filter_get_dsp_buffer(void *port_data, uint32_t n_samples);
-+
-+/** Activate or deactivate the filter \memberof pw_filter */
-+int pw_filter_set_active(struct pw_filter *filter, bool active);
-+
-+/** Flush a filter. When \a drain is true, the drained callback will
-+ * be called when all data is played or recorded */
-+int pw_filter_flush(struct pw_filter *filter, bool drain);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_FILTER_H */
-diff --git a/third_party/pipewire/pipewire/global.h b/third_party/pipewire/pipewire/global.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/global.h
-@@ -0,0 +1,155 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_GLOBAL_H
-+#define PIPEWIRE_GLOBAL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \page page_global Global
-+ *
-+ * Global objects represent resources that are available on the PipeWire
-+ * context and are accessible to remote clients.
-+ * Globals come and go when devices or other resources become available for
-+ * clients.
-+ *
-+ * Remote clients receives a list of globals when it binds to the registry
-+ * object. See \ref page_registry.
-+ *
-+ * A client can bind to a global to send methods or receive events from
-+ * the global.
-+ */
-+/** \class pw_global
-+ *
-+ * \brief A global object visible to remote clients
-+ *
-+ * A global object is visible to remote clients and represents a resource
-+ * that can be used or inspected.
-+ *
-+ * See \ref page_remote_api
-+ */
-+struct pw_global;
-+
-+#include <pipewire/impl.h>
-+
-+typedef int (*pw_global_bind_func_t) (void *object,
-+ struct pw_impl_client *client, /**< client that binds */
-+ uint32_t permissions, /**< permissions for the bind */
-+ uint32_t version, /**< client interface version */
-+ uint32_t id /**< client proxy id */);
-+
-+/** Global events, use \ref pw_global_add_listener */
-+struct pw_global_events {
-+#define PW_VERSION_GLOBAL_EVENTS 0
-+ uint32_t version;
-+
-+ /** The global is destroyed */
-+ void (*destroy) (void *data);
-+ /** The global is freed */
-+ void (*free) (void *data);
-+ /** The permissions changed for a client */
-+ void (*permissions_changed) (void *data,
-+ struct pw_impl_client *client,
-+ uint32_t old_permissions,
-+ uint32_t new_permissions);
-+};
-+
-+/** Create a new global object */
-+struct pw_global *
-+pw_global_new(struct pw_context *context, /**< the context */
-+ const char *type, /**< the interface type of the global */
-+ uint32_t version, /**< the interface version of the global */
-+ struct pw_properties *properties, /**< extra properties */
-+ pw_global_bind_func_t func, /**< function to bind */
-+ void *object /**< global object */);
-+
-+/** Register a global object to the context registry */
-+int pw_global_register(struct pw_global *global);
-+
-+/** Add an event listener on the global */
-+void pw_global_add_listener(struct pw_global *global,
-+ struct spa_hook *listener,
-+ const struct pw_global_events *events,
-+ void *data);
-+
-+/** Get the permissions of the global for a given client */
-+uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_impl_client *client);
-+
-+/** Get the context object of this global */
-+struct pw_context *pw_global_get_context(struct pw_global *global);
-+
-+/** Get the global type */
-+const char *pw_global_get_type(struct pw_global *global);
-+
-+/** Check a global type */
-+bool pw_global_is_type(struct pw_global *global, const char *type);
-+
-+/** Get the global version */
-+uint32_t pw_global_get_version(struct pw_global *global);
-+
-+/** Get the global properties */
-+const struct pw_properties *pw_global_get_properties(struct pw_global *global);
-+
-+/** Update the global properties, must be done when unregistered */
-+int pw_global_update_keys(struct pw_global *global,
-+ const struct spa_dict *dict, const char *keys[]);
-+
-+/** Get the object associated with the global. This depends on the type of the
-+ * global */
-+void *pw_global_get_object(struct pw_global *global);
-+
-+/** Get the unique id of the global */
-+uint32_t pw_global_get_id(struct pw_global *global);
-+
-+/** Add a resource to a global */
-+int pw_global_add_resource(struct pw_global *global, struct pw_resource *resource);
-+
-+/** Iterate all resources added to the global The callback should return
-+ * 0 to fetch the next item, any other value stops the iteration and returns
-+ * the value. When all callbacks return 0, this function returns 0 when all
-+ * items are iterated. */
-+int pw_global_for_each_resource(struct pw_global *global,
-+ int (*callback) (void *data, struct pw_resource *resource),
-+ void *data);
-+
-+/** Let a client bind to a global */
-+int pw_global_bind(struct pw_global *global,
-+ struct pw_impl_client *client,
-+ uint32_t permissions,
-+ uint32_t version,
-+ uint32_t id);
-+
-+int pw_global_update_permissions(struct pw_global *global, struct pw_impl_client *client,
-+ uint32_t old_permissions, uint32_t new_permissions);
-+
-+/** Destroy a global */
-+void pw_global_destroy(struct pw_global *global);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_GLOBAL_H */
-diff --git a/third_party/pipewire/pipewire/impl-client.h b/third_party/pipewire/pipewire/impl-client.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-client.h
-@@ -0,0 +1,174 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_CLIENT_H
-+#define PIPEWIRE_IMPL_CLIENT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+/** \class pw_impl_client
-+ *
-+ * \brief PipeWire client object class.
-+ *
-+ * The client object represents a client connection with the PipeWire
-+ * server.
-+ *
-+ * Each client has its own list of resources it is bound to along with
-+ * a mapping between the client types and server types.
-+ */
-+struct pw_impl_client;
-+
-+#include <pipewire/context.h>
-+#include <pipewire/global.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/resource.h>
-+#include <pipewire/permission.h>
-+
-+/** \page page_client Client
-+ *
-+ * \section sec_page_client_overview Overview
-+ *
-+ * The \ref pw_impl_client object is created by a protocol implementation when
-+ * a new client connects.
-+ *
-+ * The client is used to keep track of all resources belonging to one
-+ * connection with the PipeWire server.
-+ *
-+ * \section sec_page_client_credentials Credentials
-+ *
-+ * The client object will have its credentials filled in by the protocol.
-+ * This information is used to check if a resource or action is available
-+ * for this client. See also \ref page_access
-+ *
-+ * \section sec_page_client_types Types
-+ *
-+ * The client and server maintain a mapping between the client and server
-+ * types. All type ids that are in messages exchanged between the client
-+ * and server will automatically be remapped. See also \ref page_types.
-+ *
-+ * \section sec_page_client_resources Resources
-+ *
-+ * When a client binds to context global object, a resource is made for this
-+ * binding and a unique id is assigned to the resources. The client and
-+ * server will use this id as the destination when exchanging messages.
-+ * See also \ref page_resource
-+ */
-+
-+/** The events that a client can emit */
-+struct pw_impl_client_events {
-+#define PW_VERSION_IMPL_CLIENT_EVENTS 0
-+ uint32_t version;
-+
-+ /** emitted when the client is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** emitted right before the client is freed */
-+ void (*free) (void *data);
-+
-+ /** the client is initialized */
-+ void (*initialized) (void *data);
-+
-+ /** emitted when the client info changed */
-+ void (*info_changed) (void *data, const struct pw_client_info *info);
-+
-+ /** emitted when a new resource is added for client */
-+ void (*resource_added) (void *data, struct pw_resource *resource);
-+
-+ /** emitted when a resource is removed */
-+ void (*resource_removed) (void *data, struct pw_resource *resource);
-+
-+ /** emitted when the client becomes busy processing an asynchronous
-+ * message. In the busy state no messages should be processed.
-+ * Processing should resume when the client becomes not busy */
-+ void (*busy_changed) (void *data, bool busy);
-+};
-+
-+/** Create a new client. This is mainly used by protocols. */
-+struct pw_impl_client *
-+pw_context_create_client(struct pw_impl_core *core, /**< the core object */
-+ struct pw_protocol *prototol, /**< the client protocol */
-+ struct pw_properties *properties, /**< client properties */
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** Destroy a previously created client */
-+void pw_impl_client_destroy(struct pw_impl_client *client);
-+
-+/** Finish configuration and register a client */
-+int pw_impl_client_register(struct pw_impl_client *client, /**< the client to register */
-+ struct pw_properties *properties/**< extra properties */);
-+
-+/** Get the client user data */
-+void *pw_impl_client_get_user_data(struct pw_impl_client *client);
-+
-+/** Get the client information */
-+const struct pw_client_info *pw_impl_client_get_info(struct pw_impl_client *client);
-+
-+/** Update the client properties */
-+int pw_impl_client_update_properties(struct pw_impl_client *client, const struct spa_dict *dict);
-+
-+/** Update the client permissions */
-+int pw_impl_client_update_permissions(struct pw_impl_client *client, uint32_t n_permissions,
-+ const struct pw_permission *permissions);
-+
-+/** check if a client has permissions for global_id, Since 0.3.9 */
-+int pw_impl_client_check_permissions(struct pw_impl_client *client,
-+ uint32_t global_id, uint32_t permissions);
-+
-+/** Get the client properties */
-+const struct pw_properties *pw_impl_client_get_properties(struct pw_impl_client *client);
-+
-+/** Get the context used to create this client */
-+struct pw_context *pw_impl_client_get_context(struct pw_impl_client *client);
-+/** Get the protocol used to create this client */
-+struct pw_protocol *pw_impl_client_get_protocol(struct pw_impl_client *client);
-+
-+/** Get the client core resource */
-+struct pw_resource *pw_impl_client_get_core_resource(struct pw_impl_client *client);
-+
-+/** Get a resource with the given id */
-+struct pw_resource *pw_impl_client_find_resource(struct pw_impl_client *client, uint32_t id);
-+
-+/** Get the global associated with this client */
-+struct pw_global *pw_impl_client_get_global(struct pw_impl_client *client);
-+
-+/** listen to events from this client */
-+void pw_impl_client_add_listener(struct pw_impl_client *client,
-+ struct spa_hook *listener,
-+ const struct pw_impl_client_events *events,
-+ void *data);
-+
-+
-+/** Mark the client busy. This can be used when an asynchronous operation is
-+ * started and no further processing is allowed to happen for the client */
-+void pw_impl_client_set_busy(struct pw_impl_client *client, bool busy);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_CLIENT_H */
-diff --git a/third_party/pipewire/pipewire/impl-core.h b/third_party/pipewire/pipewire/impl-core.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-core.h
-@@ -0,0 +1,94 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_CORE_H
-+#define PIPEWIRE_IMPL_CORE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_impl_core
-+ *
-+ * \brief PipeWire core interface.
-+ *
-+ * The core is used to make objects on demand.
-+ */
-+struct pw_impl_core;
-+
-+#include <pipewire/context.h>
-+#include <pipewire/global.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/resource.h>
-+
-+/** Factory events, listen to them with \ref pw_impl_core_add_listener */
-+struct pw_impl_core_events {
-+#define PW_VERSION_IMPL_CORE_EVENTS 0
-+ uint32_t version;
-+
-+ /** the core is destroyed */
-+ void (*destroy) (void *data);
-+ /** the core is freed */
-+ void (*free) (void *data);
-+ /** the core is initialized */
-+ void (*initialized) (void *data);
-+};
-+
-+struct pw_impl_core *pw_context_create_core(struct pw_context *context,
-+ struct pw_properties *properties,
-+ size_t user_data_size);
-+
-+/* get the default core in a context */
-+struct pw_impl_core *pw_context_get_default_core(struct pw_context *context);
-+
-+/** Get the core properties */
-+const struct pw_properties *pw_impl_core_get_properties(struct pw_impl_core *core);
-+
-+/** Get the core information */
-+const struct pw_core_info *pw_impl_core_get_info(struct pw_impl_core *core);
-+
-+/** Update the core properties */
-+int pw_impl_core_update_properties(struct pw_impl_core *core, const struct spa_dict *dict);
-+
-+int pw_impl_core_register(struct pw_impl_core *core,
-+ struct pw_properties *properties);
-+
-+void pw_impl_core_destroy(struct pw_impl_core *core);
-+
-+void *pw_impl_core_get_user_data(struct pw_impl_core *core);
-+
-+/** Get the global of this core */
-+struct pw_global *pw_impl_core_get_global(struct pw_impl_core *core);
-+
-+/** Add an event listener */
-+void pw_impl_core_add_listener(struct pw_impl_core *core,
-+ struct spa_hook *listener,
-+ const struct pw_impl_core_events *events,
-+ void *data);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_CORE_H */
-diff --git a/third_party/pipewire/pipewire/impl-device.h b/third_party/pipewire/pipewire/impl-device.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-device.h
-@@ -0,0 +1,109 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_DEVICE_H
-+#define PIPEWIRE_IMPL_DEVICE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_impl_device
-+ *
-+ * \brief PipeWire device interface.
-+ *
-+ * The device is an object that manages nodes. It typically
-+ * corresponds to a physical hardware device but it does not
-+ * have to be.
-+ *
-+ * The purpose of the device is to provide an interface to
-+ * dynamically create/remove/configure the nodes it manages.
-+ */
-+struct pw_impl_device;
-+
-+#include <spa/monitor/device.h>
-+
-+#include <pipewire/context.h>
-+#include <pipewire/global.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/resource.h>
-+
-+/** Device events, listen to them with \ref pw_impl_device_add_listener */
-+struct pw_impl_device_events {
-+#define PW_VERSION_IMPL_DEVICE_EVENTS 0
-+ uint32_t version;
-+
-+ /** the device is destroyed */
-+ void (*destroy) (void *data);
-+ /** the device is freed */
-+ void (*free) (void *data);
-+ /** the device is initialized */
-+ void (*initialized) (void *data);
-+
-+ /** the device info changed */
-+ void (*info_changed) (void *data, const struct pw_device_info *info);
-+};
-+
-+struct pw_impl_device *pw_context_create_device(struct pw_context *context,
-+ struct pw_properties *properties,
-+ size_t user_data_size);
-+
-+int pw_impl_device_register(struct pw_impl_device *device,
-+ struct pw_properties *properties);
-+
-+void pw_impl_device_destroy(struct pw_impl_device *device);
-+
-+void *pw_impl_device_get_user_data(struct pw_impl_device *device);
-+
-+/** Set the device implementation */
-+int pw_impl_device_set_implementation(struct pw_impl_device *device, struct spa_device *spa_device);
-+/** Get the device implementation */
-+struct spa_device *pw_impl_device_get_implementation(struct pw_impl_device *device);
-+
-+/** Get the global of this device */
-+struct pw_global *pw_impl_device_get_global(struct pw_impl_device *device);
-+
-+/** Add an event listener */
-+void pw_impl_device_add_listener(struct pw_impl_device *device,
-+ struct spa_hook *listener,
-+ const struct pw_impl_device_events *events,
-+ void *data);
-+
-+int pw_impl_device_update_properties(struct pw_impl_device *device, const struct spa_dict *dict);
-+
-+const struct pw_properties *pw_impl_device_get_properties(struct pw_impl_device *device);
-+
-+int pw_impl_device_for_each_param(struct pw_impl_device *device,
-+ int seq, uint32_t param_id,
-+ uint32_t index, uint32_t max,
-+ const struct spa_pod *filter,
-+ int (*callback) (void *data, int seq,
-+ uint32_t id, uint32_t index, uint32_t next,
-+ struct spa_pod *param),
-+ void *data);
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_DEVICE_H */
-diff --git a/third_party/pipewire/pipewire/impl-factory.h b/third_party/pipewire/pipewire/impl-factory.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-factory.h
-@@ -0,0 +1,124 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_FACTORY_H
-+#define PIPEWIRE_IMPL_FACTORY_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_impl_factory
-+ *
-+ * \brief PipeWire factory interface.
-+ *
-+ * The factory is used to make objects on demand.
-+ */
-+struct pw_impl_factory;
-+
-+#include <pipewire/context.h>
-+#include <pipewire/impl-client.h>
-+#include <pipewire/global.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/resource.h>
-+
-+/** Factory events, listen to them with \ref pw_impl_factory_add_listener */
-+struct pw_impl_factory_events {
-+#define PW_VERSION_IMPL_FACTORY_EVENTS 0
-+ uint32_t version;
-+
-+ /** the factory is destroyed */
-+ void (*destroy) (void *data);
-+ /** the factory is freed */
-+ void (*free) (void *data);
-+ /** the factory is initialized */
-+ void (*initialized) (void *data);
-+};
-+
-+struct pw_impl_factory_implementation {
-+#define PW_VERSION_IMPL_FACTORY_IMPLEMENTATION 0
-+ uint32_t version;
-+
-+ /** The function to create an object from this factory */
-+ void *(*create_object) (void *data,
-+ struct pw_resource *resource,
-+ const char *type,
-+ uint32_t version,
-+ struct pw_properties *properties,
-+ uint32_t new_id);
-+};
-+
-+struct pw_impl_factory *pw_context_create_factory(struct pw_context *context,
-+ const char *name,
-+ const char *type,
-+ uint32_t version,
-+ struct pw_properties *properties,
-+ size_t user_data_size);
-+
-+/** Get the factory properties */
-+const struct pw_properties *pw_impl_factory_get_properties(struct pw_impl_factory *factory);
-+
-+/** Get the factory info */
-+const struct pw_factory_info *pw_impl_factory_get_info(struct pw_impl_factory *factory);
-+
-+/** Update the factory properties */
-+int pw_impl_factory_update_properties(struct pw_impl_factory *factory, const struct spa_dict *dict);
-+
-+int pw_impl_factory_register(struct pw_impl_factory *factory,
-+ struct pw_properties *properties);
-+
-+void pw_impl_factory_destroy(struct pw_impl_factory *factory);
-+
-+void *pw_impl_factory_get_user_data(struct pw_impl_factory *factory);
-+
-+/** Get the global of this factory */
-+struct pw_global *pw_impl_factory_get_global(struct pw_impl_factory *factory);
-+
-+/** Add an event listener */
-+void pw_impl_factory_add_listener(struct pw_impl_factory *factory,
-+ struct spa_hook *listener,
-+ const struct pw_impl_factory_events *events,
-+ void *data);
-+
-+void pw_impl_factory_set_implementation(struct pw_impl_factory *factory,
-+ const struct pw_impl_factory_implementation *implementation,
-+ void *data);
-+
-+void *pw_impl_factory_create_object(struct pw_impl_factory *factory,
-+ struct pw_resource *resource,
-+ const char *type,
-+ uint32_t version,
-+ struct pw_properties *properties,
-+ uint32_t new_id);
-+
-+/** Find a factory by name */
-+struct pw_impl_factory *
-+pw_context_find_factory(struct pw_context *context /**< the context */,
-+ const char *name /**< the factory name */);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_FACTORY_H */
-diff --git a/third_party/pipewire/pipewire/impl-link.h b/third_party/pipewire/pipewire/impl-link.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-link.h
-@@ -0,0 +1,128 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_LINK_H
-+#define PIPEWIRE_IMPL_LINK_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_impl_link
-+ *
-+ * PipeWire link object.
-+ */
-+struct pw_impl_link;
-+struct pw_impl_port;
-+
-+#include <pipewire/impl.h>
-+
-+/** \page page_link Link
-+ *
-+ * \section page_link_overview Overview
-+ *
-+ * A link is the connection between 2 nodes (\ref page_node). Nodes are
-+ * linked together on ports.
-+ *
-+ * The link is responsible for negotiating the format and buffers for
-+ * the nodes.
-+ */
-+
-+/** link events added with \ref pw_impl_link_add_listener */
-+struct pw_impl_link_events {
-+#define PW_VERSION_IMPL_LINK_EVENTS 0
-+ uint32_t version;
-+
-+ /** A link is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** A link is freed */
-+ void (*free) (void *data);
-+
-+ /** a Link is initialized */
-+ void (*initialized) (void *data);
-+
-+ /** The info changed on a link */
-+ void (*info_changed) (void *data, const struct pw_link_info *info);
-+
-+ /** The link state changed, \a error is only valid when the state is
-+ * in error. */
-+ void (*state_changed) (void *data, enum pw_link_state old,
-+ enum pw_link_state state, const char *error);
-+
-+ /** A port is unlinked */
-+ void (*port_unlinked) (void *data, struct pw_impl_port *port);
-+};
-+
-+
-+/** Make a new link between two ports \memberof pw_impl_link
-+ * \return a newly allocated link */
-+struct pw_impl_link *
-+pw_context_create_link(struct pw_context *context, /**< the context object */
-+ struct pw_impl_port *output, /**< an output port */
-+ struct pw_impl_port *input, /**< an input port */
-+ struct spa_pod *format_filter, /**< an optional format filter */
-+ struct pw_properties *properties /**< extra properties */,
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** Destroy a link \memberof pw_impl_link */
-+void pw_impl_link_destroy(struct pw_impl_link *link);
-+
-+/** Add an event listener to \a link */
-+void pw_impl_link_add_listener(struct pw_impl_link *link,
-+ struct spa_hook *listener,
-+ const struct pw_impl_link_events *events,
-+ void *data);
-+
-+/** Finish link configuration and register */
-+int pw_impl_link_register(struct pw_impl_link *link, /**< the link to register */
-+ struct pw_properties *properties /**< extra properties */);
-+
-+/** Get the context of a link */
-+struct pw_context *pw_impl_link_get_context(struct pw_impl_link *link);
-+
-+/** Get the user_data of a link, the size of the memory is given when
-+ * constructing the link */
-+void *pw_impl_link_get_user_data(struct pw_impl_link *link);
-+
-+/** Get the link info */
-+const struct pw_link_info *pw_impl_link_get_info(struct pw_impl_link *link);
-+
-+/** Get the global of the link */
-+struct pw_global *pw_impl_link_get_global(struct pw_impl_link *link);
-+
-+/** Get the output port of the link */
-+struct pw_impl_port *pw_impl_link_get_output(struct pw_impl_link *link);
-+
-+/** Get the input port of the link */
-+struct pw_impl_port *pw_impl_link_get_input(struct pw_impl_link *link);
-+
-+/** Find the link between 2 ports \memberof pw_impl_link */
-+struct pw_impl_link *pw_impl_link_find(struct pw_impl_port *output, struct pw_impl_port *input);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_LINK_H */
-diff --git a/third_party/pipewire/pipewire/impl-module.h b/third_party/pipewire/pipewire/impl-module.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-module.h
-@@ -0,0 +1,110 @@
-+/* PipeWire
-+ * Copyright © 2016 Axis Communications <dev-gstreamer@axis.com>
-+ * @author Linus Svensson <linus.svensson@axis.com>
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_MODULE_H
-+#define PIPEWIRE_IMPL_MODULE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+#include <pipewire/context.h>
-+
-+#define PIPEWIRE_SYMBOL_MODULE_INIT "pipewire__module_init"
-+#define PIPEWIRE_MODULE_PREFIX "libpipewire-"
-+
-+/** \class pw_impl_module
-+ *
-+ * A dynamically loadable module
-+ */
-+struct pw_impl_module;
-+
-+/** Module init function signature
-+ *
-+ * \param module A \ref pw_impl_module
-+ * \param args Arguments to the module
-+ * \return 0 on success, < 0 otherwise with an errno style error
-+ *
-+ * A module should provide an init function with this signature. This function
-+ * will be called when a module is loaded.
-+ *
-+ * \memberof pw_impl_module
-+ */
-+typedef int (*pw_impl_module_init_func_t) (struct pw_impl_module *module, const char *args);
-+
-+/** Module events added with \ref pw_impl_module_add_listener */
-+struct pw_impl_module_events {
-+#define PW_VERSION_IMPL_MODULE_EVENTS 0
-+ uint32_t version;
-+
-+ /** The module is destroyed */
-+ void (*destroy) (void *data);
-+ /** The module is freed */
-+ void (*free) (void *data);
-+ /** The module is initialized */
-+ void (*initialized) (void *data);
-+
-+ /** The module is registered. This is a good time to register
-+ * objectes created from the module. */
-+ void (*registered) (void *data);
-+};
-+
-+struct pw_impl_module *
-+pw_context_load_module(struct pw_context *context,
-+ const char *name, /**< name of the module */
-+ const char *args /**< arguments of the module */,
-+ struct pw_properties *properties /**< extra global properties */);
-+
-+/** Get the context of a module */
-+struct pw_context * pw_impl_module_get_context(struct pw_impl_module *module);
-+
-+/** Get the global of a module */
-+struct pw_global * pw_impl_module_get_global(struct pw_impl_module *module);
-+
-+/** Get the node properties */
-+const struct pw_properties *pw_impl_module_get_properties(struct pw_impl_module *module);
-+
-+/** Update the module properties */
-+int pw_impl_module_update_properties(struct pw_impl_module *module, const struct spa_dict *dict);
-+
-+/** Get the module info */
-+const struct pw_module_info *pw_impl_module_get_info(struct pw_impl_module *module);
-+
-+/** Add an event listener to a module */
-+void pw_impl_module_add_listener(struct pw_impl_module *module,
-+ struct spa_hook *listener,
-+ const struct pw_impl_module_events *events,
-+ void *data);
-+
-+/** Destroy a module */
-+void pw_impl_module_destroy(struct pw_impl_module *module);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_MODULE_H */
-diff --git a/third_party/pipewire/pipewire/impl-node.h b/third_party/pipewire/pipewire/impl-node.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-node.h
-@@ -0,0 +1,182 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_NODE_H
-+#define PIPEWIRE_IMPL_NODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \page page_node Node
-+ *
-+ * \section page_node_overview Overview
-+ *
-+ * The node object processes data. The node has a list of
-+ * input and output ports (\ref page_port) on which it
-+ * will receive and send out buffers respectively.
-+ */
-+/** \class pw_impl_node
-+ *
-+ * PipeWire node class.
-+ */
-+struct pw_impl_node;
-+struct pw_impl_port;
-+
-+#include <spa/node/node.h>
-+#include <spa/node/event.h>
-+
-+#include <pipewire/impl.h>
-+
-+/** Node events, listen to them with \ref pw_impl_node_add_listener */
-+struct pw_impl_node_events {
-+#define PW_VERSION_IMPL_NODE_EVENTS 0
-+ uint32_t version;
-+
-+ /** the node is destroyed */
-+ void (*destroy) (void *data);
-+ /** the node is about to be freed */
-+ void (*free) (void *data);
-+ /** the node is initialized */
-+ void (*initialized) (void *data);
-+
-+ /** a port is being initialized on the node */
-+ void (*port_init) (void *data, struct pw_impl_port *port);
-+ /** a port was added */
-+ void (*port_added) (void *data, struct pw_impl_port *port);
-+ /** a port was removed */
-+ void (*port_removed) (void *data, struct pw_impl_port *port);
-+
-+ /** the node info changed */
-+ void (*info_changed) (void *data, const struct pw_node_info *info);
-+ /** a port on the node changed info */
-+ void (*port_info_changed) (void *data, struct pw_impl_port *port,
-+ const struct pw_port_info *info);
-+ /** the node active state changed */
-+ void (*active_changed) (void *data, bool active);
-+
-+ /** a new state is requested on the node */
-+ void (*state_request) (void *data, enum pw_node_state state);
-+ /** the state of the node changed */
-+ void (*state_changed) (void *data, enum pw_node_state old,
-+ enum pw_node_state state, const char *error);
-+
-+ /** a result was received */
-+ void (*result) (void *data, int seq, int res, uint32_t type, const void *result);
-+
-+ /** an event is emitted */
-+ void (*event) (void *data, const struct spa_event *event);
-+
-+ /** the driver of the node changed */
-+ void (*driver_changed) (void *data, struct pw_impl_node *old, struct pw_impl_node *driver);
-+
-+ /** a peer was added */
-+ void (*peer_added) (void *data, struct pw_impl_node *peer);
-+ /** a peer was removed */
-+ void (*peer_removed) (void *data, struct pw_impl_node *peer);
-+};
-+
-+/** Create a new node \memberof pw_impl_node */
-+struct pw_impl_node *
-+pw_context_create_node(struct pw_context *context, /**< the context */
-+ struct pw_properties *properties, /**< extra properties */
-+ size_t user_data_size /**< user data size */);
-+
-+/** Complete initialization of the node and register */
-+int pw_impl_node_register(struct pw_impl_node *node, /**< node to register */
-+ struct pw_properties *properties /**< extra properties */);
-+
-+/** Destroy a node */
-+void pw_impl_node_destroy(struct pw_impl_node *node);
-+
-+/** Get the node info */
-+const struct pw_node_info *pw_impl_node_get_info(struct pw_impl_node *node);
-+
-+/** Get node user_data. The size of the memory was given in \ref pw_context_create_node */
-+void * pw_impl_node_get_user_data(struct pw_impl_node *node);
-+
-+/** Get the context of this node */
-+struct pw_context *pw_impl_node_get_context(struct pw_impl_node *node);
-+
-+/** Get the global of this node */
-+struct pw_global *pw_impl_node_get_global(struct pw_impl_node *node);
-+
-+/** Get the node properties */
-+const struct pw_properties *pw_impl_node_get_properties(struct pw_impl_node *node);
-+
-+/** Update the node properties */
-+int pw_impl_node_update_properties(struct pw_impl_node *node, const struct spa_dict *dict);
-+
-+/** Set the node implementation */
-+int pw_impl_node_set_implementation(struct pw_impl_node *node, struct spa_node *spa_node);
-+
-+/** Get the node implementation */
-+struct spa_node *pw_impl_node_get_implementation(struct pw_impl_node *node);
-+
-+/** Add an event listener */
-+void pw_impl_node_add_listener(struct pw_impl_node *node,
-+ struct spa_hook *listener,
-+ const struct pw_impl_node_events *events,
-+ void *data);
-+
-+/** Iterate the ports in the given direction. The callback should return
-+ * 0 to fetch the next item, any other value stops the iteration and returns
-+ * the value. When all callbacks return 0, this function returns 0 when all
-+ * items are iterated. */
-+int pw_impl_node_for_each_port(struct pw_impl_node *node,
-+ enum pw_direction direction,
-+ int (*callback) (void *data, struct pw_impl_port *port),
-+ void *data);
-+
-+int pw_impl_node_for_each_param(struct pw_impl_node *node,
-+ int seq, uint32_t param_id,
-+ uint32_t index, uint32_t max,
-+ const struct spa_pod *filter,
-+ int (*callback) (void *data, int seq,
-+ uint32_t id, uint32_t index, uint32_t next,
-+ struct spa_pod *param),
-+ void *data);
-+
-+/** Find the port with direction and port_id or NULL when not found. Passing
-+ * PW_ID_ANY for port_id will return any port, preferably an unlinked one. */
-+struct pw_impl_port *
-+pw_impl_node_find_port(struct pw_impl_node *node, enum pw_direction direction, uint32_t port_id);
-+
-+/** Get a free unused port_id from the node */
-+uint32_t pw_impl_node_get_free_port_id(struct pw_impl_node *node, enum pw_direction direction);
-+
-+int pw_impl_node_initialized(struct pw_impl_node *node);
-+
-+/** Set a node active. This will start negotiation with all linked active
-+ * nodes and start data transport */
-+int pw_impl_node_set_active(struct pw_impl_node *node, bool active);
-+
-+/** Check if a node is active */
-+bool pw_impl_node_is_active(struct pw_impl_node *node);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_NODE_H */
-diff --git a/third_party/pipewire/pipewire/impl-port.h b/third_party/pipewire/pipewire/impl-port.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl-port.h
-@@ -0,0 +1,138 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_PORT_H
-+#define PIPEWIRE_IMPL_PORT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+/** \page page_port Port
-+ *
-+ * \section page_node_overview Overview
-+ *
-+ * A port can be used to link two nodes.
-+ */
-+/** \class pw_impl_port
-+ *
-+ * The port object
-+ */
-+struct pw_impl_port;
-+struct pw_impl_link;
-+struct pw_control;
-+
-+#include <pipewire/impl.h>
-+
-+enum pw_impl_port_state {
-+ PW_IMPL_PORT_STATE_ERROR = -1, /**< the port is in error */
-+ PW_IMPL_PORT_STATE_INIT = 0, /**< the port is being created */
-+ PW_IMPL_PORT_STATE_CONFIGURE = 1, /**< the port is ready for format negotiation */
-+ PW_IMPL_PORT_STATE_READY = 2, /**< the port is ready for buffer allocation */
-+ PW_IMPL_PORT_STATE_PAUSED = 3, /**< the port is paused */
-+};
-+
-+/** Port events, use \ref pw_impl_port_add_listener */
-+struct pw_impl_port_events {
-+#define PW_VERSION_IMPL_PORT_EVENTS 1
-+ uint32_t version;
-+
-+ /** The port is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** The port is freed */
-+ void (*free) (void *data);
-+
-+ /** The port is initialized */
-+ void (*initialized) (void *data);
-+
-+ /** the port info changed */
-+ void (*info_changed) (void *data, const struct pw_port_info *info);
-+
-+ /** a new link is added on this port */
-+ void (*link_added) (void *data, struct pw_impl_link *link);
-+
-+ /** a link is removed from this port */
-+ void (*link_removed) (void *data, struct pw_impl_link *link);
-+
-+ /** the state of the port changed */
-+ void (*state_changed) (void *data, enum pw_impl_port_state old,
-+ enum pw_impl_port_state state, const char *error);
-+
-+ /** a control was added to the port */
-+ void (*control_added) (void *data, struct pw_control *control);
-+
-+ /** a control was removed from the port */
-+ void (*control_removed) (void *data, struct pw_control *control);
-+
-+ /** a parameter changed, since version 1 */
-+ void (*param_changed) (void *data, uint32_t id);
-+};
-+
-+/** Create a new port \memberof pw_impl_port
-+ * \return a newly allocated port */
-+struct pw_impl_port *
-+pw_context_create_port(struct pw_context *context,
-+ enum pw_direction direction,
-+ uint32_t port_id,
-+ const struct spa_port_info *info,
-+ size_t user_data_size);
-+
-+/** Get the port direction */
-+enum pw_direction pw_impl_port_get_direction(struct pw_impl_port *port);
-+
-+/** Get the port properties */
-+const struct pw_properties *pw_impl_port_get_properties(struct pw_impl_port *port);
-+
-+/** Update the port properties */
-+int pw_impl_port_update_properties(struct pw_impl_port *port, const struct spa_dict *dict);
-+
-+/** Get the port info */
-+const struct pw_port_info *pw_impl_port_get_info(struct pw_impl_port *port);
-+
-+/** Get the port id */
-+uint32_t pw_impl_port_get_id(struct pw_impl_port *port);
-+
-+/** Get the port parent node or NULL when not yet set */
-+struct pw_impl_node *pw_impl_port_get_node(struct pw_impl_port *port);
-+
-+/** check is a port has links, return 0 if not, 1 if it is linked */
-+int pw_impl_port_is_linked(struct pw_impl_port *port);
-+
-+/** Add a port to a node \memberof pw_impl_port */
-+int pw_impl_port_add(struct pw_impl_port *port, struct pw_impl_node *node);
-+
-+/** Add an event listener on the port */
-+void pw_impl_port_add_listener(struct pw_impl_port *port,
-+ struct spa_hook *listener,
-+ const struct pw_impl_port_events *events,
-+ void *data);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_PORT_H */
-diff --git a/third_party/pipewire/pipewire/impl.h b/third_party/pipewire/pipewire/impl.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/impl.h
-@@ -0,0 +1,57 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_IMPL_H
-+#define PIPEWIRE_IMPL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+struct pw_impl_client;
-+struct pw_impl_module;
-+struct pw_global;
-+struct pw_node;
-+struct pw_impl_port;
-+struct pw_resource;
-+
-+#include <pipewire/pipewire.h>
-+#include <pipewire/control.h>
-+#include <pipewire/impl-core.h>
-+#include <pipewire/impl-client.h>
-+#include <pipewire/impl-device.h>
-+#include <pipewire/impl-factory.h>
-+#include <pipewire/global.h>
-+#include <pipewire/impl-link.h>
-+#include <pipewire/impl-module.h>
-+#include <pipewire/impl-node.h>
-+#include <pipewire/impl-port.h>
-+#include <pipewire/resource.h>
-+#include <pipewire/work-queue.h>
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_IMPL_H */
-diff --git a/third_party/pipewire/pipewire/keys.h b/third_party/pipewire/pipewire/keys.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/keys.h
-@@ -0,0 +1,278 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_KEYS_H
-+#define PIPEWIRE_KEYS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * A collection of keys that are used to add extra information on objects.
-+ *
-+ * Keys that start with "pipewire." are in general set-once and then
-+ * read-only. They are usually used for security sensitive information that
-+ * needs to be fixed.
-+ *
-+ * Properties from other objects can also appear. This usually suggests some
-+ * sort of parent/child or owner/owned relationship.
-+ */
-+#define PW_KEY_PROTOCOL "pipewire.protocol" /**< protocol used for connection */
-+#define PW_KEY_ACCESS "pipewire.access" /**< how the client access is controlled */
-+
-+/** Various keys related to the identity of a client process and its security.
-+ * Must be obtained from trusted sources by the protocol and placed as
-+ * read-only properties. */
-+#define PW_KEY_SEC_PID "pipewire.sec.pid" /**< Client pid, set by protocol */
-+#define PW_KEY_SEC_UID "pipewire.sec.uid" /**< Client uid, set by protocol*/
-+#define PW_KEY_SEC_GID "pipewire.sec.gid" /**< client gid, set by protocol*/
-+#define PW_KEY_SEC_LABEL "pipewire.sec.label" /**< client security label, set by protocol*/
-+
-+#define PW_KEY_LIBRARY_NAME_SYSTEM "library.name.system" /**< name of the system library to use */
-+#define PW_KEY_LIBRARY_NAME_LOOP "library.name.loop" /**< name of the loop library to use */
-+#define PW_KEY_LIBRARY_NAME_DBUS "library.name.dbus" /**< name of the dbus library to use */
-+
-+#define PW_KEY_OBJECT_PATH "object.path" /**< unique path to construct the object */
-+#define PW_KEY_OBJECT_ID "object.id" /**< a global object id */
-+
-+/* context */
-+#define PW_KEY_CONTEXT_PROFILE_MODULES "context.profile.modules" /**< a context profile for modules */
-+#define PW_KEY_USER_NAME "context.user-name" /**< The user name that runs pipewire */
-+#define PW_KEY_HOST_NAME "context.host-name" /**< The host name of the machine */
-+
-+/* core */
-+#define PW_KEY_CORE_NAME "core.name" /**< The name of the core. Default is
-+ * pipewire-<user-name>-<pid>, overwritten
-+ * by env(PIPEWIRE_CORE) */
-+#define PW_KEY_CORE_VERSION "core.version" /**< The version of the core. */
-+#define PW_KEY_CORE_DAEMON "core.daemon" /**< If the core is listening for connections. */
-+
-+#define PW_KEY_CORE_ID "core.id" /**< the core id */
-+#define PW_KEY_CORE_MONITORS "core.monitors" /**< the apis monitored by core. */
-+
-+/* cpu */
-+#define PW_KEY_CPU_MAX_ALIGN "cpu.max-align" /**< maximum alignment needed to support
-+ * all CPU optimizations */
-+#define PW_KEY_CPU_CORES "cpu.cores" /**< number of cores */
-+
-+/* priorities */
-+#define PW_KEY_PRIORITY_SESSION "priority.session" /**< priority in session manager */
-+#define PW_KEY_PRIORITY_DRIVER "priority.driver" /**< priority to be a driver */
-+
-+/* remote keys */
-+#define PW_KEY_REMOTE_NAME "remote.name" /**< The name of the remote to connect to,
-+ * default pipewire-0, overwritten by
-+ * env(PIPEWIRE_REMOTE) */
-+#define PW_KEY_REMOTE_INTENTION "remote.intention" /**< The intention of the remote connection,
-+ * "generic", "screencast" */
-+
-+/** application keys */
-+#define PW_KEY_APP_NAME "application.name" /**< application name. Ex: "Totem Music Player" */
-+#define PW_KEY_APP_ID "application.id" /**< a textual id for identifying an
-+ * application logically. Ex: "org.gnome.Totem" */
-+#define PW_KEY_APP_VERSION "application.version"
-+#define PW_KEY_APP_ICON "application.icon" /**< aa base64 blob with PNG image data */
-+#define PW_KEY_APP_ICON_NAME "application.icon-name" /**< an XDG icon name for the application.
-+ * Ex: "totem" */
-+#define PW_KEY_APP_LANGUAGE "application.language" /**< application language if applicable, in
-+ * standard POSIX format. Ex: "en_GB" */
-+
-+#define PW_KEY_APP_PROCESS_ID "application.process.id" /**< process id (pid)*/
-+#define PW_KEY_APP_PROCESS_BINARY "application.process.binary" /**< binary name */
-+#define PW_KEY_APP_PROCESS_USER "application.process.user" /**< user name */
-+#define PW_KEY_APP_PROCESS_HOST "application.process.host" /**< host name */
-+#define PW_KEY_APP_PROCESS_MACHINE_ID "application.process.machine-id" /**< the D-Bus host id the
-+ * application runs on */
-+#define PW_KEY_APP_PROCESS_SESSION_ID "application.process.session-id" /**< login session of the
-+ * application, on Unix the
-+ * value of $XDG_SESSION_ID. */
-+/** window system */
-+#define PW_KEY_WINDOW_X11_DISPLAY "window.x11.display" /**< the X11 display string. Ex. ":0.0" */
-+
-+/** Client properties */
-+#define PW_KEY_CLIENT_ID "client.id" /**< a client id */
-+#define PW_KEY_CLIENT_NAME "client.name" /**< the client name */
-+#define PW_KEY_CLIENT_API "client.api" /**< the client api used to access
-+ * PipeWire */
-+
-+/** Node keys */
-+#define PW_KEY_NODE_ID "node.id" /**< node id */
-+#define PW_KEY_NODE_NAME "node.name" /**< node name */
-+#define PW_KEY_NODE_NICK "node.nick" /**< short node name */
-+#define PW_KEY_NODE_DESCRIPTION "node.description" /**< localized human readable node one-line
-+ * description. Ex. "Foobar USB Headset" */
-+#define PW_KEY_NODE_PLUGGED "node.plugged" /**< when the node was created. As a uint64 in
-+ * nanoseconds. */
-+
-+#define PW_KEY_NODE_SESSION "node.session" /**< the session id this node is part of */
-+#define PW_KEY_NODE_GROUP "node.group" /**< the group id this node is part of. Nodes
-+ * in the same group are always scheduled
-+ * with the same driver. */
-+#define PW_KEY_NODE_EXCLUSIVE "node.exclusive" /**< node wants exclusive access to resources */
-+#define PW_KEY_NODE_AUTOCONNECT "node.autoconnect" /**< node wants to be automatically connected
-+ * to a compatible node */
-+#define PW_KEY_NODE_TARGET "node.target" /**< node wants to be connected to the target
-+ * node/session */
-+#define PW_KEY_NODE_LATENCY "node.latency" /**< the requested latency of the node as
-+ * a fraction. Ex: 128/48000 */
-+#define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node */
-+#define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */
-+#define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */
-+#define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */
-+#define PW_KEY_NODE_STREAM "node.stream" /**< node is a stream, the server side should
-+ * add a converter */
-+/** Port keys */
-+#define PW_KEY_PORT_ID "port.id" /**< port id */
-+#define PW_KEY_PORT_NAME "port.name" /**< port name */
-+#define PW_KEY_PORT_DIRECTION "port.direction" /**< the port direction, one of "in" or "out"
-+ * or "control" and "notify" for control ports */
-+#define PW_KEY_PORT_ALIAS "port.alias" /**< port alias */
-+#define PW_KEY_PORT_PHYSICAL "port.physical" /**< if this is a physical port */
-+#define PW_KEY_PORT_TERMINAL "port.terminal" /**< if this port consumes the data */
-+#define PW_KEY_PORT_CONTROL "port.control" /**< if this port is a control port */
-+#define PW_KEY_PORT_MONITOR "port.monitor" /**< if this port is a monitor port */
-+
-+/** link properties */
-+#define PW_KEY_LINK_ID "link.id" /**< a link id */
-+#define PW_KEY_LINK_INPUT_NODE "link.input.node" /**< input node id of a link */
-+#define PW_KEY_LINK_INPUT_PORT "link.input.port" /**< input port id of a link */
-+#define PW_KEY_LINK_OUTPUT_NODE "link.output.node" /**< output node id of a link */
-+#define PW_KEY_LINK_OUTPUT_PORT "link.output.port" /**< output port id of a link */
-+#define PW_KEY_LINK_PASSIVE "link.passive" /**< indicate that a link is passive and
-+ * does not cause the graph to be
-+ * runnable. */
-+/** device properties */
-+#define PW_KEY_DEVICE_ID "device.id" /**< device id */
-+#define PW_KEY_DEVICE_NAME "device.name" /**< device name */
-+#define PW_KEY_DEVICE_PLUGGED "device.plugged" /**< when the device was created. As a uint64 in
-+ * nanoseconds. */
-+#define PW_KEY_DEVICE_NICK "device.nick" /**< a short device nickname */
-+#define PW_KEY_DEVICE_STRING "device.string" /**< device string in the underlying layer's
-+ * format. Ex. "surround51:0" */
-+#define PW_KEY_DEVICE_API "device.api" /**< API this device is accessed with.
-+ * Ex. "alsa", "v4l2" */
-+#define PW_KEY_DEVICE_DESCRIPTION "device.description" /**< localized human readable device one-line
-+ * description. Ex. "Foobar USB Headset" */
-+#define PW_KEY_DEVICE_BUS_PATH "device.bus-path" /**< bus path to the device in the OS'
-+ * format. Ex. "pci-0000:00:14.0-usb-0:3.2:1.0" */
-+#define PW_KEY_DEVICE_SERIAL "device.serial" /**< Serial number if applicable */
-+#define PW_KEY_DEVICE_VENDOR_ID "device.vendor.id" /**< vendor ID if applicable */
-+#define PW_KEY_DEVICE_VENDOR_NAME "device.vendor.name" /**< vendor name if applicable */
-+#define PW_KEY_DEVICE_PRODUCT_ID "device.product.id" /**< product ID if applicable */
-+#define PW_KEY_DEVICE_PRODUCT_NAME "device.product.name" /**< product name if applicable */
-+#define PW_KEY_DEVICE_CLASS "device.class" /**< device class */
-+#define PW_KEY_DEVICE_FORM_FACTOR "device.form-factor" /**< form factor if applicable. One of
-+ * "internal", "speaker", "handset", "tv",
-+ * "webcam", "microphone", "headset",
-+ * "headphone", "hands-free", "car", "hifi",
-+ * "computer", "portable" */
-+#define PW_KEY_DEVICE_BUS "device.bus" /**< bus of the device if applicable. One of
-+ * "isa", "pci", "usb", "firewire",
-+ * "bluetooth" */
-+#define PW_KEY_DEVICE_SUBSYSTEM "device.subsystem" /**< device subsystem */
-+#define PW_KEY_DEVICE_ICON "device.icon" /**< icon for the device. A base64 blob
-+ * containing PNG image data */
-+#define PW_KEY_DEVICE_ICON_NAME "device.icon-name" /**< an XDG icon name for the device.
-+ * Ex. "sound-card-speakers-usb" */
-+#define PW_KEY_DEVICE_INTENDED_ROLES "device.intended-roles" /**< intended use. A space separated list of
-+ * roles (see PW_KEY_MEDIA_ROLE) this device
-+ * is particularly well suited for, due to
-+ * latency, quality or form factor. */
-+
-+/** module properties */
-+#define PW_KEY_MODULE_ID "module.id" /**< the module id */
-+#define PW_KEY_MODULE_NAME "module.name" /**< the name of the module */
-+#define PW_KEY_MODULE_AUTHOR "module.author" /**< the author's name */
-+#define PW_KEY_MODULE_DESCRIPTION "module.description" /**< a human readable one-line description
-+ * of the module's purpose.*/
-+#define PW_KEY_MODULE_USAGE "module.usage" /**< a human readable usage description of
-+ * the module's arguments. */
-+#define PW_KEY_MODULE_VERSION "module.version" /**< a version string for the module. */
-+
-+/** Factory properties */
-+#define PW_KEY_FACTORY_ID "factory.id" /**< the factory id */
-+#define PW_KEY_FACTORY_NAME "factory.name" /**< the name of the factory */
-+#define PW_KEY_FACTORY_USAGE "factory.usage" /**< the usage of the factory */
-+#define PW_KEY_FACTORY_TYPE_NAME "factory.type.name" /**< the name of the type created by a factory */
-+#define PW_KEY_FACTORY_TYPE_VERSION "factory.type.version" /**< the version of the type created by a factory */
-+
-+/** Stream properties */
-+#define PW_KEY_STREAM_IS_LIVE "stream.is-live" /**< Indicates that the stream is live. */
-+#define PW_KEY_STREAM_LATENCY_MIN "stream.latency.min" /**< The minimum latency of the stream. */
-+#define PW_KEY_STREAM_LATENCY_MAX "stream.latency.max" /**< The maximum latency of the stream */
-+#define PW_KEY_STREAM_MONITOR "stream.monitor" /**< Indicates that the stream is monitoring
-+ * and might select a less accurate but faster
-+ * conversion algorithm. */
-+#define PW_KEY_STREAM_DONT_REMIX "stream.dont-remix" /**< don't remix channels */
-+
-+/** object properties */
-+#define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client
-+ * that created it has been destroyed */
-+
-+/** Media */
-+#define PW_KEY_MEDIA_TYPE "media.type" /**< Media type, one of
-+ * Audio, Video, Midi */
-+#define PW_KEY_MEDIA_CATEGORY "media.category" /**< Media Category:
-+ * Playback, Capture, Duplex, Monitor */
-+#define PW_KEY_MEDIA_ROLE "media.role" /**< Role: Movie, Music, Camera,
-+ * Screen, Communication, Game,
-+ * Notification, DSP, Production,
-+ * Accessibility, Test */
-+#define PW_KEY_MEDIA_CLASS "media.class" /**< class Ex: "Video/Source" */
-+#define PW_KEY_MEDIA_NAME "media.name" /**< media name. Ex: "Pink Floyd: Time" */
-+#define PW_KEY_MEDIA_TITLE "media.title" /**< title. Ex: "Time" */
-+#define PW_KEY_MEDIA_ARTIST "media.artist" /**< artist. Ex: "Pink Floyd" */
-+#define PW_KEY_MEDIA_COPYRIGHT "media.copyright" /**< copyright string */
-+#define PW_KEY_MEDIA_SOFTWARE "media.software" /**< generator software */
-+#define PW_KEY_MEDIA_LANGUAGE "media.language" /**< language in POSIX format. Ex: en_GB */
-+#define PW_KEY_MEDIA_FILENAME "media.filename" /**< filename */
-+#define PW_KEY_MEDIA_ICON "media.icon" /**< icon for the media, a base64 blob with
-+ * PNG image data */
-+#define PW_KEY_MEDIA_ICON_NAME "media.icon-name" /**< an XDG icon name for the media.
-+ * Ex: "audio-x-mp3" */
-+
-+/** format related properties */
-+#define PW_KEY_FORMAT_DSP "format.dsp" /**< a dsp format.
-+ * Ex: "32 bit float mono audio" */
-+/** audio related properties */
-+#define PW_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel. Ex: "FL" */
-+#define PW_KEY_AUDIO_RATE "audio.samplerate" /**< an audio samplerate */
-+#define PW_KEY_AUDIO_CHANNELS "audio.channels" /**< number of audio channels */
-+#define PW_KEY_AUDIO_FORMAT "audio.format" /**< an audio format. Ex: "S16LE" */
-+
-+/** video related properties */
-+#define PW_KEY_VIDEO_RATE "video.framerate" /**< a video framerate */
-+#define PW_KEY_VIDEO_FORMAT "video.format" /**< a video format */
-+#define PW_KEY_VIDEO_SIZE "video.size" /**< a video size as "<width>x<height" */
-+
-+#ifdef PW_ENABLE_DEPRECATED
-+#define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated */
-+#endif /* PW_ENABLE_DEPRECATED */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_KEYS_H */
-diff --git a/third_party/pipewire/pipewire/link.h b/third_party/pipewire/pipewire/link.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/link.h
-@@ -0,0 +1,124 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_LINK_H
-+#define PIPEWIRE_LINK_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+#include <pipewire/proxy.h>
-+
-+#define PW_TYPE_INTERFACE_Link PW_TYPE_INFO_INTERFACE_BASE "Link"
-+
-+#define PW_VERSION_LINK 3
-+struct pw_link;
-+
-+/** \enum pw_link_state The different link states \memberof pw_link */
-+enum pw_link_state {
-+ PW_LINK_STATE_ERROR = -2, /**< the link is in error */
-+ PW_LINK_STATE_UNLINKED = -1, /**< the link is unlinked */
-+ PW_LINK_STATE_INIT = 0, /**< the link is initialized */
-+ PW_LINK_STATE_NEGOTIATING = 1, /**< the link is negotiating formats */
-+ PW_LINK_STATE_ALLOCATING = 2, /**< the link is allocating buffers */
-+ PW_LINK_STATE_PAUSED = 3, /**< the link is paused */
-+};
-+
-+/** Convert a \ref pw_link_state to a readable string \memberof pw_link */
-+const char * pw_link_state_as_string(enum pw_link_state state);
-+/** The link information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_link_info {
-+ uint32_t id; /**< id of the global */
-+ uint32_t output_node_id; /**< server side output node id */
-+ uint32_t output_port_id; /**< output port id */
-+ uint32_t input_node_id; /**< server side input node id */
-+ uint32_t input_port_id; /**< input port id */
-+#define PW_LINK_CHANGE_MASK_STATE (1 << 0)
-+#define PW_LINK_CHANGE_MASK_FORMAT (1 << 1)
-+#define PW_LINK_CHANGE_MASK_PROPS (1 << 2)
-+#define PW_LINK_CHANGE_MASK_ALL ((1 << 3)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ enum pw_link_state state; /**< the current state of the link */
-+ const char *error; /**< an error reason if \a state is error */
-+ struct spa_pod *format; /**< format over link */
-+ struct spa_dict *props; /**< the properties of the link */
-+};
-+
-+struct pw_link_info *
-+pw_link_info_update(struct pw_link_info *info,
-+ const struct pw_link_info *update);
-+
-+void
-+pw_link_info_free(struct pw_link_info *info);
-+
-+
-+#define PW_LINK_EVENT_INFO 0
-+#define PW_LINK_EVENT_NUM 1
-+
-+/** Link events */
-+struct pw_link_events {
-+#define PW_VERSION_LINK_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify link info
-+ *
-+ * \param info info about the link
-+ */
-+ void (*info) (void *object, const struct pw_link_info *info);
-+};
-+
-+#define PW_LINK_METHOD_ADD_LISTENER 0
-+#define PW_LINK_METHOD_NUM 1
-+
-+/** Link methods */
-+struct pw_link_methods {
-+#define PW_VERSION_LINK_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_link_events *events,
-+ void *data);
-+};
-+
-+#define pw_link_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_link_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_link_add_listener(c,...) pw_link_method(c,add_listener,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_LINK_H */
-diff --git a/third_party/pipewire/pipewire/log.h b/third_party/pipewire/pipewire/log.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/log.h
-@@ -0,0 +1,97 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_LOG_H
-+#define PIPEWIRE_LOG_H
-+
-+#include <spa/support/log.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_log
-+ *
-+ * Logging functions of PipeWire
-+ *
-+ * Logging is performed to stdout and stderr. Trace logging is performed
-+ * in a lockfree ringbuffer and written out from the main thread as to not
-+ * block the realtime threads.
-+ */
-+
-+/** The global log level */
-+extern enum spa_log_level pw_log_level;
-+
-+/** Configure a logging module. This is usually done automatically
-+ * in pw_init() but you can install a custom logger before calling
-+ * pw_init(). */
-+void pw_log_set(struct spa_log *log);
-+
-+/** Get the log interface */
-+struct spa_log *pw_log_get(void);
-+
-+/** Configure the logging level */
-+void pw_log_set_level(enum spa_log_level level);
-+
-+
-+/** Log a message */
-+void
-+pw_log_log(enum spa_log_level level,
-+ const char *file,
-+ int line, const char *func,
-+ const char *fmt, ...) SPA_PRINTF_FUNC(5, 6);
-+
-+/** Log a message */
-+void
-+pw_log_logv(enum spa_log_level level,
-+ const char *file,
-+ int line, const char *func,
-+ const char *fmt, va_list args) SPA_PRINTF_FUNC(5, 0);
-+
-+
-+/** Check if a loglevel is enabled \memberof pw_log */
-+#define pw_log_level_enabled(lev) (pw_log_level >= (lev))
-+
-+#define pw_log(lev,...) \
-+({ \
-+ if (SPA_UNLIKELY(pw_log_level_enabled (lev))) \
-+ pw_log_log(lev,__FILE__,__LINE__,__func__,__VA_ARGS__); \
-+})
-+
-+#define pw_log_error(...) pw_log(SPA_LOG_LEVEL_ERROR,__VA_ARGS__)
-+#define pw_log_warn(...) pw_log(SPA_LOG_LEVEL_WARN,__VA_ARGS__)
-+#define pw_log_info(...) pw_log(SPA_LOG_LEVEL_INFO,__VA_ARGS__)
-+#define pw_log_debug(...) pw_log(SPA_LOG_LEVEL_DEBUG,__VA_ARGS__)
-+#define pw_log_trace(...) pw_log(SPA_LOG_LEVEL_TRACE,__VA_ARGS__)
-+
-+#ifndef FASTPATH
-+#define pw_log_trace_fp(...) pw_log(SPA_LOG_LEVEL_TRACE,__VA_ARGS__)
-+#else
-+#define pw_log_trace_fp(...)
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+#endif /* PIPEWIRE_LOG_H */
-diff --git a/third_party/pipewire/pipewire/loop.h b/third_party/pipewire/pipewire/loop.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/loop.h
-@@ -0,0 +1,80 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_LOOP_H
-+#define PIPEWIRE_LOOP_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/support/loop.h>
-+#include <spa/utils/dict.h>
-+
-+/** \class pw_loop
-+ *
-+ * PipeWire loop object provides an implementation of
-+ * the spa loop interfaces. It can be used to implement various
-+ * event loops.
-+ */
-+struct pw_loop {
-+ struct spa_system *system; /**< system utils */
-+ struct spa_loop *loop; /**< wrapped loop */
-+ struct spa_loop_control *control; /**< loop control */
-+ struct spa_loop_utils *utils; /**< loop utils */
-+};
-+
-+struct pw_loop *
-+pw_loop_new(const struct spa_dict *props);
-+
-+void
-+pw_loop_destroy(struct pw_loop *loop);
-+
-+#define pw_loop_add_source(l,...) spa_loop_add_source((l)->loop,__VA_ARGS__)
-+#define pw_loop_update_source(l,...) spa_loop_update_source(__VA_ARGS__)
-+#define pw_loop_remove_source(l,...) spa_loop_remove_source(__VA_ARGS__)
-+#define pw_loop_invoke(l,...) spa_loop_invoke((l)->loop,__VA_ARGS__)
-+
-+#define pw_loop_get_fd(l) spa_loop_control_get_fd((l)->control)
-+#define pw_loop_add_hook(l,...) spa_loop_control_add_hook((l)->control,__VA_ARGS__)
-+#define pw_loop_enter(l) spa_loop_control_enter((l)->control)
-+#define pw_loop_iterate(l,...) spa_loop_control_iterate((l)->control,__VA_ARGS__)
-+#define pw_loop_leave(l) spa_loop_control_leave((l)->control)
-+
-+#define pw_loop_add_io(l,...) spa_loop_utils_add_io((l)->utils,__VA_ARGS__)
-+#define pw_loop_update_io(l,...) spa_loop_utils_update_io((l)->utils,__VA_ARGS__)
-+#define pw_loop_add_idle(l,...) spa_loop_utils_add_idle((l)->utils,__VA_ARGS__)
-+#define pw_loop_enable_idle(l,...) spa_loop_utils_enable_idle((l)->utils,__VA_ARGS__)
-+#define pw_loop_add_event(l,...) spa_loop_utils_add_event((l)->utils,__VA_ARGS__)
-+#define pw_loop_signal_event(l,...) spa_loop_utils_signal_event((l)->utils,__VA_ARGS__)
-+#define pw_loop_add_timer(l,...) spa_loop_utils_add_timer((l)->utils,__VA_ARGS__)
-+#define pw_loop_update_timer(l,...) spa_loop_utils_update_timer((l)->utils,__VA_ARGS__)
-+#define pw_loop_add_signal(l,...) spa_loop_utils_add_signal((l)->utils,__VA_ARGS__)
-+#define pw_loop_destroy_source(l,...) spa_loop_utils_destroy_source((l)->utils,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_LOOP_H */
-diff --git a/third_party/pipewire/pipewire/main-loop.h b/third_party/pipewire/pipewire/main-loop.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/main-loop.h
-@@ -0,0 +1,78 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_MAIN_LOOP_H
-+#define PIPEWIRE_MAIN_LOOP_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_main_loop
-+ *
-+ * \brief PipeWire main-loop interface.
-+ *
-+ * A main loop object
-+ */
-+/** A main loop object \memberof pw_main_loop */
-+struct pw_main_loop;
-+
-+#include <pipewire/loop.h>
-+
-+/** Events of the main loop */
-+struct pw_main_loop_events {
-+#define PW_VERSION_MAIN_LOOP_EVENTS 0
-+ uint32_t version;
-+
-+ /** Emitted when the main loop is destroyed */
-+ void (*destroy) (void *data);
-+};
-+
-+/** Create a new main loop. */
-+struct pw_main_loop *
-+pw_main_loop_new(const struct spa_dict *props);
-+
-+/** Add an event listener */
-+void pw_main_loop_add_listener(struct pw_main_loop *loop,
-+ struct spa_hook *listener,
-+ const struct pw_main_loop_events *events,
-+ void *data);
-+
-+/** Get the loop implementation */
-+struct pw_loop * pw_main_loop_get_loop(struct pw_main_loop *loop);
-+
-+/** Destroy a loop */
-+void pw_main_loop_destroy(struct pw_main_loop *loop);
-+
-+/** Run a main loop. This blocks until \ref pw_main_loop_quit is called */
-+int pw_main_loop_run(struct pw_main_loop *loop);
-+
-+/** Quit a main loop */
-+int pw_main_loop_quit(struct pw_main_loop *loop);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_MAIN_LOOP_H */
-diff --git a/third_party/pipewire/pipewire/map.h b/third_party/pipewire/pipewire/map.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/map.h
-@@ -0,0 +1,206 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_MAP_H
-+#define PIPEWIRE_MAP_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <string.h>
-+#include <errno.h>
-+
-+#include <spa/utils/defs.h>
-+#include <pipewire/array.h>
-+
-+/** \class pw_map
-+ *
-+ * A map that holds objects indexed by id
-+ */
-+
-+/** An entry in the map \memberof pw_map */
-+union pw_map_item {
-+ uint32_t next; /**< next free index */
-+ void *data; /**< data of this item, must be an even address */
-+};
-+
-+/** A map \memberof pw_map */
-+struct pw_map {
-+ struct pw_array items; /**< an array with the map items */
-+ uint32_t free_list; /**< the free items */
-+};
-+
-+#define PW_MAP_INIT(extend) (struct pw_map) { PW_ARRAY_INIT(extend), 0 }
-+
-+#define pw_map_get_size(m) pw_array_get_len(&(m)->items, union pw_map_item)
-+#define pw_map_get_item(m,id) pw_array_get_unchecked(&(m)->items,id,union pw_map_item)
-+#define pw_map_item_is_free(item) ((item)->next & 0x1)
-+#define pw_map_id_is_free(m,id) (pw_map_item_is_free(pw_map_get_item(m,id)))
-+#define pw_map_check_id(m,id) ((id) < pw_map_get_size(m))
-+#define pw_map_has_item(m,id) (pw_map_check_id(m,id) && !pw_map_id_is_free(m, id))
-+#define pw_map_lookup_unchecked(m,id) pw_map_get_item(m,id)->data
-+
-+/** Convert an id to a pointer that can be inserted into the map \memberof pw_map */
-+#define PW_MAP_ID_TO_PTR(id) (SPA_UINT32_TO_PTR((id)<<1))
-+/** Convert a pointer to an id that can be retrieved from the map \memberof pw_map */
-+#define PW_MAP_PTR_TO_ID(p) (SPA_PTR_TO_UINT32(p)>>1)
-+
-+/** Initialize a map
-+ * \param map the map to initialize
-+ * \param size the initial size of the map
-+ * \param extend the amount to bytes to grow the map with when needed
-+ * \memberof pw_map
-+ */
-+static inline void pw_map_init(struct pw_map *map, size_t size, size_t extend)
-+{
-+ pw_array_init(&map->items, extend);
-+ pw_array_ensure_size(&map->items, size * sizeof(union pw_map_item));
-+ map->free_list = SPA_ID_INVALID;
-+}
-+
-+/** Clear a map
-+ * \param map the map to clear
-+ * \memberof pw_map
-+ */
-+static inline void pw_map_clear(struct pw_map *map)
-+{
-+ pw_array_clear(&map->items);
-+}
-+
-+static inline void pw_map_reset(struct pw_map *map)
-+{
-+ pw_array_reset(&map->items);
-+ map->free_list = SPA_ID_INVALID;
-+}
-+
-+/** Insert data in the map
-+ * \param map the map to insert into
-+ * \param data the item to add
-+ * \return the id where the item was inserted or SPA_ID_INVALID when the
-+ * item can not be inserted.
-+ * \memberof pw_map
-+ */
-+static inline uint32_t pw_map_insert_new(struct pw_map *map, void *data)
-+{
-+ union pw_map_item *start, *item;
-+ uint32_t id;
-+
-+ if (map->free_list != SPA_ID_INVALID) {
-+ start = (union pw_map_item *) map->items.data;
-+ item = &start[map->free_list >> 1];
-+ map->free_list = item->next;
-+ } else {
-+ item = (union pw_map_item *) pw_array_add(&map->items, sizeof(union pw_map_item));
-+ if (item == NULL)
-+ return SPA_ID_INVALID;
-+ start = (union pw_map_item *) map->items.data;
-+ }
-+ item->data = data;
-+ id = (item - start);
-+ return id;
-+}
-+
-+/** Insert data in the map at an index
-+ * \param map the map to inser into
-+ * \param id the index to insert at
-+ * \param data the data to insert
-+ * \return 0 on success, -ENOSPC value when the index is invalid or a < 0
-+ * errno value.
-+ * \memberof pw_map
-+ */
-+static inline int pw_map_insert_at(struct pw_map *map, uint32_t id, void *data)
-+{
-+ size_t size = pw_map_get_size(map);
-+ union pw_map_item *item;
-+
-+ if (id > size)
-+ return -ENOSPC;
-+ else if (id == size) {
-+ item = (union pw_map_item *) pw_array_add(&map->items, sizeof(union pw_map_item));
-+ if (item == NULL)
-+ return -errno;
-+ }
-+ else {
-+ item = pw_map_get_item(map, id);
-+ }
-+ item->data = data;
-+ return 0;
-+}
-+
-+/** Remove an item at index
-+ * \param map the map to remove from
-+ * \param id the index to remove
-+ * \memberof pw_map
-+ */
-+static inline void pw_map_remove(struct pw_map *map, uint32_t id)
-+{
-+ pw_map_get_item(map, id)->next = map->free_list;
-+ map->free_list = (id << 1) | 1;
-+}
-+
-+/** Find an item in the map
-+ * \param map the map to use
-+ * \param id the index to look at
-+ * \return the item at \a id or NULL when no such item exists
-+ * \memberof pw_map
-+ */
-+static inline void *pw_map_lookup(struct pw_map *map, uint32_t id)
-+{
-+ if (SPA_LIKELY(pw_map_check_id(map, id))) {
-+ union pw_map_item *item = pw_map_get_item(map, id);
-+ if (!pw_map_item_is_free(item))
-+ return item->data;
-+ }
-+ return NULL;
-+}
-+
-+/** Iterate all map items
-+ * \param map the map to iterate
-+ * \param func the function to call for each item, the item data and \a data is
-+ * passed to the function. When \a func returns a non-zero result,
-+ * iteration ends and the result is returned.
-+ * \param data data to pass to \a func
-+ * \return the result of the last call to \a func or 0 when all callbacks returned 0.
-+ * \memberof pw_map
-+ */
-+static inline int pw_map_for_each(struct pw_map *map,
-+ int (*func) (void *item_data, void *data), void *data)
-+{
-+ union pw_map_item *item;
-+ int res = 0;
-+
-+ pw_array_for_each(item, &map->items) {
-+ if (!pw_map_item_is_free(item))
-+ if ((res = func(item->data, data)) != 0)
-+ break;
-+ }
-+ return res;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_MAP_H */
-diff --git a/third_party/pipewire/pipewire/mem.h b/third_party/pipewire/pipewire/mem.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/mem.h
-@@ -0,0 +1,199 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_MEM_H
-+#define PIPEWIRE_MEM_H
-+
-+#include <pipewire/properties.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** Flags passed to \ref pw_mempool_alloc() \memberof pw_memblock */
-+enum pw_memblock_flags {
-+ PW_MEMBLOCK_FLAG_NONE = 0,
-+ PW_MEMBLOCK_FLAG_READABLE = (1 << 0), /**< memory is readable */
-+ PW_MEMBLOCK_FLAG_WRITABLE = (1 << 1), /**< memory is writable */
-+ PW_MEMBLOCK_FLAG_SEAL = (1 << 2), /**< seal the fd */
-+ PW_MEMBLOCK_FLAG_MAP = (1 << 3), /**< mmap the fd */
-+ PW_MEMBLOCK_FLAG_DONT_CLOSE = (1 << 4), /**< don't close fd */
-+ PW_MEMBLOCK_FLAG_DONT_NOTIFY = (1 << 5), /**< don't notify events */
-+
-+ PW_MEMBLOCK_FLAG_READWRITE = PW_MEMBLOCK_FLAG_READABLE | PW_MEMBLOCK_FLAG_WRITABLE,
-+};
-+
-+enum pw_memmap_flags {
-+ PW_MEMMAP_FLAG_NONE = 0,
-+ PW_MEMMAP_FLAG_READ = (1 << 0), /**< map in read mode */
-+ PW_MEMMAP_FLAG_WRITE = (1 << 1), /**< map in write mode */
-+ PW_MEMMAP_FLAG_TWICE = (1 << 2), /**< map the same area twice after each other,
-+ * creating a circular ringbuffer */
-+ PW_MEMMAP_FLAG_PRIVATE = (1 << 3), /**< writes will be private */
-+ PW_MEMMAP_FLAG_READWRITE = PW_MEMMAP_FLAG_READ | PW_MEMMAP_FLAG_WRITE,
-+};
-+
-+struct pw_memchunk;
-+
-+/** \class pw_memblock
-+ *
-+ * A memory pool is a collection of pw_memblocks */
-+struct pw_mempool {
-+ struct pw_properties *props;
-+};
-+
-+/** \class pw_memblock
-+ * Memory block structure */
-+struct pw_memblock {
-+ struct pw_mempool *pool; /**< owner pool */
-+ uint32_t id; /**< unique id */
-+ int ref; /**< refcount */
-+ uint32_t flags; /**< flags for the memory block on of enum pw_memblock_flags */
-+ uint32_t type; /**< type of the fd, one of enum spa_data_type */
-+ int fd; /**< fd */
-+ uint32_t size; /**< size of memory */
-+ struct pw_memmap *map; /**< optional map when PW_MEMBLOCK_FLAG_MAP was given */
-+};
-+
-+/** a mapped region of a pw_memblock */
-+struct pw_memmap {
-+ struct pw_memblock *block; /**< owner memblock */
-+ void *ptr; /**< mapped pointer */
-+ uint32_t flags; /**< flags for the mapping on of enum pw_memmap_flags */
-+ uint32_t offset; /**< offset in memblock */
-+ uint32_t size; /**< size in memblock */
-+ uint32_t tag[5]; /**< user tag */
-+};
-+
-+struct pw_mempool_events {
-+#define PW_VERSION_MEMPOOL_EVENTS 0
-+ uint32_t version;
-+
-+ /** the pool is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** a new memory block is added to the pool */
-+ void (*added) (void *data, struct pw_memblock *block);
-+
-+ /** a memory block is removed from the pool */
-+ void (*removed) (void *data, struct pw_memblock *block);
-+};
-+
-+/** Create a new memory pool */
-+struct pw_mempool *pw_mempool_new(struct pw_properties *props);
-+
-+/** Listen for events */
-+void pw_mempool_add_listener(struct pw_mempool *pool,
-+ struct spa_hook *listener,
-+ const struct pw_mempool_events *events,
-+ void *data);
-+
-+/** Clear a pool */
-+void pw_mempool_clear(struct pw_mempool *pool);
-+
-+/** Clear and destroy a pool */
-+void pw_mempool_destroy(struct pw_mempool *pool);
-+
-+
-+/** Allocate a memory block from the pool */
-+struct pw_memblock * pw_mempool_alloc(struct pw_mempool *pool,
-+ enum pw_memblock_flags flags, uint32_t type, size_t size);
-+
-+/** Import a block from another pool */
-+struct pw_memblock * pw_mempool_import_block(struct pw_mempool *pool,
-+ struct pw_memblock *mem);
-+
-+/** Import an fd into the pool */
-+struct pw_memblock * pw_mempool_import(struct pw_mempool *pool,
-+ enum pw_memblock_flags flags, uint32_t type, int fd);
-+
-+/** Free a memblock regardless of the refcount and destroy all mappings */
-+void pw_memblock_free(struct pw_memblock *mem);
-+
-+/** Unref a memblock */
-+static inline void pw_memblock_unref(struct pw_memblock *mem)
-+{
-+ if (--mem->ref == 0)
-+ pw_memblock_free(mem);
-+}
-+
-+/** Remove a memblock for given \a id */
-+int pw_mempool_remove_id(struct pw_mempool *pool, uint32_t id);
-+
-+/** Find memblock for given \a ptr */
-+struct pw_memblock * pw_mempool_find_ptr(struct pw_mempool *pool, const void *ptr);
-+
-+/** Find memblock for given \a id */
-+struct pw_memblock * pw_mempool_find_id(struct pw_mempool *pool, uint32_t id);
-+
-+/** Find memblock for given \a fd */
-+struct pw_memblock * pw_mempool_find_fd(struct pw_mempool *pool, int fd);
-+
-+
-+/** Map a region of a memory block */
-+struct pw_memmap * pw_memblock_map(struct pw_memblock *block,
-+ enum pw_memmap_flags flags, uint32_t offset, uint32_t size,
-+ uint32_t tag[5]);
-+
-+/** Map a region of a memory block with \a id */
-+struct pw_memmap * pw_mempool_map_id(struct pw_mempool *pool, uint32_t id,
-+ enum pw_memmap_flags flags, uint32_t offset, uint32_t size,
-+ uint32_t tag[5]);
-+
-+struct pw_memmap * pw_mempool_import_map(struct pw_mempool *pool,
-+ struct pw_mempool *other, void *data, uint32_t size, uint32_t tag[5]);
-+
-+/** find a map with the given tag */
-+struct pw_memmap * pw_mempool_find_tag(struct pw_mempool *pool, uint32_t tag[5], size_t size);
-+
-+/** Unmap a region */
-+int pw_memmap_free(struct pw_memmap *map);
-+
-+
-+/** parameters to map a memory range */
-+struct pw_map_range {
-+ uint32_t start; /** offset in first page with start of data */
-+ uint32_t offset; /** page aligned offset to map */
-+ uint32_t size; /** size to map */
-+};
-+
-+#define PW_MAP_RANGE_INIT (struct pw_map_range){ 0, }
-+
-+/** Calculate parameters to mmap() memory into \a range so that
-+ * \a size bytes at \a offset can be mapped with mmap(). */
-+static inline void pw_map_range_init(struct pw_map_range *range,
-+ uint32_t offset, uint32_t size,
-+ uint32_t page_size)
-+{
-+ range->offset = SPA_ROUND_DOWN_N(offset, page_size);
-+ range->start = offset - range->offset;
-+ range->size = SPA_ROUND_UP_N(range->start + size, page_size);
-+}
-+
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_MEM_H */
-diff --git a/third_party/pipewire/pipewire/module.h b/third_party/pipewire/pipewire/module.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/module.h
-@@ -0,0 +1,106 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_MODULE_H
-+#define PIPEWIRE_MODULE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+#include <pipewire/proxy.h>
-+
-+#define PW_TYPE_INTERFACE_Module PW_TYPE_INFO_INTERFACE_BASE "Module"
-+
-+#define PW_VERSION_MODULE 3
-+struct pw_module;
-+
-+/** The module information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_module_info {
-+ uint32_t id; /**< id of the global */
-+ const char *name; /**< name of the module */
-+ const char *filename; /**< filename of the module */
-+ const char *args; /**< arguments passed to the module */
-+#define PW_MODULE_CHANGE_MASK_PROPS (1 << 0)
-+#define PW_MODULE_CHANGE_MASK_ALL ((1 << 1)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ struct spa_dict *props; /**< extra properties */
-+};
-+
-+/** Update and existing \ref pw_module_info with \a update \memberof pw_introspect */
-+struct pw_module_info *
-+pw_module_info_update(struct pw_module_info *info,
-+ const struct pw_module_info *update);
-+
-+/** Free a \ref pw_module_info \memberof pw_introspect */
-+void pw_module_info_free(struct pw_module_info *info);
-+
-+#define PW_MODULE_EVENT_INFO 0
-+#define PW_MODULE_EVENT_NUM 1
-+
-+/** Module events */
-+struct pw_module_events {
-+#define PW_VERSION_MODULE_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify module info
-+ *
-+ * \param info info about the module
-+ */
-+ void (*info) (void *object, const struct pw_module_info *info);
-+};
-+
-+#define PW_MODULE_METHOD_ADD_LISTENER 0
-+#define PW_MODULE_METHOD_NUM 1
-+
-+/** Module methods */
-+struct pw_module_methods {
-+#define PW_VERSION_MODULE_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_module_events *events,
-+ void *data);
-+};
-+
-+#define pw_module_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_module_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_module_add_listener(c,...) pw_module_method(c,add_listener,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_MODULE_H */
-diff --git a/third_party/pipewire/pipewire/node.h b/third_party/pipewire/pipewire/node.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/node.h
-@@ -0,0 +1,200 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_NODE_H
-+#define PIPEWIRE_NODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+#include <errno.h>
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+#include <spa/node/command.h>
-+#include <spa/param/param.h>
-+
-+#include <pipewire/proxy.h>
-+
-+#define PW_TYPE_INTERFACE_Node PW_TYPE_INFO_INTERFACE_BASE "Node"
-+
-+#define PW_VERSION_NODE 3
-+struct pw_node;
-+
-+/** \enum pw_node_state The different node states \memberof pw_node */
-+enum pw_node_state {
-+ PW_NODE_STATE_ERROR = -1, /**< error state */
-+ PW_NODE_STATE_CREATING = 0, /**< the node is being created */
-+ PW_NODE_STATE_SUSPENDED = 1, /**< the node is suspended, the device might
-+ * be closed */
-+ PW_NODE_STATE_IDLE = 2, /**< the node is running but there is no active
-+ * port */
-+ PW_NODE_STATE_RUNNING = 3, /**< the node is running */
-+};
-+
-+/** Convert a \ref pw_node_state to a readable string \memberof pw_node */
-+const char * pw_node_state_as_string(enum pw_node_state state);
-+
-+/** The node information. Extra information can be added in later versions \memberof pw_introspect */
-+struct pw_node_info {
-+ uint32_t id; /**< id of the global */
-+ uint32_t max_input_ports; /**< maximum number of inputs */
-+ uint32_t max_output_ports; /**< maximum number of outputs */
-+#define PW_NODE_CHANGE_MASK_INPUT_PORTS (1 << 0)
-+#define PW_NODE_CHANGE_MASK_OUTPUT_PORTS (1 << 1)
-+#define PW_NODE_CHANGE_MASK_STATE (1 << 2)
-+#define PW_NODE_CHANGE_MASK_PROPS (1 << 3)
-+#define PW_NODE_CHANGE_MASK_PARAMS (1 << 4)
-+#define PW_NODE_CHANGE_MASK_ALL ((1 << 5)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ uint32_t n_input_ports; /**< number of inputs */
-+ uint32_t n_output_ports; /**< number of outputs */
-+ enum pw_node_state state; /**< the current state of the node */
-+ const char *error; /**< an error reason if \a state is error */
-+ struct spa_dict *props; /**< the properties of the node */
-+ struct spa_param_info *params; /**< parameters */
-+ uint32_t n_params; /**< number of items in \a params */
-+};
-+
-+struct pw_node_info *
-+pw_node_info_update(struct pw_node_info *info,
-+ const struct pw_node_info *update);
-+
-+void
-+pw_node_info_free(struct pw_node_info *info);
-+
-+#define PW_NODE_EVENT_INFO 0
-+#define PW_NODE_EVENT_PARAM 1
-+#define PW_NODE_EVENT_NUM 2
-+
-+/** Node events */
-+struct pw_node_events {
-+#define PW_VERSION_NODE_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify node info
-+ *
-+ * \param info info about the node
-+ */
-+ void (*info) (void *object, const struct pw_node_info *info);
-+ /**
-+ * Notify a node param
-+ *
-+ * Event emitted as a result of the enum_params method.
-+ *
-+ * \param seq the sequence number of the request
-+ * \param id the param id
-+ * \param index the param index
-+ * \param next the param index of the next param
-+ * \param param the parameter
-+ */
-+ void (*param) (void *object, int seq,
-+ uint32_t id, uint32_t index, uint32_t next,
-+ const struct spa_pod *param);
-+};
-+
-+#define PW_NODE_METHOD_ADD_LISTENER 0
-+#define PW_NODE_METHOD_SUBSCRIBE_PARAMS 1
-+#define PW_NODE_METHOD_ENUM_PARAMS 2
-+#define PW_NODE_METHOD_SET_PARAM 3
-+#define PW_NODE_METHOD_SEND_COMMAND 4
-+#define PW_NODE_METHOD_NUM 5
-+
-+/** Node methods */
-+struct pw_node_methods {
-+#define PW_VERSION_NODE_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_node_events *events,
-+ void *data);
-+ /**
-+ * Subscribe to parameter changes
-+ *
-+ * Automatically emit param events for the given ids when
-+ * they are changed.
-+ *
-+ * \param ids an array of param ids
-+ * \param n_ids the number of ids in \a ids
-+ */
-+ int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
-+
-+ /**
-+ * Enumerate node parameters
-+ *
-+ * Start enumeration of node parameters. For each param, a
-+ * param event will be emitted.
-+ *
-+ * \param seq a sequence number to place in the reply
-+ * \param id the parameter id to enum or PW_ID_ANY for all
-+ * \param start the start index or 0 for the first param
-+ * \param num the maximum number of params to retrieve
-+ * \param filter a param filter or NULL
-+ */
-+ int (*enum_params) (void *object, int seq, uint32_t id,
-+ uint32_t start, uint32_t num,
-+ const struct spa_pod *filter);
-+
-+ /**
-+ * Set a parameter on the node
-+ *
-+ * \param id the parameter id to set
-+ * \param flags extra parameter flags
-+ * \param param the parameter to set
-+ */
-+ int (*set_param) (void *object, uint32_t id, uint32_t flags,
-+ const struct spa_pod *param);
-+
-+ /**
-+ * Send a command to the node
-+ *
-+ * \param command the command to send
-+ */
-+ int (*send_command) (void *object, const struct spa_command *command);
-+};
-+
-+#define pw_node_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_node_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+/** Node */
-+#define pw_node_add_listener(c,...) pw_node_method(c,add_listener,0,__VA_ARGS__)
-+#define pw_node_subscribe_params(c,...) pw_node_method(c,subscribe_params,0,__VA_ARGS__)
-+#define pw_node_enum_params(c,...) pw_node_method(c,enum_params,0,__VA_ARGS__)
-+#define pw_node_set_param(c,...) pw_node_method(c,set_param,0,__VA_ARGS__)
-+#define pw_node_send_command(c,...) pw_node_method(c,send_command,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_NODE_H */
-diff --git a/third_party/pipewire/pipewire/permission.h b/third_party/pipewire/pipewire/permission.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/permission.h
-@@ -0,0 +1,79 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_PERMISSION_H
-+#define PIPEWIRE_PERMISSION_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+
-+/** \class pw_permission
-+ *
-+ * \brief a PipeWire permission
-+ *
-+ * Permissions are kept for a client and describe what the client is
-+ * allowed to do with an object.
-+ *
-+ * See \ref page_core_api
-+ */
-+
-+#define PW_PERM_R 0400 /**< object can be seen and events can be received */
-+#define PW_PERM_W 0200 /**< methods can be called that modify the object */
-+#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
-+ * present in order to call methods that modify the object. */
-+#define PW_PERM_M 0010 /**< metadata can be set on object, Since 0.3.9 */
-+
-+#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
-+#define PW_PERM_RWXM (PW_PERM_RWX|PW_PERM_M)
-+
-+#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
-+#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
-+#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
-+#define PW_PERM_IS_M(p) (((p)&PW_PERM_M) == PW_PERM_M)
-+
-+#define PW_PERM_ALL PW_PERM_RWXM
-+#define PW_PERM_INVALID (uint32_t)(0xffffffff)
-+
-+struct pw_permission {
-+ uint32_t id; /**< id of object, PW_ID_ANY for default permission */
-+ uint32_t permissions; /**< bitmask of above permissions */
-+};
-+
-+#define PW_PERMISSION_INIT(id,p) (struct pw_permission){ (id), (p) }
-+
-+#define PW_PERMISSION_FORMAT "%c%c%c%c"
-+#define PW_PERMISSION_ARGS(permission) \
-+ (permission) & PW_PERM_R ? 'r' : '-', \
-+ (permission) & PW_PERM_W ? 'w' : '-', \
-+ (permission) & PW_PERM_X ? 'x' : '-', \
-+ (permission) & PW_PERM_M ? 'm' : '-'
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_PERMISSION_H */
-diff --git a/third_party/pipewire/pipewire/pipewire.h b/third_party/pipewire/pipewire/pipewire.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/pipewire.h
-@@ -0,0 +1,158 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_H
-+#define PIPEWIRE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/support/plugin.h>
-+
-+#include <pipewire/array.h>
-+#include <pipewire/client.h>
-+#include <pipewire/context.h>
-+#include <pipewire/device.h>
-+#include <pipewire/buffers.h>
-+#include <pipewire/core.h>
-+#include <pipewire/factory.h>
-+#include <pipewire/keys.h>
-+#include <pipewire/log.h>
-+#include <pipewire/loop.h>
-+#include <pipewire/link.h>
-+#include <pipewire/main-loop.h>
-+#include <pipewire/map.h>
-+#include <pipewire/mem.h>
-+#include <pipewire/module.h>
-+#include <pipewire/node.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/proxy.h>
-+#include <pipewire/permission.h>
-+#include <pipewire/protocol.h>
-+#include <pipewire/port.h>
-+#include <pipewire/stream.h>
-+#include <pipewire/filter.h>
-+#include <pipewire/thread-loop.h>
-+#include <pipewire/data-loop.h>
-+#include <pipewire/type.h>
-+#include <pipewire/utils.h>
-+#include <pipewire/version.h>
-+
-+/** \mainpage
-+ *
-+ * \section sec_intro Introduction
-+ *
-+ * This document describes the API for the PipeWire multimedia framework.
-+ * The API consists of two parts:
-+ *
-+ * \li The core API to access a PipeWire instance.
-+ * (See \subpage page_core_api)
-+ * \li The implementation API and tools to build new objects and
-+ * modules (See \subpage page_implementation_api)
-+ *
-+ * \section sec_errors Error reporting
-+ *
-+ * Functions return either NULL with errno set or a negative int error
-+ * code when an error occurs. Error codes are used from the SPA plugin
-+ * library on which PipeWire is built.
-+ *
-+ * Some functions might return asynchronously. The error code for such
-+ * functions is positive and SPA_RESULT_IS_ASYNC() will return true.
-+ * SPA_RESULT_ASYNC_SEQ() can be used to get the unique sequence number
-+ * associated with the async operation.
-+ *
-+ * The object returning the async result code will have some way to
-+ * signal the completion of the async operation (with, for example, a
-+ * callback). The sequence number can be used to see which operation
-+ * completed.
-+ *
-+ * \section sec_logging Logging
-+ *
-+ * The 'PIPEWIRE_DEBUG' environment variable can be used to enable
-+ * more debugging. The format is:
-+ *
-+ * &lt;level&gt;[:&lt;category&gt;,...]
-+ *
-+ * - &lt;level&gt;: specifies the log level:
-+ * + `0`: no logging is enabled
-+ * + `1`: Error logging is enabled
-+ * + `2`: Warnings are enabled
-+ * + `3`: Informational messages are enabled
-+ * + `4`: Debug messages are enabled
-+ * + `5`: Trace messages are enabled. These messages can be logged
-+ * from the realtime threads.
-+ *
-+ * - &lt;category&gt;: Specifies a string category to enable. Many categories
-+ * can be separated by commas. Current categories are:
-+ * + `connection`: to log connection messages
-+ */
-+
-+/** \class pw_pipewire
-+ *
-+ * \brief PipeWire initialization and infrastructure functions
-+ */
-+void
-+pw_init(int *argc, char **argv[]);
-+
-+void pw_deinit(void);
-+
-+bool
-+pw_debug_is_category_enabled(const char *name);
-+
-+const char *
-+pw_get_application_name(void);
-+
-+const char *
-+pw_get_prgname(void);
-+
-+const char *
-+pw_get_user_name(void);
-+
-+const char *
-+pw_get_host_name(void);
-+
-+const char *
-+pw_get_client_name(void);
-+
-+bool pw_in_valgrind(void);
-+
-+enum pw_direction
-+pw_direction_reverse(enum pw_direction direction);
-+
-+uint32_t pw_get_support(struct spa_support *support, uint32_t max_support);
-+
-+struct spa_handle *pw_load_spa_handle(const char *lib,
-+ const char *factory_name,
-+ const struct spa_dict *info,
-+ uint32_t n_support,
-+ const struct spa_support support[]);
-+
-+int pw_unload_spa_handle(struct spa_handle *handle);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_H */
-diff --git a/third_party/pipewire/pipewire/port.h b/third_party/pipewire/pipewire/port.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/port.h
-@@ -0,0 +1,169 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_PORT_H
-+#define PIPEWIRE_PORT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+#include <errno.h>
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+#include <spa/param/param.h>
-+
-+#include <pipewire/proxy.h>
-+
-+#define PW_TYPE_INTERFACE_Port PW_TYPE_INFO_INTERFACE_BASE "Port"
-+
-+#define PW_VERSION_PORT 3
-+struct pw_port;
-+
-+/** \enum pw_direction The direction of a port \memberof pw_introspect */
-+#define pw_direction spa_direction
-+#define PW_DIRECTION_INPUT SPA_DIRECTION_INPUT
-+#define PW_DIRECTION_OUTPUT SPA_DIRECTION_OUTPUT
-+
-+/** Convert a \ref pw_direction to a readable string \memberof pw_introspect */
-+const char * pw_direction_as_string(enum pw_direction direction);
-+
-+
-+/** \class pw_introspect
-+ *
-+ * The introspection methods and structures are used to get information
-+ * about the object in the PipeWire server
-+ */
-+
-+struct pw_port_info {
-+ uint32_t id; /**< id of the global */
-+ enum pw_direction direction; /**< port direction */
-+#define PW_PORT_CHANGE_MASK_PROPS (1 << 0)
-+#define PW_PORT_CHANGE_MASK_PARAMS (1 << 1)
-+#define PW_PORT_CHANGE_MASK_ALL ((1 << 2)-1)
-+ uint64_t change_mask; /**< bitfield of changed fields since last call */
-+ struct spa_dict *props; /**< the properties of the port */
-+ struct spa_param_info *params; /**< parameters */
-+ uint32_t n_params; /**< number of items in \a params */
-+};
-+
-+struct pw_port_info *
-+pw_port_info_update(struct pw_port_info *info,
-+ const struct pw_port_info *update);
-+
-+void
-+pw_port_info_free(struct pw_port_info *info);
-+
-+#define PW_PORT_EVENT_INFO 0
-+#define PW_PORT_EVENT_PARAM 1
-+#define PW_PORT_EVENT_NUM 2
-+
-+/** Port events */
-+struct pw_port_events {
-+#define PW_VERSION_PORT_EVENTS 0
-+ uint32_t version;
-+ /**
-+ * Notify port info
-+ *
-+ * \param info info about the port
-+ */
-+ void (*info) (void *object, const struct pw_port_info *info);
-+ /**
-+ * Notify a port param
-+ *
-+ * Event emitted as a result of the enum_params method.
-+ *
-+ * \param seq the sequence number of the request
-+ * \param id the param id
-+ * \param index the param index
-+ * \param next the param index of the next param
-+ * \param param the parameter
-+ */
-+ void (*param) (void *object, int seq,
-+ uint32_t id, uint32_t index, uint32_t next,
-+ const struct spa_pod *param);
-+};
-+
-+#define PW_PORT_METHOD_ADD_LISTENER 0
-+#define PW_PORT_METHOD_SUBSCRIBE_PARAMS 1
-+#define PW_PORT_METHOD_ENUM_PARAMS 2
-+#define PW_PORT_METHOD_NUM 3
-+
-+/** Port methods */
-+struct pw_port_methods {
-+#define PW_VERSION_PORT_METHODS 0
-+ uint32_t version;
-+
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct pw_port_events *events,
-+ void *data);
-+ /**
-+ * Subscribe to parameter changes
-+ *
-+ * Automatically emit param events for the given ids when
-+ * they are changed.
-+ *
-+ * \param ids an array of param ids
-+ * \param n_ids the number of ids in \a ids
-+ */
-+ int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
-+
-+ /**
-+ * Enumerate port parameters
-+ *
-+ * Start enumeration of port parameters. For each param, a
-+ * param event will be emitted.
-+ *
-+ * \param seq a sequence number returned in the reply
-+ * \param id the parameter id to enumerate
-+ * \param start the start index or 0 for the first param
-+ * \param num the maximum number of params to retrieve
-+ * \param filter a param filter or NULL
-+ */
-+ int (*enum_params) (void *object, int seq,
-+ uint32_t id, uint32_t start, uint32_t num,
-+ const struct spa_pod *filter);
-+};
-+
-+#define pw_port_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)o, \
-+ struct pw_port_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define pw_port_add_listener(c,...) pw_port_method(c,add_listener,0,__VA_ARGS__)
-+#define pw_port_subscribe_params(c,...) pw_port_method(c,subscribe_params,0,__VA_ARGS__)
-+#define pw_port_enum_params(c,...) pw_port_method(c,enum_params,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_PORT_H */
-diff --git a/third_party/pipewire/pipewire/properties.h b/third_party/pipewire/pipewire/properties.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/properties.h
-@@ -0,0 +1,121 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_PROPERTIES_H
-+#define PIPEWIRE_PROPERTIES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+
-+#include <spa/utils/dict.h>
-+
-+/** \class pw_properties
-+ *
-+ * \brief A collection of key/value pairs
-+ *
-+ * Properties are used to pass around arbitrary key/value pairs.
-+ * Both keys and values are strings which keeps things simple.
-+ * Encoding of arbitrary values should be done by using a string
-+ * serialization such as base64 for binary blobs.
-+ */
-+struct pw_properties {
-+ struct spa_dict dict; /**< dictionary of key/values */
-+ uint32_t flags; /**< extra flags */
-+};
-+
-+struct pw_properties *
-+pw_properties_new(const char *key, ...) SPA_SENTINEL;
-+
-+struct pw_properties *
-+pw_properties_new_dict(const struct spa_dict *dict);
-+
-+struct pw_properties *
-+pw_properties_new_string(const char *args);
-+
-+struct pw_properties *
-+pw_properties_copy(const struct pw_properties *properties);
-+
-+int pw_properties_update_keys(struct pw_properties *props,
-+ const struct spa_dict *dict, const char *keys[]);
-+
-+int pw_properties_update(struct pw_properties *oldprops,
-+ const struct spa_dict *dict);
-+
-+int pw_properties_add(struct pw_properties *oldprops,
-+ const struct spa_dict *dict);
-+int pw_properties_add_keys(struct pw_properties *oldprops,
-+ const struct spa_dict *dict, const char *keys[]);
-+
-+void pw_properties_clear(struct pw_properties *properties);
-+
-+void
-+pw_properties_free(struct pw_properties *properties);
-+
-+int
-+pw_properties_set(struct pw_properties *properties, const char *key, const char *value);
-+
-+int
-+pw_properties_setf(struct pw_properties *properties,
-+ const char *key, const char *format, ...) SPA_PRINTF_FUNC(3, 4);
-+int
-+pw_properties_setva(struct pw_properties *properties,
-+ const char *key, const char *format, va_list args) SPA_PRINTF_FUNC(3,0);
-+const char *
-+pw_properties_get(const struct pw_properties *properties, const char *key);
-+
-+const char *
-+pw_properties_iterate(const struct pw_properties *properties, void **state);
-+
-+static inline bool pw_properties_parse_bool(const char *value) {
-+ return (strcmp(value, "true") == 0 || atoi(value) == 1);
-+}
-+
-+static inline int pw_properties_parse_int(const char *value) {
-+ return strtol(value, NULL, 0);
-+}
-+
-+static inline int64_t pw_properties_parse_int64(const char *value) {
-+ return strtoll(value, NULL, 0);
-+}
-+
-+static inline uint64_t pw_properties_parse_uint64(const char *value) {
-+ return strtoull(value, NULL, 0);
-+}
-+
-+static inline float pw_properties_parse_float(const char *value) {
-+ return strtof(value, NULL);
-+}
-+
-+static inline double pw_properties_parse_double(const char *value) {
-+ return strtod(value, NULL);
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_PROPERTIES_H */
-diff --git a/third_party/pipewire/pipewire/protocol.h b/third_party/pipewire/pipewire/protocol.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/protocol.h
-@@ -0,0 +1,152 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_PROTOCOL_H
-+#define PIPEWIRE_PROTOCOL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/list.h>
-+
-+struct pw_protocol;
-+
-+#include <pipewire/context.h>
-+#include <pipewire/properties.h>
-+#include <pipewire/utils.h>
-+
-+#define PW_TYPE_INFO_Protocol "PipeWire:Protocol"
-+#define PW_TYPE_INFO_PROTOCOL_BASE PW_TYPE_INFO_Protocol ":"
-+
-+struct pw_protocol_client {
-+ struct spa_list link; /**< link in protocol client_list */
-+ struct pw_protocol *protocol; /**< the owner protocol */
-+
-+ struct pw_core *core;
-+
-+ int (*connect) (struct pw_protocol_client *client,
-+ const struct spa_dict *props,
-+ void (*done_callback) (void *data, int result),
-+ void *data);
-+ int (*connect_fd) (struct pw_protocol_client *client, int fd, bool close);
-+ int (*steal_fd) (struct pw_protocol_client *client);
-+ void (*disconnect) (struct pw_protocol_client *client);
-+ void (*destroy) (struct pw_protocol_client *client);
-+ int (*set_paused) (struct pw_protocol_client *client, bool paused);
-+};
-+
-+#define pw_protocol_client_connect(c,p,cb,d) ((c)->connect(c,p,cb,d))
-+#define pw_protocol_client_connect_fd(c,fd,cl) ((c)->connect_fd(c,fd,cl))
-+#define pw_protocol_client_steal_fd(c) ((c)->steal_fd(c))
-+#define pw_protocol_client_disconnect(c) ((c)->disconnect(c))
-+#define pw_protocol_client_destroy(c) ((c)->destroy(c))
-+#define pw_protocol_client_set_paused(c,p) ((c)->set_paused(c,p))
-+
-+struct pw_protocol_server {
-+ struct spa_list link; /**< link in protocol server_list */
-+ struct pw_protocol *protocol; /**< the owner protocol */
-+
-+ struct pw_impl_core *core;
-+
-+ struct spa_list client_list; /**< list of clients of this protocol */
-+
-+ void (*destroy) (struct pw_protocol_server *listen);
-+};
-+
-+#define pw_protocol_server_destroy(l) ((l)->destroy(l))
-+
-+struct pw_protocol_marshal {
-+ const char *type; /**< interface type */
-+ uint32_t version; /**< version */
-+#define PW_PROTOCOL_MARSHAL_FLAG_IMPL (1 << 0) /**< marshal for implementations */
-+ uint32_t flags; /**< version */
-+ uint32_t n_client_methods; /**< number of client methods */
-+ uint32_t n_server_methods; /**< number of server methods */
-+ const void *client_marshal;
-+ const void *server_demarshal;
-+ const void *server_marshal;
-+ const void *client_demarshal;
-+};
-+
-+struct pw_protocol_implementaton {
-+#define PW_VERSION_PROTOCOL_IMPLEMENTATION 0
-+ uint32_t version;
-+
-+ struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
-+ struct pw_core *core,
-+ const struct spa_dict *props);
-+ struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
-+ struct pw_impl_core *core,
-+ const struct spa_dict *props);
-+};
-+
-+struct pw_protocol_events {
-+#define PW_VERSION_PROTOCOL_EVENTS 0
-+ uint32_t version;
-+
-+ void (*destroy) (void *data);
-+};
-+
-+#define pw_protocol_new_client(p,...) (pw_protocol_get_implementation(p)->new_client(p,__VA_ARGS__))
-+#define pw_protocol_add_server(p,...) (pw_protocol_get_implementation(p)->add_server(p,__VA_ARGS__))
-+#define pw_protocol_ext(p,type,method,...) (((type*)pw_protocol_get_extension(p))->method( __VA_ARGS__))
-+
-+struct pw_protocol *pw_protocol_new(struct pw_context *context, const char *name, size_t user_data_size);
-+
-+void pw_protocol_destroy(struct pw_protocol *protocol);
-+
-+struct pw_context *pw_protocol_get_context(struct pw_protocol *protocol);
-+
-+void *pw_protocol_get_user_data(struct pw_protocol *protocol);
-+
-+const struct pw_protocol_implementaton *
-+pw_protocol_get_implementation(struct pw_protocol *protocol);
-+
-+const void *
-+pw_protocol_get_extension(struct pw_protocol *protocol);
-+
-+
-+void pw_protocol_add_listener(struct pw_protocol *protocol,
-+ struct spa_hook *listener,
-+ const struct pw_protocol_events *events,
-+ void *data);
-+
-+/** \class pw_protocol
-+ *
-+ * \brief Manages protocols and their implementation
-+ */
-+int pw_protocol_add_marshal(struct pw_protocol *protocol,
-+ const struct pw_protocol_marshal *marshal);
-+
-+const struct pw_protocol_marshal *
-+pw_protocol_get_marshal(struct pw_protocol *protocol, const char *type, uint32_t version, uint32_t flags);
-+
-+struct pw_protocol * pw_context_find_protocol(struct pw_context *context, const char *name);
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_PROTOCOL_H */
-diff --git a/third_party/pipewire/pipewire/proxy.h b/third_party/pipewire/pipewire/proxy.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/proxy.h
-@@ -0,0 +1,207 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_PROXY_H
-+#define PIPEWIRE_PROXY_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+/** \page page_proxy Proxy
-+ *
-+ * \section sec_page_proxy_overview Overview
-+ *
-+ * The proxy object is a client side representation of a resource
-+ * that lives on a remote PipeWire instance.
-+ *
-+ * It is used to communicate with the remote object.
-+ *
-+ * \section sec_page_proxy_core Core proxy
-+ *
-+ * A proxy for a remote core object can be obtained by making
-+ * a remote connection with \ref pw_core_connect.
-+ * See \ref pw_page_remote_api
-+ *
-+ * Some methods on proxy object allow creation of more proxy objects or
-+ * create a binding between a local proxy and global resource.
-+ *
-+ * \section sec_page_proxy_create Create
-+ *
-+ * A client first creates a new proxy object with pw_proxy_new(). A
-+ * type must be provided for this object.
-+ *
-+ * The protocol of the context will usually install an interface to
-+ * translate method calls and events to the wire format.
-+ *
-+ * The creator of the proxy will usually also install an event
-+ * implementation of the particular object type.
-+ *
-+ * \section sec_page_proxy_bind Bind
-+ *
-+ * To actually use the proxy object, one needs to create a server
-+ * side resource for it. This can be done by, for example, binding
-+ * to a global object or by calling a method that creates and binds
-+ * to a new remote object. In all cases, the local id is passed to
-+ * the server and is used to create a resource with the same id.
-+ *
-+ * \section sec_page_proxy_methods Methods
-+ *
-+ * To call a method on the proxy use the interface methods. Calling
-+ * any interface method will result in a request to the server to
-+ * perform the requested action on the corresponding resource.
-+ *
-+ * \section sec_page_proxy_events Events
-+ *
-+ * Events send from the server to the proxy will be demarshalled by
-+ * the protocol and will then result in a call to the installed
-+ * implementation of the proxy.
-+ *
-+ * \section sec_page_proxy_destroy Destroy
-+ *
-+ * Use pw_proxy_destroy() to destroy the client side object. This
-+ * is usually done automatically when the server removes the resource
-+ * associated to the proxy.
-+ */
-+
-+/** \class pw_proxy
-+ *
-+ * \brief Represents an object on the client side.
-+ *
-+ * A pw_proxy acts as a client side proxy to an object existing in a remote
-+ * pipewire instance. The proxy is responsible for converting interface functions
-+ * invoked by the client to PipeWire messages. Events will call the handlers
-+ * set in listener.
-+ *
-+ * See \ref page_proxy
-+ */
-+struct pw_proxy;
-+
-+#include <pipewire/protocol.h>
-+
-+/** Proxy events, use \ref pw_proxy_add_listener */
-+struct pw_proxy_events {
-+#define PW_VERSION_PROXY_EVENTS 0
-+ uint32_t version;
-+
-+ /** The proxy is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** a proxy is bound to a global id */
-+ void (*bound) (void *data, uint32_t global_id);
-+
-+ /** a proxy is removed from the server. Use pw_proxy_destroy to
-+ * free the proxy. */
-+ void (*removed) (void *data);
-+
-+ /** a reply to a sync method completed */
-+ void (*done) (void *data, int seq);
-+
-+ /** an error occurred on the proxy */
-+ void (*error) (void *data, int seq, int res, const char *message);
-+};
-+
-+/** Make a new proxy object. The id can be used to bind to a remote object and
-+ * can be retrieved with \ref pw_proxy_get_id . */
-+struct pw_proxy *
-+pw_proxy_new(struct pw_proxy *factory, /**< factory */
-+ const char *type, /**< interface type */
-+ uint32_t version, /**< interface version */
-+ size_t user_data_size /**< size of user data */);
-+
-+/** Add an event listener to proxy */
-+void pw_proxy_add_listener(struct pw_proxy *proxy,
-+ struct spa_hook *listener,
-+ const struct pw_proxy_events *events,
-+ void *data);
-+
-+/** Add a listener for the events received from the remote object. The
-+ * events depend on the type of the remote object type. */
-+void pw_proxy_add_object_listener(struct pw_proxy *proxy, /**< the proxy */
-+ struct spa_hook *listener, /**< listener */
-+ const void *funcs, /**< proxied functions */
-+ void *data /**< data passed to events */);
-+
-+/** destroy a proxy */
-+void pw_proxy_destroy(struct pw_proxy *proxy);
-+
-+/** Get the user_data. The size was given in \ref pw_proxy_new */
-+void *pw_proxy_get_user_data(struct pw_proxy *proxy);
-+
-+/** Get the local id of the proxy */
-+uint32_t pw_proxy_get_id(struct pw_proxy *proxy);
-+
-+/** Get the type and version of the proxy */
-+const char *pw_proxy_get_type(struct pw_proxy *proxy, uint32_t *version);
-+
-+/** Get the protocol used for the proxy */
-+struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy);
-+
-+/** Generate an sync method for a proxy. This will generate a done event
-+ * with the same seq number of the reply. */
-+int pw_proxy_sync(struct pw_proxy *proxy, int seq);
-+
-+/** Set the global id this proxy is bound to. This is usually used internally
-+ * and will also emit the bound event */
-+int pw_proxy_set_bound_id(struct pw_proxy *proxy, uint32_t global_id);
-+/** Get the global id bound to this proxy of SPA_ID_INVALID when not bound
-+ * to a global */
-+uint32_t pw_proxy_get_bound_id(struct pw_proxy *proxy);
-+
-+/** Generate an error for a proxy */
-+int pw_proxy_error(struct pw_proxy *proxy, int res, const char *error);
-+int pw_proxy_errorf(struct pw_proxy *proxy, int res, const char *error, ...) SPA_PRINTF_FUNC(3, 4);
-+
-+/** Get the listener of proxy */
-+struct spa_hook_list *pw_proxy_get_object_listeners(struct pw_proxy *proxy);
-+
-+/** Get the marshal functions for the proxy */
-+const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy);
-+
-+/** Install a marshal function on a proxy */
-+int pw_proxy_install_marshal(struct pw_proxy *proxy, bool implementor);
-+
-+#define pw_proxy_notify(p,type,event,version,...) \
-+ spa_hook_list_call(pw_proxy_get_object_listeners(p), \
-+ type, event, version, ## __VA_ARGS__)
-+
-+#define pw_proxy_call(p,type,method,version,...) \
-+ spa_interface_call((struct spa_interface*)p, \
-+ type, method, version, ##__VA_ARGS__)
-+
-+#define pw_proxy_call_res(p,type,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)p, \
-+ type, _res, method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_PROXY_H */
-diff --git a/third_party/pipewire/pipewire/resource.h b/third_party/pipewire/pipewire/resource.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/resource.h
-@@ -0,0 +1,168 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_RESOURCE_H
-+#define PIPEWIRE_RESOURCE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/hook.h>
-+
-+/** \page page_resource Resource
-+ *
-+ * \section sec_page_resource Overview
-+ *
-+ * Resources represent objects owned by a \ref pw_impl_client. They are
-+ * the result of binding to a global resource or by calling API that
-+ * creates client owned objects.
-+ *
-+ * The client usually has a proxy object associated with the resource
-+ * that it can use to communicate with the resource. See \ref page_proxy.
-+ *
-+ * Resources are destroyed when the client or the bound object is
-+ * destroyed.
-+ *
-+ */
-+
-+/** \class pw_resource
-+ *
-+ * \brief Client owned objects
-+ *
-+ * Resources are objects owned by a client and are destroyed when the
-+ * client disappears.
-+ *
-+ * See also \ref page_resource
-+ */
-+struct pw_resource;
-+
-+#include <pipewire/impl-client.h>
-+
-+/** Resource events */
-+struct pw_resource_events {
-+#define PW_VERSION_RESOURCE_EVENTS 0
-+ uint32_t version;
-+
-+ /** The resource is destroyed */
-+ void (*destroy) (void *data);
-+
-+ /** a reply to a ping event completed */
-+ void (*pong) (void *data, int seq);
-+
-+ /** an error occurred on the resource */
-+ void (*error) (void *data, int seq, int res, const char *message);
-+};
-+
-+/** Make a new resource for client */
-+struct pw_resource *
-+pw_resource_new(struct pw_impl_client *client, /**< the client owning the resource */
-+ uint32_t id, /**< the remote per client id */
-+ uint32_t permissions, /**< permissions on this resource */
-+ const char *type, /**< interface of the resource */
-+ uint32_t version, /**< requested interface version */
-+ size_t user_data_size /**< extra user data size */);
-+
-+/** Destroy a resource */
-+void pw_resource_destroy(struct pw_resource *resource);
-+
-+/** Remove a resource, like pw_resource_destroy but without sending a
-+ * remove_id message to the client */
-+void pw_resource_remove(struct pw_resource *resource);
-+
-+/** Get the client owning this resource */
-+struct pw_impl_client *pw_resource_get_client(struct pw_resource *resource);
-+
-+/** Get the unique id of this resource */
-+uint32_t pw_resource_get_id(struct pw_resource *resource);
-+
-+/** Get the permissions of this resource */
-+uint32_t pw_resource_get_permissions(struct pw_resource *resource);
-+
-+/** Get the type and optionally the version of this resource */
-+const char *pw_resource_get_type(struct pw_resource *resource, uint32_t *version);
-+
-+/** Get the protocol used for this resource */
-+struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource);
-+
-+/** Get the user data for the resource, the size was given in \ref pw_resource_new */
-+void *pw_resource_get_user_data(struct pw_resource *resource);
-+
-+/** Add an event listener */
-+void pw_resource_add_listener(struct pw_resource *resource,
-+ struct spa_hook *listener,
-+ const struct pw_resource_events *events,
-+ void *data);
-+
-+/** Set the resource implementation. */
-+void pw_resource_add_object_listener(struct pw_resource *resource,
-+ struct spa_hook *listener,
-+ const void *funcs,
-+ void *data);
-+
-+/** Generate an ping event for a resource. This will generate a pong event
-+ * with the same \a sequence number in the return value. */
-+int pw_resource_ping(struct pw_resource *resource, int seq);
-+
-+/** Notify global id this resource is bound to */
-+int pw_resource_set_bound_id(struct pw_resource *resource, uint32_t global_id);
-+
-+/** Get the global id this resource is bound to or SPA_ID_INVALID when not bound */
-+uint32_t pw_resource_get_bound_id(struct pw_resource *resource);
-+
-+/** Generate an error for a resource */
-+void pw_resource_error(struct pw_resource *resource, int res, const char *error);
-+void pw_resource_errorf(struct pw_resource *resource, int res, const char *error, ...) SPA_PRINTF_FUNC(3, 4);
-+void pw_resource_errorf_id(struct pw_resource *resource, uint32_t id, int res, const char *error, ...) SPA_PRINTF_FUNC(4, 5);
-+
-+/** Get the list of object listeners from a resource */
-+struct spa_hook_list *pw_resource_get_object_listeners(struct pw_resource *resource);
-+
-+/** Get the marshal functions for the resource */
-+const struct pw_protocol_marshal *pw_resource_get_marshal(struct pw_resource *resource);
-+
-+/** install a marshal function on a resource */
-+int pw_resource_install_marshal(struct pw_resource *resource, bool implementor);
-+
-+#define pw_resource_notify(r,type,event,version,...) \
-+ spa_hook_list_call(pw_resource_get_object_listeners(r), \
-+ type, event, version, ## __VA_ARGS__)
-+
-+#define pw_resource_call(r,type,method,version,...) \
-+ spa_interface_call((struct spa_interface*)r, \
-+ type, method, version, ##__VA_ARGS__)
-+
-+#define pw_resource_call_res(r,type,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_interface_call_res((struct spa_interface*)r, \
-+ type, _res, method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_RESOURCE_H */
-diff --git a/third_party/pipewire/pipewire/stream.h b/third_party/pipewire/pipewire/stream.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/stream.h
-@@ -0,0 +1,358 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_STREAM_H
-+#define PIPEWIRE_STREAM_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \page page_streams Media Streams
-+ *
-+ * \section sec_overview Overview
-+ *
-+ * Media streams are used to exchange data with the PipeWire server. A
-+ * stream is a wrapper around a proxy for a \ref pw_client_node with
-+ * an adapter. This means the stream will automatically do conversion
-+ * to the type required by the server.
-+ *
-+ * Streams can be used to:
-+ *
-+ * \li Consume a stream from PipeWire. This is a PW_DIRECTION_INPUT stream.
-+ * \li Produce a stream to PipeWire. This is a PW_DIRECTION_OUTPUT stream
-+ *
-+ * You can connect the stream port to a specific server port or let PipeWire
-+ * choose a port for you.
-+ *
-+ * For more complicated nodes such as filters or ports with multiple
-+ * inputs and/or outputs you will need to use the pw_filter or make
-+ * a pw_node yourself and export it with \ref pw_core_export.
-+ *
-+ * \section sec_create Create
-+ *
-+ * Make a new stream with \ref pw_stream_new(). You will need to specify
-+ * a name for the stream and extra properties. You can use \ref
-+ * pw_fill_stream_properties() to get a basic set of properties for the
-+ * stream.
-+ *
-+ * Once the stream is created, the state_changed event should be used to
-+ * track the state of the stream.
-+ *
-+ * \section sec_connect Connect
-+ *
-+ * The stream is initially unconnected. To connect the stream, use
-+ * \ref pw_stream_connect(). Pass the desired direction as an argument.
-+ *
-+ * \subsection ssec_stream_target Stream target
-+ *
-+ * To make the newly connected stream automatically connect to an existing
-+ * PipeWire node, use the \ref PW_STREAM_FLAG_AUTOCONNECT and the port_path
-+ * argument while connecting.
-+ *
-+ * \subsection ssec_stream_formats Stream formats
-+ *
-+ * An array of possible formats that this stream can consume or provide
-+ * must be specified.
-+ *
-+ * \section sec_format Format negotiation
-+ *
-+ * After connecting the stream, the server will want to configure some
-+ * parameters on the stream. You will be notified of these changes
-+ * with the param_changed event.
-+ *
-+ * When a format param change is emitted, the client should now prepare
-+ * itself to deal with the format and complete the negotiation procedure
-+ * with a call to \ref pw_stream_update_params().
-+ *
-+ * As arguments to \ref pw_stream_update_params() an array of spa_param
-+ * structures must be given. They contain parameters such as buffer size,
-+ * number of buffers, required metadata and other parameters for the
-+ * media buffers.
-+ *
-+ * \section sec_buffers Buffer negotiation
-+ *
-+ * After completing the format negotiation, PipeWire will allocate and
-+ * notify the stream of the buffers that will be used to exchange data
-+ * between client and server.
-+ *
-+ * With the add_buffer event, a stream will be notified of a new buffer
-+ * that can be used for data transport. You can attach user_data to these
-+ * buffers.
-+ *
-+ * After the buffers are negotiated, the stream will transition to the
-+ * \ref PW_STREAM_STATE_PAUSED state.
-+ *
-+ * \section sec_streaming Streaming
-+ *
-+ * From the \ref PW_STREAM_STATE_PAUSED state, the stream can be set to
-+ * the \ref PW_STREAM_STATE_STREAMING state by the PipeWire server when
-+ * data transport is started.
-+ *
-+ * Depending on how the stream was connected it will need to Produce or
-+ * Consume data for/from PipeWire as explained in the following
-+ * subsections.
-+ *
-+ * \subsection ssec_consume Consume data
-+ *
-+ * The process event is emitted for each new buffer that can can be
-+ * consumed.
-+ *
-+ * \ref pw_stream_dequeue_buffer() should be used to get the data and
-+ * metadata of the buffer.
-+ *
-+ * When the buffer is no longer in use, call \ref pw_stream_queue_buffer()
-+ * to let PipeWire reuse the buffer.
-+ *
-+ * \subsection ssec_produce Produce data
-+ *
-+ * \ref pw_stream_dequeue_buffer() gives an empty buffer that can be filled.
-+ *
-+ * Filled buffers should be queued with \ref pw_stream_queue_buffer().
-+ *
-+ * The process event is emitted when PipeWire has emptied a buffer that
-+ * can now be refilled.
-+ *
-+ * \section sec_stream_disconnect Disconnect
-+ *
-+ * Use \ref pw_stream_disconnect() to disconnect a stream after use.
-+ */
-+/** \class pw_stream
-+ *
-+ * \brief PipeWire stream object class
-+ *
-+ * The stream object provides a convenient way to send and
-+ * receive data streams from/to PipeWire.
-+ *
-+ * See also \ref page_streams and \ref page_context_api
-+ */
-+struct pw_stream;
-+
-+#include <spa/buffer/buffer.h>
-+#include <spa/param/param.h>
-+
-+/** \enum pw_stream_state The state of a stream \memberof pw_stream */
-+enum pw_stream_state {
-+ PW_STREAM_STATE_ERROR = -1, /**< the stream is in error */
-+ PW_STREAM_STATE_UNCONNECTED = 0, /**< unconnected */
-+ PW_STREAM_STATE_CONNECTING = 1, /**< connection is in progress */
-+ PW_STREAM_STATE_PAUSED = 2, /**< paused */
-+ PW_STREAM_STATE_STREAMING = 3 /**< streaming */
-+};
-+
-+struct pw_buffer {
-+ struct spa_buffer *buffer; /**< the spa buffer */
-+ void *user_data; /**< user data attached to the buffer */
-+ uint64_t size; /**< This field is set by the user and the sum of
-+ * all queued buffer is returned in the time info */
-+};
-+
-+struct pw_stream_control {
-+ const char *name; /**< name of the control */
-+ uint32_t flags; /**< extra flags (unused) */
-+ float def; /**< default value */
-+ float min; /**< min value */
-+ float max; /**< max value */
-+ float *values; /**< array of values */
-+ uint32_t n_values; /**< number of values in array */
-+ uint32_t max_values; /**< max values that can be set on this control */
-+};
-+
-+/** A time structure \memberof pw_stream */
-+struct pw_time {
-+ int64_t now; /**< the monotonic time */
-+ struct spa_fraction rate; /**< the rate of \a ticks and delay */
-+ uint64_t ticks; /**< the ticks at \a now. This is the current time that
-+ * the remote end is reading/writing. */
-+ int64_t delay; /**< delay to device, add to ticks to get the time of the
-+ * device. Positive for INPUT streams and
-+ * negative for OUTPUT streams. */
-+ uint64_t queued; /**< data queued in the stream, this is the sum
-+ * of the size fields in the pw_buffer that are
-+ * currently queued */
-+};
-+
-+#include <pipewire/pipewire.h>
-+
-+/** Events for a stream. These events are always called from the mainloop
-+ * unless explicitly documented otherwise. */
-+struct pw_stream_events {
-+#define PW_VERSION_STREAM_EVENTS 0
-+ uint32_t version;
-+
-+ void (*destroy) (void *data);
-+ /** when the stream state changes */
-+ void (*state_changed) (void *data, enum pw_stream_state old,
-+ enum pw_stream_state state, const char *error);
-+
-+ /** Notify information about a control. */
-+ void (*control_info) (void *data, uint32_t id, const struct pw_stream_control *control);
-+
-+ /** when io changed on the stream. */
-+ void (*io_changed) (void *data, uint32_t id, void *area, uint32_t size);
-+ /** when a parameter changed */
-+ void (*param_changed) (void *data, uint32_t id, const struct spa_pod *param);
-+
-+ /** when a new buffer was created for this stream */
-+ void (*add_buffer) (void *data, struct pw_buffer *buffer);
-+ /** when a buffer was destroyed for this stream */
-+ void (*remove_buffer) (void *data, struct pw_buffer *buffer);
-+
-+ /** when a buffer can be queued (for playback streams) or
-+ * dequeued (for capture streams). This is normally called from the
-+ * mainloop but can also be called directly from the realtime data
-+ * thread if the user is prepared to deal with this. */
-+ void (*process) (void *data);
-+
-+ /** The stream is drained */
-+ void (*drained) (void *data);
-+
-+};
-+
-+/** Convert a stream state to a readable string \memberof pw_stream */
-+const char * pw_stream_state_as_string(enum pw_stream_state state);
-+
-+/** \enum pw_stream_flags Extra flags that can be used in \ref pw_stream_connect() \memberof pw_stream */
-+enum pw_stream_flags {
-+ PW_STREAM_FLAG_NONE = 0, /**< no flags */
-+ PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect
-+ * this stream */
-+ PW_STREAM_FLAG_INACTIVE = (1 << 1), /**< start the stream inactive,
-+ * pw_stream_set_active() needs to be
-+ * called explicitly */
-+ PW_STREAM_FLAG_MAP_BUFFERS = (1 << 2), /**< mmap the buffers */
-+ PW_STREAM_FLAG_DRIVER = (1 << 3), /**< be a driver */
-+ PW_STREAM_FLAG_RT_PROCESS = (1 << 4), /**< call process from the realtime
-+ * thread. You MUST use RT safe functions
-+ * in the process callback. */
-+ PW_STREAM_FLAG_NO_CONVERT = (1 << 5), /**< don't convert format */
-+ PW_STREAM_FLAG_EXCLUSIVE = (1 << 6), /**< require exclusive access to the
-+ * device */
-+ PW_STREAM_FLAG_DONT_RECONNECT = (1 << 7), /**< don't try to reconnect this stream
-+ * when the sink/source is removed */
-+ PW_STREAM_FLAG_ALLOC_BUFFERS = (1 << 8), /**< the application will allocate buffer
-+ * memory. In the add_buffer event, the
-+ * data of the buffer should be set */
-+};
-+
-+/** Create a new unconneced \ref pw_stream \memberof pw_stream
-+ * \return a newly allocated \ref pw_stream */
-+struct pw_stream *
-+pw_stream_new(struct pw_core *core, /**< a \ref pw_core */
-+ const char *name, /**< a stream media name */
-+ struct pw_properties *props /**< stream properties, ownership is taken */);
-+
-+struct pw_stream *
-+pw_stream_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */
-+ const char *name, /**< a stream media name */
-+ struct pw_properties *props,/**< stream properties, ownership is taken */
-+ const struct pw_stream_events *events, /**< stream events */
-+ void *data /**< data passed to events */);
-+
-+/** Destroy a stream \memberof pw_stream */
-+void pw_stream_destroy(struct pw_stream *stream);
-+
-+void pw_stream_add_listener(struct pw_stream *stream,
-+ struct spa_hook *listener,
-+ const struct pw_stream_events *events,
-+ void *data);
-+
-+enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error);
-+
-+const char *pw_stream_get_name(struct pw_stream *stream);
-+
-+struct pw_core *pw_stream_get_core(struct pw_stream *stream);
-+
-+const struct pw_properties *pw_stream_get_properties(struct pw_stream *stream);
-+
-+int pw_stream_update_properties(struct pw_stream *stream, const struct spa_dict *dict);
-+
-+/** Connect a stream for input or output on \a port_path. \memberof pw_stream
-+ * \return 0 on success < 0 on error.
-+ *
-+ * You should connect to the process event and use pw_stream_dequeue_buffer()
-+ * to get the latest metadata and data. */
-+int
-+pw_stream_connect(struct pw_stream *stream, /**< a \ref pw_stream */
-+ enum pw_direction direction, /**< the stream direction */
-+ uint32_t target_id, /**< the target object id to connect to or
-+ * PW_ID_ANY to let the manager
-+ * select a target. */
-+ enum pw_stream_flags flags, /**< stream flags */
-+ const struct spa_pod **params, /**< an array with params. The params
-+ * should ideally contain supported
-+ * formats. */
-+ uint32_t n_params /**< number of items in \a params */);
-+
-+/** Get the node ID of the stream. \memberof pw_stream
-+ * \return node ID. */
-+uint32_t
-+pw_stream_get_node_id(struct pw_stream *stream);
-+
-+/** Disconnect \a stream \memberof pw_stream */
-+int pw_stream_disconnect(struct pw_stream *stream);
-+
-+/** Set the stream in error state */
-+int pw_stream_set_error(struct pw_stream *stream, /**< a \ref pw_stream */
-+ int res, /**< a result code */
-+ const char *error, ... /**< an error message */) SPA_PRINTF_FUNC(3, 4);
-+
-+/** Complete the negotiation process with result code \a res \memberof pw_stream
-+ *
-+ * This function should be called after notification of the format.
-+
-+ * When \a res indicates success, \a params contain the parameters for the
-+ * allocation state. */
-+int
-+pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */
-+ const struct spa_pod **params, /**< an array of params. The params should
-+ * ideally contain parameters for doing
-+ * buffer allocation. */
-+ uint32_t n_params /**< number of elements in \a params */);
-+
-+/** Set control values */
-+int pw_stream_set_control(struct pw_stream *stream, uint32_t id, uint32_t n_values, float *values, ...);
-+
-+/** Query the time on the stream \memberof pw_stream */
-+int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time);
-+
-+/** Get a buffer that can be filled for playback streams or consumed
-+ * for capture streams. */
-+struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream);
-+
-+/** Submit a buffer for playback or recycle a buffer for capture. */
-+int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
-+
-+/** Activate or deactivate the stream \memberof pw_stream */
-+int pw_stream_set_active(struct pw_stream *stream, bool active);
-+
-+/** Flush a stream. When \a drain is true, the drained callback will
-+ * be called when all data is played or recorded */
-+int pw_stream_flush(struct pw_stream *stream, bool drain);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_STREAM_H */
-diff --git a/third_party/pipewire/pipewire/thread-loop.h b/third_party/pipewire/pipewire/thread-loop.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/thread-loop.h
-@@ -0,0 +1,168 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_THREAD_LOOP_H
-+#define PIPEWIRE_THREAD_LOOP_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <pipewire/loop.h>
-+
-+/** \page page_thread_loop Threaded Loop
-+ *
-+ * \section sec_thread_loop_overview Overview
-+ *
-+ * The threaded loop implementation is a special wrapper around the
-+ * regular \ref pw_loop implementation.
-+ *
-+ * The added feature in the threaded loop is that it spawns a new thread
-+ * that runs the wrapped loop. This allows a synchronous application to use
-+ * the asynchronous API without risking to stall the PipeWire library.
-+ *
-+ * \section sec_thread_loop_create Creation
-+ *
-+ * A \ref pw_thread_loop object is created using pw_thread_loop_new().
-+ * The \ref pw_loop to wrap must be given as an argument along with the name
-+ * for the thread that will be spawned.
-+ *
-+ * After allocating the object, the thread must be started with
-+ * pw_thread_loop_start()
-+ *
-+ * \section sec_thread_loop_destruction Destruction
-+ *
-+ * When the PipeWire connection has been terminated, the thread must be
-+ * stopped and the resources freed. Stopping the thread is done using
-+ * pw_thread_loop_stop(), which must be called without the lock (see
-+ * below) held. When that function returns, the thread is stopped and the
-+ * \ref pw_thread_loop object can be freed using pw_thread_loop_destroy().
-+ *
-+ * \section sec_thread_loop_locking Locking
-+ *
-+ * Since the PipeWire API doesn't allow concurrent accesses to objects,
-+ * a locking scheme must be used to guarantee safe usage. The threaded
-+ * loop API provides such a scheme through the functions
-+ * pw_thread_loop_lock() and pw_thread_loop_unlock().
-+ *
-+ * The lock is recursive, so it's safe to use it multiple times from the same
-+ * thread. Just make sure you call pw_thread_loop_unlock() the same
-+ * number of times you called pw_thread_loop_lock().
-+ *
-+ * The lock needs to be held whenever you call any PipeWire function that
-+ * uses an object associated with this loop. Make sure you do not hold
-+ * on to the lock more than necessary though, as the threaded loop stops
-+ * while the lock is held.
-+ *
-+ * \section sec_thread_loop_events Events and Callbacks
-+ *
-+ * All events and callbacks are called with the thread lock held.
-+ *
-+ */
-+/** \class pw_thread_loop
-+ *
-+ * \brief PipeWire threaded loop object
-+ *
-+ * The threaded loop object runs a \ref pw_loop in a separate thread
-+ * and ensures proper locking is done.
-+ *
-+ * All of the loop callbacks will be executed with the loop
-+ * lock held.
-+ *
-+ * See also \ref page_thread_loop
-+ */
-+struct pw_thread_loop;
-+
-+/** Thread loop events */
-+struct pw_thread_loop_events {
-+#define PW_VERSION_THREAD_LOOP_EVENTS 0
-+ uint32_t version;
-+
-+ /** the loop is destroyed */
-+ void (*destroy) (void *data);
-+};
-+
-+/** Make a new thread loop with the given name and optional properties. */
-+struct pw_thread_loop *
-+pw_thread_loop_new(const char *name, const struct spa_dict *props);
-+
-+/** Make a new thread loop with the given loop, name and optional properties.
-+ * When \a loop is NULL, a new loop will be created. */
-+struct pw_thread_loop *
-+pw_thread_loop_new_full(struct pw_loop *loop, const char *name, const struct spa_dict *props);
-+
-+/** Destroy a thread loop */
-+void pw_thread_loop_destroy(struct pw_thread_loop *loop);
-+
-+/** Add an event listener */
-+void pw_thread_loop_add_listener(struct pw_thread_loop *loop,
-+ struct spa_hook *listener,
-+ const struct pw_thread_loop_events *events,
-+ void *data);
-+
-+/** Get the loop implementation of the thread loop */
-+struct pw_loop * pw_thread_loop_get_loop(struct pw_thread_loop *loop);
-+
-+/** Start the thread loop */
-+int pw_thread_loop_start(struct pw_thread_loop *loop);
-+
-+/** Stop the thread loop */
-+void pw_thread_loop_stop(struct pw_thread_loop *loop);
-+
-+/** Lock the loop. This ensures exclusive ownership of the loop */
-+void pw_thread_loop_lock(struct pw_thread_loop *loop);
-+
-+/** Unlock the loop */
-+void pw_thread_loop_unlock(struct pw_thread_loop *loop);
-+
-+/** Release the lock and wait until some thread calls \ref pw_thread_loop_signal */
-+void pw_thread_loop_wait(struct pw_thread_loop *loop);
-+
-+/** Release the lock and wait a maximum of 'wait_max_sec' seconds
-+ * until some thread calls \ref pw_thread_loop_signal or time out */
-+int pw_thread_loop_timed_wait(struct pw_thread_loop *loop, int wait_max_sec);
-+
-+/** Get a struct timespec suitable for \ref pw_thread_loop_timed_wait_full.
-+ * Since: 0.3.7 */
-+int pw_thread_loop_get_time(struct pw_thread_loop *loop, struct timespec *abstime, int64_t timeout);
-+
-+/** Release the lock and wait up to \a abstime until some thread calls
-+ * \ref pw_thread_loop_signal. Use \ref pw_thread_loop_get_time to make a timeout.
-+ * Since: 0.3.7 */
-+int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, struct timespec *abstime);
-+
-+/** Signal all threads waiting with \ref pw_thread_loop_wait */
-+void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept);
-+
-+/** Signal all threads executing \ref pw_thread_loop_signal with wait_for_accept */
-+void pw_thread_loop_accept(struct pw_thread_loop *loop);
-+
-+/** Check if inside the thread */
-+bool pw_thread_loop_in_thread(struct pw_thread_loop *loop);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_THREAD_LOOP_H */
-diff --git a/third_party/pipewire/pipewire/type.h b/third_party/pipewire/pipewire/type.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/type.h
-@@ -0,0 +1,52 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_TYPE_H
-+#define PIPEWIRE_TYPE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/type.h>
-+
-+enum {
-+ PW_TYPE_FIRST = SPA_TYPE_VENDOR_PipeWire,
-+};
-+
-+#define PW_TYPE_INFO_BASE "PipeWire:"
-+
-+#define PW_TYPE_INFO_Object PW_TYPE_INFO_BASE "Object"
-+#define PW_TYPE_INFO_OBJECT_BASE PW_TYPE_INFO_Object ":"
-+
-+#define PW_TYPE_INFO_Interface PW_TYPE_INFO_BASE "Interface"
-+#define PW_TYPE_INFO_INTERFACE_BASE PW_TYPE_INFO_Interface ":"
-+
-+const struct spa_type_info * pw_type_info(void);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_TYPE_H */
-diff --git a/third_party/pipewire/pipewire/utils.h b/third_party/pipewire/pipewire/utils.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/utils.h
-@@ -0,0 +1,59 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_UTILS_H
-+#define PIPEWIRE_UTILS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/pod/pod.h>
-+
-+/** \class pw_utils
-+ *
-+ * Various utility functions
-+ */
-+
-+/** a function to destroy an item \memberof pw_utils */
-+typedef void (*pw_destroy_t) (void *object);
-+
-+const char *
-+pw_split_walk(const char *str, const char *delimiter, size_t *len, const char **state);
-+
-+char **
-+pw_split_strv(const char *str, const char *delimiter, int max_tokens, int *n_tokens);
-+
-+void
-+pw_free_strv(char **str);
-+
-+char *
-+pw_strip(char *str, const char *whitespace);
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* PIPEWIRE_UTILS_H */
-diff --git a/third_party/pipewire/pipewire/version.h b/third_party/pipewire/pipewire/version.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/version.h
-@@ -0,0 +1,68 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_VERSION_H
-+#define PIPEWIRE_VERSION_H
-+
-+/* WARNING: Make sure to edit the real source file version.h.in! */
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** Return the version of the header files. Keep in mind that this is
-+a macro and not a function, so it is impossible to get the pointer of
-+it. */
-+#define pw_get_headers_version() ("0.3.13")
-+
-+/** Return the version of the library the current application is
-+ * linked to. */
-+const char* pw_get_library_version(void);
-+
-+/** The current API version. Versions prior to 0.2.0 have
-+ * PW_API_VERSION undefined. Please note that this is only ever
-+ * increased on incompatible API changes! */
-+#define PW_API_VERSION "0.3"
-+
-+/** The major version of PipeWire. \since 0.2.0 */
-+#define PW_MAJOR 0
-+
-+/** The minor version of PipeWire. \since 0.2.0 */
-+#define PW_MINOR 3
-+
-+/** The micro version of PipeWire. \since 0.2.0 */
-+#define PW_MICRO 13
-+
-+/** Evaluates to TRUE if the PipeWire library version is equal or
-+ * newer than the specified. \since 0.2.0 */
-+#define PW_CHECK_VERSION(major,minor,micro) \
-+ ((PW_MAJOR > (major)) || \
-+ (PW_MAJOR == (major) && PW_MINOR > (minor)) || \
-+ (PW_MAJOR == (major) && PW_MINOR == (minor) && PW_MICRO >= (micro)))
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_VERION_H */
-diff --git a/third_party/pipewire/pipewire/work-queue.h b/third_party/pipewire/pipewire/work-queue.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/pipewire/work-queue.h
-@@ -0,0 +1,63 @@
-+/* PipeWire
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef PIPEWIRE_WORK_QUEUE_H
-+#define PIPEWIRE_WORK_QUEUE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** \class pw_work_queue
-+ *
-+ * PipeWire work queue object
-+ */
-+struct pw_work_queue;
-+
-+#include <pipewire/loop.h>
-+
-+typedef void (*pw_work_func_t) (void *obj, void *data, int res, uint32_t id);
-+
-+struct pw_work_queue *
-+pw_work_queue_new(struct pw_loop *loop);
-+
-+void
-+pw_work_queue_destroy(struct pw_work_queue *queue);
-+
-+uint32_t
-+pw_work_queue_add(struct pw_work_queue *queue,
-+ void *obj, int res,
-+ pw_work_func_t func, void *data);
-+
-+int
-+pw_work_queue_cancel(struct pw_work_queue *queue, void *obj, uint32_t id);
-+
-+int
-+pw_work_queue_complete(struct pw_work_queue *queue, void *obj, uint32_t seq, int res);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* PIPEWIRE_WORK_QUEUE_H */
-diff --git a/third_party/pipewire/spa/buffer/alloc.h b/third_party/pipewire/spa/buffer/alloc.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/buffer/alloc.h
-@@ -0,0 +1,338 @@
-+/* Simple Plugin API
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+#ifndef SPA_BUFFER_ALLOC_H
-+#define SPA_BUFFER_ALLOC_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/buffer/buffer.h>
-+
-+/** information about the buffer layout */
-+struct spa_buffer_alloc_info {
-+#define SPA_BUFFER_ALLOC_FLAG_INLINE_META (1<<0) /**< add metadata data in the skeleton */
-+#define SPA_BUFFER_ALLOC_FLAG_INLINE_CHUNK (1<<1) /**< add chunk data in the skeleton */
-+#define SPA_BUFFER_ALLOC_FLAG_INLINE_DATA (1<<2) /**< add buffer data to the skeleton */
-+#define SPA_BUFFER_ALLOC_FLAG_INLINE_ALL 0b111
-+#define SPA_BUFFER_ALLOC_FLAG_NO_DATA (1<<3) /**< don't set data pointers */
-+ uint32_t flags;
-+ uint32_t max_align; /**< max of all alignments */
-+ uint32_t n_metas;
-+ uint32_t n_datas;
-+ struct spa_meta *metas;
-+ struct spa_data *datas;
-+ uint32_t *data_aligns;
-+ size_t skel_size; /**< size of the struct spa_buffer and inlined meta/chunk/data */
-+ size_t meta_size; /**< size of the meta if not inlined */
-+ size_t chunk_size; /**< size of the chunk if not inlined */
-+ size_t data_size; /**< size of the data if not inlined */
-+ size_t mem_size; /**< size of the total memory if not inlined */
-+};
-+
-+/**
-+ * Fill buffer allocation information
-+ *
-+ * Fill \a info with allocation information needed to allocate buffers
-+ * with the given number of metadata and data members.
-+ *
-+ * The required size of the skeleton (the struct spa_buffer) information
-+ * and the memory (for the metadata, chunk and buffer memory) will be
-+ * calculated.
-+ *
-+ * The flags member in \a info should be configured before calling this
-+ * functions.
-+ *
-+ * \param info the information to fill
-+ * \param n_metas the number of metadatas for the buffer
-+ * \param metas an array of metadata items
-+ * \param n_datas the number of datas for the buffer
-+ * \param datas an array of \a n_datas items
-+ * \param data_aligns \a n_datas alignments
-+ * \return 0 on success.
-+ * */
-+static inline int spa_buffer_alloc_fill_info(struct spa_buffer_alloc_info *info,
-+ uint32_t n_metas, struct spa_meta metas[],
-+ uint32_t n_datas, struct spa_data datas[],
-+ uint32_t data_aligns[])
-+{
-+ size_t size, *target;
-+ uint32_t i;
-+
-+ info->n_metas = n_metas;
-+ info->metas = metas;
-+ info->n_datas = n_datas;
-+ info->datas = datas;
-+ info->data_aligns = data_aligns;
-+ info->max_align = 16;
-+ info->mem_size = 0;
-+ /*
-+ * The buffer skeleton is placed in memory like below and can
-+ * be accessed as a regular structure.
-+ *
-+ * +==============================+
-+ * | struct spa_buffer |
-+ * | uint32_t n_metas | number of metas
-+ * | uint32_t n_datas | number of datas
-+ * +-| struct spa_meta *metas | pointer to array of metas
-+ * +|-| struct spa_data *datas | pointer to array of datas
-+ * || +------------------------------+
-+ * |+>| struct spa_meta |
-+ * | | uint32_t type | metadata
-+ * | | uint32_t size | size of metadata
-+ * +|--| void *data | pointer to metadata
-+ * || | ... <n_metas> | more spa_meta follow
-+ * || +------------------------------+
-+ * |+->| struct spa_data |
-+ * | | uint32_t type | memory type
-+ * | | uint32_t flags |
-+ * | | int fd | fd of shared memory block
-+ * | | uint32_t mapoffset | offset in shared memory of data
-+ * | | uint32_t maxsize | size of data block
-+ * | +-| void *data | pointer to data
-+ * |+|-| struct spa_chunk *chunk | pointer to chunk
-+ * ||| | ... <n_datas> | more spa_data follow
-+ * ||| +==============================+
-+ * VVV
-+ *
-+ * metadata, chunk and memory can either be placed right
-+ * after the skeleton (inlined) or in a separate piece of memory.
-+ *
-+ * vvv
-+ * ||| +==============================+
-+ * +-->| meta data memory | metadata memory, 8 byte aligned
-+ * || | ... <n_metas> |
-+ * || +------------------------------+
-+ * +->| struct spa_chunk | memory for n_datas chunks
-+ * | | uint32_t offset |
-+ * | | uint32_t size |
-+ * | | int32_t stride |
-+ * | | int32_t dummy |
-+ * | | ... <n_datas> chunks |
-+ * | +------------------------------+
-+ * +>| data | memory for n_datas data, aligned
-+ * | ... <n_datas> blocks | according to alignments
-+ * +==============================+
-+ */
-+ info->skel_size = sizeof(struct spa_buffer);
-+ info->skel_size += n_metas * sizeof(struct spa_meta);
-+ info->skel_size += n_datas * sizeof(struct spa_data);
-+
-+ for (i = 0, size = 0; i < n_metas; i++)
-+ size += SPA_ROUND_UP_N(metas[i].size, 8);
-+ info->meta_size = size;
-+
-+ if (SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_INLINE_META))
-+ target = &info->skel_size;
-+ else
-+ target = &info->mem_size;
-+ *target += info->meta_size;
-+
-+ info->chunk_size = n_datas * sizeof(struct spa_chunk);
-+ if (SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_INLINE_CHUNK))
-+ target = &info->skel_size;
-+ else
-+ target = &info->mem_size;
-+ *target += info->chunk_size;
-+
-+ for (i = 0, size = 0; i < n_datas; i++) {
-+ info->max_align = SPA_MAX(info->max_align, data_aligns[i]);
-+ size = SPA_ROUND_UP_N(size, data_aligns[i]);
-+ size += datas[i].maxsize;
-+ }
-+ info->data_size = size;
-+
-+ if (!SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_NO_DATA) &&
-+ SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_INLINE_DATA))
-+ target = &info->skel_size;
-+ else
-+ target = &info->mem_size;
-+
-+ *target = SPA_ROUND_UP_N(*target, n_datas ? data_aligns[0] : 1);
-+ *target += info->data_size;
-+ *target = SPA_ROUND_UP_N(*target, info->max_align);
-+
-+ return 0;
-+}
-+
-+/**
-+ * Fill skeleton and data according to the allocation info
-+ *
-+ * Use the allocation info to create a \ref struct spa_buffer into
-+ * \a skel_mem and \a data_mem.
-+ *
-+ * Depending on the flags given when calling \ref
-+ * spa_buffer_alloc_fill_info(), the buffer meta, chunk and memory
-+ * will be referenced in either skel_mem or data_mem.
-+ *
-+ * \param info an allocation info
-+ * \param skel_mem memory to hold the \ref struct spa_buffer and the
-+ * pointers to meta, chunk and memory.
-+ * \param data_mem memory to hold the meta, chunk and memory
-+ * \return a \ref struct spa_buffer in \a skel_mem
-+ */
-+static inline struct spa_buffer *
-+spa_buffer_alloc_layout(struct spa_buffer_alloc_info *info,
-+ void *skel_mem, void *data_mem)
-+{
-+ struct spa_buffer *b = (struct spa_buffer*)skel_mem;
-+ size_t size;
-+ uint32_t i;
-+ void **dp, *skel, *data;
-+ struct spa_chunk *cp;
-+
-+ b->n_metas = info->n_metas;
-+ b->metas = SPA_MEMBER(b, sizeof(struct spa_buffer), struct spa_meta);
-+ b->n_datas = info->n_datas;
-+ b->datas = SPA_MEMBER(b->metas, info->n_metas * sizeof(struct spa_meta), struct spa_data);
-+
-+ skel = SPA_MEMBER(b->datas, info->n_datas * sizeof(struct spa_data), void);
-+ data = data_mem;
-+
-+ if (SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_INLINE_META))
-+ dp = &skel;
-+ else
-+ dp = &data;
-+
-+ for (i = 0; i < info->n_metas; i++) {
-+ struct spa_meta *m = &b->metas[i];
-+ *m = info->metas[i];
-+ m->data = *dp;
-+ *dp = SPA_MEMBER(*dp, SPA_ROUND_UP_N(m->size, 8), void);
-+ }
-+
-+ size = info->n_datas * sizeof(struct spa_chunk);
-+ if (SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_INLINE_CHUNK)) {
-+ cp = (struct spa_chunk*)skel;
-+ skel = SPA_MEMBER(skel, size, void);
-+ }
-+ else {
-+ cp = (struct spa_chunk*)data;
-+ data = SPA_MEMBER(data, size, void);
-+ }
-+
-+ if (SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_INLINE_DATA))
-+ dp = &skel;
-+ else
-+ dp = &data;
-+
-+ for (i = 0; i < info->n_datas; i++) {
-+ struct spa_data *d = &b->datas[i];
-+
-+ *d = info->datas[i];
-+ d->chunk = &cp[i];
-+ if (!SPA_FLAG_IS_SET(info->flags, SPA_BUFFER_ALLOC_FLAG_NO_DATA)) {
-+ *dp = SPA_PTR_ALIGN(*dp, info->data_aligns[i], void);
-+ d->data = *dp;
-+ *dp = SPA_MEMBER(*dp, d->maxsize, void);
-+ }
-+ }
-+ return b;
-+}
-+
-+/**
-+ * Layout an array of buffers
-+ *
-+ * Use the allocation info to layout the memory of an array of buffers.
-+ *
-+ * \a skel_mem should point to at least info->skel_size * \a n_buffers bytes
-+ * of memory.
-+ * \a data_mem should point to at least info->mem_size * \a n_buffers bytes
-+ * of memory.
-+ *
-+ * \param info the allocation info for one buffer
-+ * \param n_buffers the number of buffers to create
-+ * \param buffer a array with space to hold \a n_buffers pointers to buffers
-+ * \param skel_mem memory for the \ref struct spa_buffer
-+ * \param data_mem memory for the meta, chunk, memory of the buffer if not
-+ * inlined in the skeleton.
-+ * \return 0 on success.
-+ *
-+ */
-+static inline int
-+spa_buffer_alloc_layout_array(struct spa_buffer_alloc_info *info,
-+ uint32_t n_buffers, struct spa_buffer *buffers[],
-+ void *skel_mem, void *data_mem)
-+{
-+ uint32_t i;
-+ for (i = 0; i < n_buffers; i++) {
-+ buffers[i] = spa_buffer_alloc_layout(info, skel_mem, data_mem);
-+ skel_mem = SPA_MEMBER(skel_mem, info->skel_size, void);
-+ data_mem = SPA_MEMBER(data_mem, info->mem_size, void);
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * Allocate an array of buffers
-+ *
-+ * Allocate \a n_buffers with the given metadata, memory and alignment
-+ * information.
-+ *
-+ * The buffer array, structures, data and metadata will all be allocated
-+ * in one block of memory with the proper requested alignment.
-+ *
-+ * \param n_buffers the number of buffers to create
-+ * \param flags extra flags
-+ * \param n_metas number of metadatas
-+ * \param metas \a n_metas metadata specification
-+ * \param n_datas number of datas
-+ * \param datas \a n_datas memory specification
-+ * \param data_aligns \a n_datas alignment specifications
-+ * \returns an array of \a n_buffers pointers to \ref struct spa_buffer
-+ * with the given metadata, data and alignment or NULL when
-+ * allocation failed.
-+ *
-+ */
-+static inline struct spa_buffer **
-+spa_buffer_alloc_array(uint32_t n_buffers, uint32_t flags,
-+ uint32_t n_metas, struct spa_meta metas[],
-+ uint32_t n_datas, struct spa_data datas[],
-+ uint32_t data_aligns[])
-+{
-+
-+ struct spa_buffer **buffers;
-+ struct spa_buffer_alloc_info info = { flags | SPA_BUFFER_ALLOC_FLAG_INLINE_ALL, };
-+ void *skel;
-+
-+ spa_buffer_alloc_fill_info(&info, n_metas, metas, n_datas, datas, data_aligns);
-+
-+ buffers = (struct spa_buffer **)calloc(1, info.max_align +
-+ n_buffers * (sizeof(struct spa_buffer *) + info.skel_size));
-+ if (buffers == NULL)
-+ return NULL;
-+
-+ skel = SPA_MEMBER(buffers, sizeof(struct spa_buffer *) * n_buffers, void);
-+ skel = SPA_PTR_ALIGN(skel, info.max_align, void);
-+
-+ spa_buffer_alloc_layout_array(&info, n_buffers, buffers, skel, NULL);
-+
-+ return buffers;
-+}
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_BUFFER_ALLOC_H */
-diff --git a/third_party/pipewire/spa/buffer/buffer.h b/third_party/pipewire/spa/buffer/buffer.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/buffer/buffer.h
-@@ -0,0 +1,114 @@
-+/* Simple Plugin API
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_BUFFER_H
-+#define SPA_BUFFER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/buffer/meta.h>
-+
-+/** \page page_buffer Buffers
-+ *
-+ * Buffers describe the data and metadata that is exchanged between
-+ * ports of a node.
-+ */
-+
-+enum spa_data_type {
-+ SPA_DATA_Invalid,
-+ SPA_DATA_MemPtr, /**< pointer to memory, the data field in
-+ * struct spa_data is set. */
-+ SPA_DATA_MemFd, /**< generic fd, mmap to get to memory */
-+ SPA_DATA_DmaBuf, /**< fd to dmabuf memory */
-+ SPA_DATA_MemId, /**< memory is identified with an id */
-+
-+ SPA_DATA_LAST, /**< not part of ABI */
-+};
-+
-+/** Chunk of memory, can change for each buffer */
-+struct spa_chunk {
-+ uint32_t offset; /**< offset of valid data. Should be taken
-+ * modulo the data maxsize to get the offset
-+ * in the data memory. */
-+ uint32_t size; /**< size of valid data. Should be clamped to
-+ * maxsize. */
-+ int32_t stride; /**< stride of valid data */
-+#define SPA_CHUNK_FLAG_NONE 0
-+#define SPA_CHUNK_FLAG_CORRUPTED (1u<<0) /**< chunk data is corrupted in some way */
-+ int32_t flags; /**< chunk flags */
-+};
-+
-+/** Data for a buffer this stays constant for a buffer */
-+struct spa_data {
-+ uint32_t type; /**< memory type, one of enum spa_data_type, when
-+ * allocating memory, the type contains a bitmask
-+ * of allowed types */
-+#define SPA_DATA_FLAG_NONE 0
-+#define SPA_DATA_FLAG_READABLE (1u<<0) /**< data is readable */
-+#define SPA_DATA_FLAG_WRITABLE (1u<<1) /**< data is writable */
-+#define SPA_DATA_FLAG_DYNAMIC (1u<<2) /**< data pointer can be changed */
-+#define SPA_DATA_FLAG_READWRITE (SPA_DATA_FLAG_READABLE|SPA_DATA_FLAG_WRITABLE)
-+ uint32_t flags; /**< data flags */
-+ int64_t fd; /**< optional fd for data */
-+ uint32_t mapoffset; /**< offset to map fd at */
-+ uint32_t maxsize; /**< max size of data */
-+ void *data; /**< optional data pointer */
-+ struct spa_chunk *chunk; /**< valid chunk of memory */
-+};
-+
-+/** A Buffer */
-+struct spa_buffer {
-+ uint32_t n_metas; /**< number of metadata */
-+ uint32_t n_datas; /**< number of data members */
-+ struct spa_meta *metas; /**< array of metadata */
-+ struct spa_data *datas; /**< array of data members */
-+};
-+
-+/** Find metadata in a buffer */
-+static inline struct spa_meta *spa_buffer_find_meta(const struct spa_buffer *b, uint32_t type)
-+{
-+ uint32_t i;
-+
-+ for (i = 0; i < b->n_metas; i++)
-+ if (b->metas[i].type == type)
-+ return &b->metas[i];
-+
-+ return NULL;
-+}
-+
-+static inline void *spa_buffer_find_meta_data(const struct spa_buffer *b, uint32_t type, size_t size)
-+{
-+ struct spa_meta *m;
-+ if ((m = spa_buffer_find_meta(b, type)) && m->size >= size)
-+ return m->data;
-+ return NULL;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_BUFFER_H */
-diff --git a/third_party/pipewire/spa/buffer/meta.h b/third_party/pipewire/spa/buffer/meta.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/buffer/meta.h
-@@ -0,0 +1,151 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_META_H
-+#define SPA_META_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/pod/pod.h>
-+
-+/** \page page_meta Metadata
-+ *
-+ * Metadata contains extra information on a buffer.
-+ */
-+enum spa_meta_type {
-+ SPA_META_Invalid,
-+ SPA_META_Header, /**< struct spa_meta_header */
-+ SPA_META_VideoCrop, /**< struct spa_meta_region with cropping data */
-+ SPA_META_VideoDamage, /**< array of struct spa_meta_region with damage */
-+ SPA_META_Bitmap, /**< struct spa_meta_bitmap */
-+ SPA_META_Cursor, /**< struct spa_meta_cursor */
-+ SPA_META_Control, /**< metadata contains a spa_meta_control
-+ * associated with the data */
-+
-+ SPA_META_LAST, /**< not part of ABI/API */
-+};
-+
-+/**
-+ * A metadata element.
-+ *
-+ * This structure is available on the buffer structure and contains
-+ * the type of the metadata and a pointer/size to the actual metadata
-+ * itself.
-+ */
-+struct spa_meta {
-+ uint32_t type; /**< metadata type, one of enum spa_meta_type */
-+ uint32_t size; /**< size of metadata */
-+ void *data; /**< pointer to metadata */
-+};
-+
-+#define spa_meta_first(m) ((m)->data)
-+#define spa_meta_end(m) SPA_MEMBER((m)->data,(m)->size,void)
-+#define spa_meta_check(p,m) (SPA_MEMBER(p,sizeof(*p),void) <= spa_meta_end(m))
-+
-+/**
-+ * Describes essential buffer header metadata such as flags and
-+ * timestamps.
-+ */
-+struct spa_meta_header {
-+#define SPA_META_HEADER_FLAG_DISCONT (1 << 0) /**< data is not continuous with previous buffer */
-+#define SPA_META_HEADER_FLAG_CORRUPTED (1 << 1) /**< data might be corrupted */
-+#define SPA_META_HEADER_FLAG_MARKER (1 << 2) /**< media specific marker */
-+#define SPA_META_HEADER_FLAG_HEADER (1 << 3) /**< data contains a codec specific header */
-+#define SPA_META_HEADER_FLAG_GAP (1 << 4) /**< data contains media neutral data */
-+#define SPA_META_HEADER_FLAG_DELTA_UNIT (1 << 5) /**< cannot be decoded independently */
-+ uint32_t flags; /**< flags */
-+ uint32_t offset; /**< offset in current cycle */
-+ int64_t pts; /**< presentation timestamp */
-+ int64_t dts_offset; /**< decoding timestamp as a difference with pts */
-+ uint64_t seq; /**< sequence number, increments with a
-+ * media specific frequency */
-+};
-+
-+/** metadata structure for Region or an array of these for RegionArray */
-+struct spa_meta_region {
-+ struct spa_region region;
-+};
-+
-+#define spa_meta_region_is_valid(m) ((m)->region.size.width != 0 && (m)->region.size.height != 0)
-+
-+/** iterate all the items in a metadata */
-+#define spa_meta_for_each(pos,meta) \
-+ for (pos = (__typeof(pos))spa_meta_first(meta); \
-+ spa_meta_check(pos, meta); \
-+ (pos)++)
-+
-+#define spa_meta_bitmap_is_valid(m) ((m)->format != 0)
-+
-+/**
-+ * Bitmap information
-+ *
-+ * This metadata contains a bitmap image in the given format and size.
-+ * It is typically used for cursor images or other small images that are
-+ * better transferred inline.
-+ */
-+struct spa_meta_bitmap {
-+ uint32_t format; /**< bitmap video format, one of enum spa_video_format. 0 is
-+ * and invalid format and should be handled as if there is
-+ * no new bitmap information. */
-+ struct spa_rectangle size; /**< width and height of bitmap */
-+ int32_t stride; /**< stride of bitmap data */
-+ uint32_t offset; /**< offset of bitmap data in this structure. An offset of
-+ * 0 means no image data (invisible), an offset >=
-+ * sizeof(struct spa_meta_bitmap) contains valid bitmap
-+ * info. */
-+};
-+
-+#define spa_meta_cursor_is_valid(m) ((m)->id != 0)
-+
-+/**
-+ * Cursor information
-+ *
-+ * Metadata to describe the position and appearance of a pointing device.
-+ */
-+struct spa_meta_cursor {
-+ uint32_t id; /**< cursor id. an id of 0 is an invalid id and means that
-+ * there is no new cursor data */
-+ uint32_t flags; /**< extra flags */
-+ struct spa_point position; /**< position on screen */
-+ struct spa_point hotspot; /**< offsets for hotspot in bitmap, this field has no meaning
-+ * when there is no valid bitmap (see below) */
-+ uint32_t bitmap_offset; /**< offset of bitmap meta in this structure. When the offset
-+ * is 0, there is no new bitmap information. When the offset is
-+ * >= sizeof(struct spa_meta_cursor) there is a
-+ * struct spa_meta_bitmap at the offset. */
-+};
-+
-+/** a timed set of events associated with the buffer */
-+struct spa_meta_control {
-+ struct spa_pod_sequence sequence;
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_META_H */
-diff --git a/third_party/pipewire/spa/buffer/type-info.h b/third_party/pipewire/spa/buffer/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/buffer/type-info.h
-@@ -0,0 +1,83 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_BUFFER_TYPES_H
-+#define SPA_BUFFER_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/buffer/buffer.h>
-+#include <spa/buffer/meta.h>
-+#include <spa/utils/type.h>
-+
-+#define SPA_TYPE_INFO_Buffer SPA_TYPE_INFO_POINTER_BASE "Buffer"
-+#define SPA_TYPE_INFO_BUFFER_BASE SPA_TYPE_INFO_Buffer ":"
-+
-+/** Buffers contain data of a certain type */
-+#define SPA_TYPE_INFO_Data SPA_TYPE_INFO_ENUM_BASE "Data"
-+#define SPA_TYPE_INFO_DATA_BASE SPA_TYPE_INFO_Data ":"
-+
-+/** base type for fd based memory */
-+#define SPA_TYPE_INFO_DATA_Fd SPA_TYPE_INFO_DATA_BASE "Fd"
-+#define SPA_TYPE_INFO_DATA_FD_BASE SPA_TYPE_INFO_DATA_Fd ":"
-+
-+static const struct spa_type_info spa_type_data_type[] = {
-+ { SPA_DATA_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "Invalid", NULL },
-+ { SPA_DATA_MemPtr, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "MemPtr", NULL },
-+ { SPA_DATA_MemFd, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_FD_BASE "MemFd", NULL },
-+ { SPA_DATA_DmaBuf, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_FD_BASE "DmaBuf", NULL },
-+ { SPA_DATA_MemId, SPA_TYPE_Int, SPA_TYPE_INFO_DATA_BASE "MemId", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_Meta SPA_TYPE_INFO_POINTER_BASE "Meta"
-+#define SPA_TYPE_INFO_META_BASE SPA_TYPE_INFO_Meta ":"
-+
-+#define SPA_TYPE_INFO_META_Array SPA_TYPE_INFO_META_BASE "Array"
-+#define SPA_TYPE_INFO_META_ARRAY_BASE SPA_TYPE_INFO_META_Array ":"
-+
-+#define SPA_TYPE_INFO_META_Region SPA_TYPE_INFO_META_BASE "Region"
-+#define SPA_TYPE_INFO_META_REGION_BASE SPA_TYPE_INFO_META_Region ":"
-+
-+#define SPA_TYPE_INFO_META_ARRAY_Region SPA_TYPE_INFO_META_ARRAY_BASE "Region"
-+#define SPA_TYPE_INFO_META_ARRAY_REGION_BASE SPA_TYPE_INFO_META_ARRAY_Region ":"
-+
-+static const struct spa_type_info spa_type_meta_type[] = {
-+ { SPA_META_Invalid, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Invalid", NULL },
-+ { SPA_META_Header, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Header", NULL },
-+ { SPA_META_VideoCrop, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_REGION_BASE "VideoCrop", NULL },
-+ { SPA_META_VideoDamage, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_ARRAY_REGION_BASE "VideoDamage", NULL },
-+ { SPA_META_Bitmap, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Bitmap", NULL },
-+ { SPA_META_Cursor, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Cursor", NULL },
-+ { SPA_META_Control, SPA_TYPE_Pointer, SPA_TYPE_INFO_META_BASE "Control", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_BUFFER_TYPES_H */
-diff --git a/third_party/pipewire/spa/control/control.h b/third_party/pipewire/spa/control/control.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/control/control.h
-@@ -0,0 +1,53 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_CONTROL_H
-+#define SPA_CONTROL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/pod/pod.h>
-+
-+/** Controls
-+ *
-+ */
-+
-+/** Different Control types */
-+enum spa_control_type {
-+ SPA_CONTROL_Invalid,
-+ SPA_CONTROL_Properties, /**< data contains a SPA_TYPE_OBJECT_Props */
-+ SPA_CONTROL_Midi, /**< data contains a spa_pod_bytes with raw midi data */
-+ SPA_CONTROL_OSC, /**< data contains a spa_pod_bytes with an OSC packet */
-+
-+ SPA_CONTROL_LAST, /**< not part of ABI */
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_CONTROL_H */
-diff --git a/third_party/pipewire/spa/control/type-info.h b/third_party/pipewire/spa/control/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/control/type-info.h
-@@ -0,0 +1,52 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_CONTROL_TYPES_H
-+#define SPA_CONTROL_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/type-info.h>
-+#include <spa/control/control.h>
-+
-+/* base for parameter object enumerations */
-+#define SPA_TYPE_INFO_Control SPA_TYPE_INFO_ENUM_BASE "Control"
-+#define SPA_TYPE_INFO_CONTROL_BASE SPA_TYPE_INFO_Control ":"
-+
-+static const struct spa_type_info spa_type_control[] = {
-+ { SPA_CONTROL_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Invalid", NULL },
-+ { SPA_CONTROL_Properties, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Properties", NULL },
-+ { SPA_CONTROL_Midi, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "Midi", NULL },
-+ { SPA_CONTROL_OSC, SPA_TYPE_Int, SPA_TYPE_INFO_CONTROL_BASE "OSC", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_CONTROL_TYPES_H */
-diff --git a/third_party/pipewire/spa/debug/buffer.h b/third_party/pipewire/spa/debug/buffer.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/buffer.h
-@@ -0,0 +1,119 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_BUFFER_H
-+#define SPA_DEBUG_BUFFER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/debug/mem.h>
-+#include <spa/debug/types.h>
-+#include <spa/buffer/type-info.h>
-+
-+#ifndef spa_debug
-+#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
-+#endif
-+
-+static inline int spa_debug_buffer(int indent, const struct spa_buffer *buffer)
-+{
-+ uint32_t i;
-+
-+ spa_debug("%*s" "struct spa_buffer %p:", indent, "", buffer);
-+ spa_debug("%*s" " n_metas: %u (at %p)", indent, "", buffer->n_metas, buffer->metas);
-+ for (i = 0; i < buffer->n_metas; i++) {
-+ struct spa_meta *m = &buffer->metas[i];
-+ const char *type_name;
-+
-+ type_name = spa_debug_type_find_name(spa_type_meta_type, m->type);
-+ spa_debug("%*s" " meta %d: type %d (%s), data %p, size %d:", indent, "", i, m->type,
-+ type_name, m->data, m->size);
-+
-+ switch (m->type) {
-+ case SPA_META_Header:
-+ {
-+ struct spa_meta_header *h = (struct spa_meta_header*)m->data;
-+ spa_debug("%*s" " struct spa_meta_header:", indent, "");
-+ spa_debug("%*s" " flags: %08x", indent, "", h->flags);
-+ spa_debug("%*s" " offset: %u", indent, "", h->offset);
-+ spa_debug("%*s" " seq: %" PRIu64, indent, "", h->seq);
-+ spa_debug("%*s" " pts: %" PRIi64, indent, "", h->pts);
-+ spa_debug("%*s" " dts_offset: %" PRIi64, indent, "", h->dts_offset);
-+ break;
-+ }
-+ case SPA_META_VideoCrop:
-+ {
-+ struct spa_meta_region *h = (struct spa_meta_region*)m->data;
-+ spa_debug("%*s" " struct spa_meta_region:", indent, "");
-+ spa_debug("%*s" " x: %d", indent, "", h->region.position.x);
-+ spa_debug("%*s" " y: %d", indent, "", h->region.position.y);
-+ spa_debug("%*s" " width: %d", indent, "", h->region.size.width);
-+ spa_debug("%*s" " height: %d", indent, "", h->region.size.height);
-+ break;
-+ }
-+ case SPA_META_VideoDamage:
-+ {
-+ struct spa_meta_region *h;
-+ spa_meta_for_each(h, m) {
-+ spa_debug("%*s" " struct spa_meta_region:", indent, "");
-+ spa_debug("%*s" " x: %d", indent, "", h->region.position.x);
-+ spa_debug("%*s" " y: %d", indent, "", h->region.position.y);
-+ spa_debug("%*s" " width: %d", indent, "", h->region.size.width);
-+ spa_debug("%*s" " height: %d", indent, "", h->region.size.height);
-+ }
-+ break;
-+ }
-+ case SPA_META_Bitmap:
-+ break;
-+ case SPA_META_Cursor:
-+ break;
-+ default:
-+ spa_debug("%*s" " Unknown:", indent, "");
-+ spa_debug_mem(5, m->data, m->size);
-+ }
-+ }
-+ spa_debug("%*s" " n_datas: \t%u (at %p)", indent, "", buffer->n_datas, buffer->datas);
-+ for (i = 0; i < buffer->n_datas; i++) {
-+ struct spa_data *d = &buffer->datas[i];
-+ spa_debug("%*s" " type: %d (%s)", indent, "", d->type,
-+ spa_debug_type_find_name(spa_type_data_type, d->type));
-+ spa_debug("%*s" " flags: %d", indent, "", d->flags);
-+ spa_debug("%*s" " data: %p", indent, "", d->data);
-+ spa_debug("%*s" " fd: %" PRIi64, indent, "", d->fd);
-+ spa_debug("%*s" " offset: %d", indent, "", d->mapoffset);
-+ spa_debug("%*s" " maxsize: %u", indent, "", d->maxsize);
-+ spa_debug("%*s" " chunk: %p", indent, "", d->chunk);
-+ spa_debug("%*s" " offset: %d", indent, "", d->chunk->offset);
-+ spa_debug("%*s" " size: %u", indent, "", d->chunk->size);
-+ spa_debug("%*s" " stride: %d", indent, "", d->chunk->stride);
-+ }
-+ return 0;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_BUFFER_H */
-diff --git a/third_party/pipewire/spa/debug/dict.h b/third_party/pipewire/spa/debug/dict.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/dict.h
-@@ -0,0 +1,52 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_DICT_H
-+#define SPA_DEBUG_DICT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/dict.h>
-+
-+#ifndef spa_debug
-+#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
-+#endif
-+
-+static inline int spa_debug_dict(int indent, const struct spa_dict *dict)
-+{
-+ const struct spa_dict_item *item;
-+ spa_debug("%*sflags:%08x n_items:%d", indent, "", dict->flags, dict->n_items);
-+ spa_dict_for_each(item, dict) {
-+ spa_debug("%*s %s = \"%s\"", indent, "", item->key, item->value);
-+ }
-+ return 0;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_DICT_H */
-diff --git a/third_party/pipewire/spa/debug/format.h b/third_party/pipewire/spa/debug/format.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/format.h
-@@ -0,0 +1,201 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_FORMAT_H
-+#define SPA_DEBUG_FORMAT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/parser.h>
-+#include <spa/debug/types.h>
-+#include <spa/param/type-info.h>
-+#include <spa/param/format-utils.h>
-+
-+static inline int
-+spa_debug_format_value(const struct spa_type_info *info,
-+ uint32_t type, void *body, uint32_t size)
-+{
-+ switch (type) {
-+ case SPA_TYPE_Bool:
-+ fprintf(stderr, "%s", *(int32_t *) body ? "true" : "false");
-+ break;
-+ case SPA_TYPE_Id:
-+ {
-+ const char *str = spa_debug_type_find_short_name(info, *(int32_t *) body);
-+ char tmp[64];
-+ if (str == NULL) {
-+ snprintf(tmp, sizeof(tmp), "%d", *(int32_t*)body);
-+ str = tmp;
-+ }
-+ fprintf(stderr, "%s", str);
-+ break;
-+ }
-+ case SPA_TYPE_Int:
-+ fprintf(stderr, "%d", *(int32_t *) body);
-+ break;
-+ case SPA_TYPE_Long:
-+ fprintf(stderr, "%" PRIi64, *(int64_t *) body);
-+ break;
-+ case SPA_TYPE_Float:
-+ fprintf(stderr, "%f", *(float *) body);
-+ break;
-+ case SPA_TYPE_Double:
-+ fprintf(stderr, "%g", *(double *) body);
-+ break;
-+ case SPA_TYPE_String:
-+ fprintf(stderr, "%s", (char *) body);
-+ break;
-+ case SPA_TYPE_Rectangle:
-+ {
-+ struct spa_rectangle *r = (struct spa_rectangle *)body;
-+ fprintf(stderr, "%" PRIu32 "x%" PRIu32, r->width, r->height);
-+ break;
-+ }
-+ case SPA_TYPE_Fraction:
-+ {
-+ struct spa_fraction *f = (struct spa_fraction *)body;
-+ fprintf(stderr, "%" PRIu32 "/%" PRIu32, f->num, f->denom);
-+ break;
-+ }
-+ case SPA_TYPE_Bitmap:
-+ fprintf(stderr, "Bitmap");
-+ break;
-+ case SPA_TYPE_Bytes:
-+ fprintf(stderr, "Bytes");
-+ break;
-+ case SPA_TYPE_Array:
-+ {
-+ void *p;
-+ struct spa_pod_array_body *b = (struct spa_pod_array_body *)body;
-+ int i = 0;
-+ fprintf(stderr, "< ");
-+ SPA_POD_ARRAY_BODY_FOREACH(b, size, p) {
-+ if (i++ > 0)
-+ fprintf(stderr, ", ");
-+ spa_debug_format_value(info, b->child.type, p, b->child.size);
-+ }
-+ fprintf(stderr, " >");
-+ break;
-+ }
-+ default:
-+ fprintf(stderr, "INVALID type %d", type);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static inline int spa_debug_format(int indent,
-+ const struct spa_type_info *info, const struct spa_pod *format)
-+{
-+ const char *media_type;
-+ const char *media_subtype;
-+ struct spa_pod_prop *prop;
-+ uint32_t mtype, mstype;
-+
-+ if (info == NULL)
-+ info = spa_type_format;
-+
-+ if (format == NULL || SPA_POD_TYPE(format) != SPA_TYPE_Object)
-+ return -EINVAL;
-+
-+ if (spa_format_parse(format, &mtype, &mstype) < 0)
-+ return -EINVAL;
-+
-+ media_type = spa_debug_type_find_name(spa_type_media_type, mtype);
-+ media_subtype = spa_debug_type_find_name(spa_type_media_subtype, mstype);
-+
-+ fprintf(stderr, "%*s %s/%s\n", indent, "",
-+ media_type ? spa_debug_type_short_name(media_type) : "unknown",
-+ media_subtype ? spa_debug_type_short_name(media_subtype) : "unknown");
-+
-+ SPA_POD_OBJECT_FOREACH((struct spa_pod_object*)format, prop) {
-+ const char *key;
-+ const struct spa_type_info *ti;
-+ uint32_t i, type, size, n_vals, choice;
-+ const struct spa_pod *val;
-+ void *vals;
-+
-+ if (prop->key == SPA_FORMAT_mediaType ||
-+ prop->key == SPA_FORMAT_mediaSubtype)
-+ continue;
-+
-+ val = spa_pod_get_values(&prop->value, &n_vals, &choice);
-+
-+ type = val->type;
-+ size = val->size;
-+ vals = SPA_POD_BODY(val);
-+
-+ if (type < SPA_TYPE_None || type >= SPA_TYPE_LAST)
-+ continue;
-+
-+ ti = spa_debug_type_find(info, prop->key);
-+ key = ti ? ti->name : NULL;
-+
-+ fprintf(stderr, "%*s %16s : (%s) ", indent, "",
-+ key ? spa_debug_type_short_name(key) : "unknown",
-+ spa_debug_type_short_name(spa_types[type].name));
-+
-+ if (choice == SPA_CHOICE_None) {
-+ spa_debug_format_value(ti ? ti->values : NULL, type, vals, size);
-+ } else {
-+ const char *ssep, *esep, *sep;
-+
-+ switch (choice) {
-+ case SPA_CHOICE_Range:
-+ case SPA_CHOICE_Step:
-+ ssep = "[ ";
-+ sep = ", ";
-+ esep = " ]";
-+ break;
-+ default:
-+ case SPA_CHOICE_Enum:
-+ case SPA_CHOICE_Flags:
-+ ssep = "{ ";
-+ sep = ", ";
-+ esep = " }";
-+ break;
-+ }
-+
-+ fprintf(stderr, "%s", ssep);
-+
-+ for (i = 1; i < n_vals; i++) {
-+ vals = SPA_MEMBER(vals, size, void);
-+ if (i > 1)
-+ fprintf(stderr, "%s", sep);
-+ spa_debug_format_value(ti ? ti->values : NULL, type, vals, size);
-+ }
-+ fprintf(stderr, "%s", esep);
-+ }
-+ fprintf(stderr, "\n");
-+ }
-+ return 0;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_FORMAT_H */
-diff --git a/third_party/pipewire/spa/debug/mem.h b/third_party/pipewire/spa/debug/mem.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/mem.h
-@@ -0,0 +1,60 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_MEM_H
-+#define SPA_DEBUG_MEM_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/dict.h>
-+
-+#ifndef spa_debug
-+#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
-+#endif
-+
-+static inline int spa_debug_mem(int indent, const void *data, size_t size)
-+{
-+ const uint8_t *t = (const uint8_t*)data;
-+ char buffer[512];
-+ size_t i;
-+ int pos = 0;
-+
-+ for (i = 0; i < size; i++) {
-+ if (i % 16 == 0)
-+ pos = sprintf(buffer, "%p: ", &t[i]);
-+ pos += sprintf(buffer + pos, "%02x ", t[i]);
-+ if (i % 16 == 15 || i == size - 1) {
-+ spa_debug("%*s" "%s", indent, "", buffer);
-+ }
-+ }
-+ return 0;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_MEM_H */
-diff --git a/third_party/pipewire/spa/debug/node.h b/third_party/pipewire/spa/debug/node.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/node.h
-@@ -0,0 +1,57 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_NODE_H
-+#define SPA_DEBUG_NODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/node/node.h>
-+#include <spa/debug/dict.h>
-+
-+#ifndef spa_debug
-+#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
-+#endif
-+
-+static inline int spa_debug_port_info(int indent, const struct spa_port_info *info)
-+{
-+ spa_debug("%*s" "struct spa_port_info %p:", indent, "", info);
-+ spa_debug("%*s" " flags: \t%08" PRIx64, indent, "", info->flags);
-+ spa_debug("%*s" " rate: \t%d/%d", indent, "", info->rate.num, info->rate.denom);
-+ spa_debug("%*s" " props:", indent, "");
-+ if (info->props)
-+ spa_debug_dict(indent + 2, info->props);
-+ else
-+ spa_debug("%*s" " none", indent, "");
-+ return 0;
-+}
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_NODE_H */
-diff --git a/third_party/pipewire/spa/debug/pod.h b/third_party/pipewire/spa/debug/pod.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/pod.h
-@@ -0,0 +1,207 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_POD_H
-+#define SPA_DEBUG_POD_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/debug/mem.h>
-+#include <spa/debug/types.h>
-+#include <spa/pod/pod.h>
-+#include <spa/pod/iter.h>
-+
-+#ifndef spa_debug
-+#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); })
-+#endif
-+
-+static inline int
-+spa_debug_pod_value(int indent, const struct spa_type_info *info,
-+ uint32_t type, void *body, uint32_t size)
-+{
-+ switch (type) {
-+ case SPA_TYPE_Bool:
-+ spa_debug("%*s" "Bool %s", indent, "", (*(int32_t *) body) ? "true" : "false");
-+ break;
-+ case SPA_TYPE_Id:
-+ spa_debug("%*s" "Id %-8d (%s)", indent, "", *(int32_t *) body,
-+ spa_debug_type_find_name(info, *(int32_t *) body));
-+ break;
-+ case SPA_TYPE_Int:
-+ spa_debug("%*s" "Int %d", indent, "", *(int32_t *) body);
-+ break;
-+ case SPA_TYPE_Long:
-+ spa_debug("%*s" "Long %" PRIi64 "", indent, "", *(int64_t *) body);
-+ break;
-+ case SPA_TYPE_Float:
-+ spa_debug("%*s" "Float %f", indent, "", *(float *) body);
-+ break;
-+ case SPA_TYPE_Double:
-+ spa_debug("%*s" "Double %f", indent, "", *(double *) body);
-+ break;
-+ case SPA_TYPE_String:
-+ spa_debug("%*s" "String \"%s\"", indent, "", (char *) body);
-+ break;
-+ case SPA_TYPE_Fd:
-+ spa_debug("%*s" "Fd %d", indent, "", *(int *) body);
-+ break;
-+ case SPA_TYPE_Pointer:
-+ {
-+ struct spa_pod_pointer_body *b = (struct spa_pod_pointer_body *)body;
-+ spa_debug("%*s" "Pointer %s %p", indent, "",
-+ spa_debug_type_find_name(SPA_TYPE_ROOT, b->type), b->value);
-+ break;
-+ }
-+ case SPA_TYPE_Rectangle:
-+ {
-+ struct spa_rectangle *r = (struct spa_rectangle *)body;
-+ spa_debug("%*s" "Rectangle %dx%d", indent, "", r->width, r->height);
-+ break;
-+ }
-+ case SPA_TYPE_Fraction:
-+ {
-+ struct spa_fraction *f = (struct spa_fraction *)body;
-+ spa_debug("%*s" "Fraction %d/%d", indent, "", f->num, f->denom);
-+ break;
-+ }
-+ case SPA_TYPE_Bitmap:
-+ spa_debug("%*s" "Bitmap", indent, "");
-+ break;
-+ case SPA_TYPE_Array:
-+ {
-+ struct spa_pod_array_body *b = (struct spa_pod_array_body *)body;
-+ void *p;
-+ const struct spa_type_info *ti = spa_debug_type_find(SPA_TYPE_ROOT, b->child.type);
-+
-+ spa_debug("%*s" "Array: child.size %d, child.type %s", indent, "",
-+ b->child.size, ti ? ti->name : "unknown");
-+
-+ SPA_POD_ARRAY_BODY_FOREACH(b, size, p)
-+ spa_debug_pod_value(indent + 2, info, b->child.type, p, b->child.size);
-+ break;
-+ }
-+ case SPA_TYPE_Choice:
-+ {
-+ struct spa_pod_choice_body *b = (struct spa_pod_choice_body *)body;
-+ void *p;
-+ const struct spa_type_info *ti = spa_debug_type_find(spa_type_choice, b->type);
-+
-+ spa_debug("%*s" "Choice: type %s, flags %08x %d %d", indent, "",
-+ ti ? ti->name : "unknown", b->flags, size, b->child.size);
-+
-+ SPA_POD_CHOICE_BODY_FOREACH(b, size, p)
-+ spa_debug_pod_value(indent + 2, info, b->child.type, p, b->child.size);
-+ break;
-+ }
-+ case SPA_TYPE_Struct:
-+ {
-+ struct spa_pod *b = (struct spa_pod *)body, *p;
-+ spa_debug("%*s" "Struct: size %d", indent, "", size);
-+ SPA_POD_FOREACH(b, size, p)
-+ spa_debug_pod_value(indent + 2, info, p->type, SPA_POD_BODY(p), p->size);
-+ break;
-+ }
-+ case SPA_TYPE_Object:
-+ {
-+ struct spa_pod_object_body *b = (struct spa_pod_object_body *)body;
-+ struct spa_pod_prop *p;
-+ const struct spa_type_info *ti, *ii;
-+
-+ ti = spa_debug_type_find(info, b->type);
-+ ii = ti ? spa_debug_type_find(ti->values, 0) : NULL;
-+ ii = ii ? spa_debug_type_find(ii->values, b->id) : NULL;
-+
-+ spa_debug("%*s" "Object: size %d, type %s (%d), id %s (%d)", indent, "", size,
-+ ti ? ti->name : "unknown", b->type, ii ? ii->name : "unknown", b->id);
-+
-+ info = ti ? ti->values : info;
-+
-+ SPA_POD_OBJECT_BODY_FOREACH(b, size, p) {
-+ ii = spa_debug_type_find(info, p->key);
-+
-+ spa_debug("%*s" "Prop: key %s (%d), flags %08x", indent+2, "",
-+ ii ? ii->name : "unknown", p->key, p->flags);
-+
-+ spa_debug_pod_value(indent + 4, ii ? ii->values : NULL,
-+ p->value.type,
-+ SPA_POD_CONTENTS(struct spa_pod_prop, p),
-+ p->value.size);
-+ }
-+ break;
-+ }
-+ case SPA_TYPE_Sequence:
-+ {
-+ struct spa_pod_sequence_body *b = (struct spa_pod_sequence_body *)body;
-+ const struct spa_type_info *ti, *ii;
-+ struct spa_pod_control *c;
-+
-+ ti = spa_debug_type_find(info, b->unit);
-+
-+ spa_debug("%*s" "Sequence: size %d, unit %s", indent, "", size,
-+ ti ? ti->name : "unknown");
-+
-+ SPA_POD_SEQUENCE_BODY_FOREACH(b, size, c) {
-+ ii = spa_debug_type_find(spa_type_control, c->type);
-+
-+ spa_debug("%*s" "Control: offset %d, type %s", indent+2, "",
-+ c->offset, ii ? ii->name : "unknown");
-+
-+ spa_debug_pod_value(indent + 4, ii ? ii->values : NULL,
-+ c->value.type,
-+ SPA_POD_CONTENTS(struct spa_pod_control, c),
-+ c->value.size);
-+ }
-+ break;
-+ }
-+ case SPA_TYPE_Bytes:
-+ spa_debug("%*s" "Bytes", indent, "");
-+ spa_debug_mem(indent + 2, body, size);
-+ break;
-+ case SPA_TYPE_None:
-+ spa_debug("%*s" "None", indent, "");
-+ spa_debug_mem(indent + 2, body, size);
-+ break;
-+ default:
-+ spa_debug("%*s" "unhandled POD type %d", indent, "", type);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static inline int spa_debug_pod(int indent,
-+ const struct spa_type_info *info, const struct spa_pod *pod)
-+{
-+ return spa_debug_pod_value(indent, info ? info : SPA_TYPE_ROOT,
-+ SPA_POD_TYPE(pod),
-+ SPA_POD_BODY(pod),
-+ SPA_POD_BODY_SIZE(pod));
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_POD_H */
-diff --git a/third_party/pipewire/spa/debug/types.h b/third_party/pipewire/spa/debug/types.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/debug/types.h
-@@ -0,0 +1,98 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEBUG_TYPES_H
-+#define SPA_DEBUG_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/type-info.h>
-+
-+#include <string.h>
-+
-+static inline const struct spa_type_info *spa_debug_type_find(const struct spa_type_info *info, uint32_t type)
-+{
-+ const struct spa_type_info *res;
-+
-+ if (info == NULL)
-+ info = SPA_TYPE_ROOT;
-+
-+ while (info && info->name) {
-+ if (info->type == SPA_ID_INVALID) {
-+ if (info->values && (res = spa_debug_type_find(info->values, type)))
-+ return res;
-+ }
-+ else if (info->type == type)
-+ return info;
-+ info++;
-+ }
-+ return NULL;
-+}
-+
-+static inline const char *spa_debug_type_short_name(const char *name)
-+{
-+ const char *h;
-+ if ((h = strrchr(name, ':')) != NULL)
-+ name = h + 1;
-+ return name;
-+}
-+
-+static inline const char *spa_debug_type_find_name(const struct spa_type_info *info, uint32_t type)
-+{
-+ if ((info = spa_debug_type_find(info, type)) == NULL)
-+ return NULL;
-+ return info->name;
-+}
-+
-+static inline const char *spa_debug_type_find_short_name(const struct spa_type_info *info, uint32_t type)
-+{
-+ const char *str;
-+ if ((str = spa_debug_type_find_name(info, type)) == NULL)
-+ return NULL;
-+ return spa_debug_type_short_name(str);
-+}
-+
-+static inline uint32_t spa_debug_type_find_type(const struct spa_type_info *info, const char *name)
-+{
-+ if (info == NULL)
-+ info = SPA_TYPE_ROOT;
-+
-+ while (info && info->name) {
-+ uint32_t res;
-+ if (strcmp(info->name, name) == 0)
-+ return info->type;
-+ if (info->values && (res = spa_debug_type_find_type(info->values, name)) != SPA_ID_INVALID)
-+ return res;
-+ info++;
-+ }
-+ return SPA_ID_INVALID;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEBUG_NODE_H */
-diff --git a/third_party/pipewire/spa/graph/graph.h b/third_party/pipewire/spa/graph/graph.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/graph/graph.h
-@@ -0,0 +1,352 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_GRAPH_H
-+#define SPA_GRAPH_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/list.h>
-+#include <spa/utils/hook.h>
-+#include <spa/node/node.h>
-+#include <spa/node/io.h>
-+
-+#ifndef spa_debug
-+#define spa_debug(...)
-+#endif
-+
-+struct spa_graph;
-+struct spa_graph_node;
-+struct spa_graph_link;
-+struct spa_graph_port;
-+
-+struct spa_graph_state {
-+ int status; /**< current status */
-+ int32_t required; /**< required number of signals */
-+ int32_t pending; /**< number of pending signals */
-+};
-+
-+static inline void spa_graph_state_reset(struct spa_graph_state *state)
-+{
-+ state->pending = state->required;
-+}
-+
-+struct spa_graph_link {
-+ struct spa_list link;
-+ struct spa_graph_state *state;
-+ int (*signal) (void *data);
-+ void *signal_data;
-+};
-+
-+#define spa_graph_link_signal(l) ((l)->signal((l)->signal_data))
-+
-+#define spa_graph_state_dec(s,c) (__atomic_sub_fetch(&(s)->pending, c, __ATOMIC_SEQ_CST) == 0)
-+
-+static inline int spa_graph_link_trigger(struct spa_graph_link *link)
-+{
-+ struct spa_graph_state *state = link->state;
-+
-+ spa_debug("link %p: state %p: pending %d/%d", link, state,
-+ state->pending, state->required);
-+
-+ if (spa_graph_state_dec(state, 1))
-+ spa_graph_link_signal(link);
-+
-+ return state->status;
-+}
-+struct spa_graph {
-+ uint32_t flags; /* flags */
-+ struct spa_graph_node *parent; /* parent node or NULL when driver */
-+ struct spa_graph_state *state; /* state of graph */
-+ struct spa_list nodes; /* list of nodes of this graph */
-+};
-+
-+struct spa_graph_node_callbacks {
-+#define SPA_VERSION_GRAPH_NODE_CALLBACKS 0
-+ uint32_t version;
-+
-+ int (*process) (void *data, struct spa_graph_node *node);
-+ int (*reuse_buffer) (void *data, struct spa_graph_node *node,
-+ uint32_t port_id, uint32_t buffer_id);
-+};
-+
-+struct spa_graph_node {
-+ struct spa_list link; /**< link in graph nodes list */
-+ struct spa_graph *graph; /**< owner graph */
-+ struct spa_list ports[2]; /**< list of input and output ports */
-+ struct spa_list links; /**< list of links to next nodes */
-+ uint32_t flags; /**< node flags */
-+ struct spa_graph_state *state; /**< state of the node */
-+ struct spa_graph_link graph_link; /**< link in graph */
-+ struct spa_graph *subgraph; /**< subgraph or NULL */
-+ struct spa_callbacks callbacks;
-+ struct spa_list sched_link; /**< link for scheduler */
-+};
-+
-+#define spa_graph_node_call(n,method,version,...) \
-+({ \
-+ int __res = 0; \
-+ spa_callbacks_call_res(&(n)->callbacks, \
-+ struct spa_graph_node_callbacks, __res, \
-+ method, version, ##__VA_ARGS__); \
-+ __res; \
-+})
-+
-+#define spa_graph_node_process(n) spa_graph_node_call(n, process, 0, n)
-+#define spa_graph_node_reuse_buffer(n,p,i) spa_graph_node_call(n, reuse_buffer, 0, n, p, i)
-+
-+struct spa_graph_port {
-+ struct spa_list link; /**< link in node port list */
-+ struct spa_graph_node *node; /**< owner node */
-+ enum spa_direction direction; /**< port direction */
-+ uint32_t port_id; /**< port id */
-+ uint32_t flags; /**< port flags */
-+ struct spa_graph_port *peer; /**< peer */
-+};
-+
-+static inline int spa_graph_node_trigger(struct spa_graph_node *node)
-+{
-+ struct spa_graph_link *l;
-+ spa_debug("node %p trigger", node);
-+ spa_list_for_each(l, &node->links, link)
-+ spa_graph_link_trigger(l);
-+ return 0;
-+}
-+
-+static inline int spa_graph_run(struct spa_graph *graph)
-+{
-+ struct spa_graph_node *n, *t;
-+ struct spa_list pending;
-+
-+ spa_graph_state_reset(graph->state);
-+ spa_debug("graph %p run with state %p pending %d/%d", graph, graph->state,
-+ graph->state->pending, graph->state->required);
-+
-+ spa_list_init(&pending);
-+
-+ spa_list_for_each(n, &graph->nodes, link) {
-+ struct spa_graph_state *s = n->state;
-+ spa_graph_state_reset(s);
-+ spa_debug("graph %p node %p: state %p pending %d/%d status %d", graph, n,
-+ s, s->pending, s->required, s->status);
-+ if (--s->pending == 0)
-+ spa_list_append(&pending, &n->sched_link);
-+ }
-+ spa_list_for_each_safe(n, t, &pending, sched_link)
-+ spa_graph_node_process(n);
-+
-+ return 0;
-+}
-+
-+static inline int spa_graph_finish(struct spa_graph *graph)
-+{
-+ spa_debug("graph %p finish", graph);
-+ if (graph->parent)
-+ return spa_graph_node_trigger(graph->parent);
-+ return 0;
-+}
-+static inline int spa_graph_link_signal_node(void *data)
-+{
-+ struct spa_graph_node *node = (struct spa_graph_node *)data;
-+ spa_debug("node %p call process", node);
-+ return spa_graph_node_process(node);
-+}
-+
-+static inline int spa_graph_link_signal_graph(void *data)
-+{
-+ struct spa_graph_node *node = (struct spa_graph_node *)data;
-+ return spa_graph_finish(node->graph);
-+}
-+
-+static inline void spa_graph_init(struct spa_graph *graph, struct spa_graph_state *state)
-+{
-+ spa_list_init(&graph->nodes);
-+ graph->flags = 0;
-+ graph->state = state;
-+ spa_debug("graph %p init state %p", graph, state);
-+}
-+
-+static inline void
-+spa_graph_link_add(struct spa_graph_node *out,
-+ struct spa_graph_state *state,
-+ struct spa_graph_link *link)
-+{
-+ link->state = state;
-+ state->required++;
-+ spa_debug("node %p add link %p to state %p %d", out, link, state, state->required);
-+ spa_list_append(&out->links, &link->link);
-+}
-+
-+static inline void spa_graph_link_remove(struct spa_graph_link *link)
-+{
-+ link->state->required--;
-+ spa_debug("link %p state %p remove %d", link, link->state, link->state->required);
-+ spa_list_remove(&link->link);
-+}
-+
-+static inline void
-+spa_graph_node_init(struct spa_graph_node *node, struct spa_graph_state *state)
-+{
-+ spa_list_init(&node->ports[SPA_DIRECTION_INPUT]);
-+ spa_list_init(&node->ports[SPA_DIRECTION_OUTPUT]);
-+ spa_list_init(&node->links);
-+ node->flags = 0;
-+ node->subgraph = NULL;
-+ node->state = state;
-+ node->state->required = node->state->pending = 0;
-+ node->state->status = SPA_STATUS_OK;
-+ node->graph_link.signal = spa_graph_link_signal_graph;
-+ node->graph_link.signal_data = node;
-+ spa_debug("node %p init state %p", node, state);
-+}
-+
-+
-+static inline int spa_graph_node_impl_sub_process(void *data, struct spa_graph_node *node)
-+{
-+ struct spa_graph *graph = node->subgraph;
-+ spa_debug("node %p: sub process %p", node, graph);
-+ return spa_graph_run(graph);
-+}
-+
-+static const struct spa_graph_node_callbacks spa_graph_node_sub_impl_default = {
-+ SPA_VERSION_GRAPH_NODE_CALLBACKS,
-+ .process = spa_graph_node_impl_sub_process,
-+};
-+
-+static inline void spa_graph_node_set_subgraph(struct spa_graph_node *node,
-+ struct spa_graph *subgraph)
-+{
-+ node->subgraph = subgraph;
-+ subgraph->parent = node;
-+ spa_debug("node %p set subgraph %p", node, subgraph);
-+}
-+
-+static inline void
-+spa_graph_node_set_callbacks(struct spa_graph_node *node,
-+ const struct spa_graph_node_callbacks *callbacks,
-+ void *data)
-+{
-+ node->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
-+}
-+
-+static inline void
-+spa_graph_node_add(struct spa_graph *graph,
-+ struct spa_graph_node *node)
-+{
-+ node->graph = graph;
-+ spa_list_append(&graph->nodes, &node->link);
-+ node->state->required++;
-+ spa_debug("node %p add to graph %p, state %p required %d",
-+ node, graph, node->state, node->state->required);
-+ spa_graph_link_add(node, graph->state, &node->graph_link);
-+}
-+
-+static inline void spa_graph_node_remove(struct spa_graph_node *node)
-+{
-+ spa_debug("node %p remove from graph %p, state %p required %d",
-+ node, node->graph, node->state, node->state->required);
-+ spa_graph_link_remove(&node->graph_link);
-+ node->state->required--;
-+ spa_list_remove(&node->link);
-+}
-+
-+
-+static inline void
-+spa_graph_port_init(struct spa_graph_port *port,
-+ enum spa_direction direction,
-+ uint32_t port_id,
-+ uint32_t flags)
-+{
-+ spa_debug("port %p init type %d id %d", port, direction, port_id);
-+ port->direction = direction;
-+ port->port_id = port_id;
-+ port->flags = flags;
-+}
-+
-+static inline void
-+spa_graph_port_add(struct spa_graph_node *node,
-+ struct spa_graph_port *port)
-+{
-+ spa_debug("port %p add to node %p", port, node);
-+ port->node = node;
-+ spa_list_append(&node->ports[port->direction], &port->link);
-+}
-+
-+static inline void spa_graph_port_remove(struct spa_graph_port *port)
-+{
-+ spa_debug("port %p remove", port);
-+ spa_list_remove(&port->link);
-+}
-+
-+static inline void
-+spa_graph_port_link(struct spa_graph_port *out, struct spa_graph_port *in)
-+{
-+ spa_debug("port %p link to %p %p %p", out, in, in->node, in->node->state);
-+ out->peer = in;
-+ in->peer = out;
-+}
-+
-+static inline void
-+spa_graph_port_unlink(struct spa_graph_port *port)
-+{
-+ spa_debug("port %p unlink from %p", port, port->peer);
-+ if (port->peer) {
-+ port->peer->peer = NULL;
-+ port->peer = NULL;
-+ }
-+}
-+
-+static inline int spa_graph_node_impl_process(void *data, struct spa_graph_node *node)
-+{
-+ struct spa_node *n = (struct spa_node *)data;
-+ struct spa_graph_state *state = node->state;
-+
-+ spa_debug("node %p: process state %p: %d, node %p", node, state, state->status, n);
-+ if ((state->status = spa_node_process(n)) != SPA_STATUS_OK)
-+ spa_graph_node_trigger(node);
-+
-+ return state->status;
-+}
-+
-+static inline int spa_graph_node_impl_reuse_buffer(void *data, struct spa_graph_node *node,
-+ uint32_t port_id, uint32_t buffer_id)
-+{
-+ struct spa_node *n = (struct spa_node *)data;
-+ return spa_node_port_reuse_buffer(n, port_id, buffer_id);
-+}
-+
-+static const struct spa_graph_node_callbacks spa_graph_node_impl_default = {
-+ SPA_VERSION_GRAPH_NODE_CALLBACKS,
-+ .process = spa_graph_node_impl_process,
-+ .reuse_buffer = spa_graph_node_impl_reuse_buffer,
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_GRAPH_H */
-diff --git a/third_party/pipewire/spa/monitor/device.h b/third_party/pipewire/spa/monitor/device.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/monitor/device.h
-@@ -0,0 +1,297 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEVICE_H
-+#define SPA_DEVICE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+#include <spa/utils/dict.h>
-+#include <spa/pod/event.h>
-+
-+/**
-+ * spa_device:
-+ *
-+ * The device interface can be used to monitor all kinds of devices
-+ * and create objects as a result. Objects a typically other
-+ * Devices or Nodes.
-+ *
-+ */
-+#define SPA_TYPE_INTERFACE_Device SPA_TYPE_INFO_INTERFACE_BASE "Device"
-+
-+#define SPA_VERSION_DEVICE 0
-+struct spa_device { struct spa_interface iface; };
-+
-+/**
-+ * Information about the device and parameters it supports
-+ *
-+ * This information is part of the info event on a device.
-+ */
-+struct spa_device_info {
-+#define SPA_VERSION_DEVICE_INFO 0
-+ uint32_t version;
-+
-+#define SPA_DEVICE_CHANGE_MASK_FLAGS (1u<<0)
-+#define SPA_DEVICE_CHANGE_MASK_PROPS (1u<<1)
-+#define SPA_DEVICE_CHANGE_MASK_PARAMS (1u<<2)
-+ uint64_t change_mask;
-+ uint64_t flags;
-+ const struct spa_dict *props; /**< device properties */
-+ struct spa_param_info *params; /**< supported parameters */
-+ uint32_t n_params; /**< number of elements in params */
-+};
-+
-+#define SPA_DEVICE_INFO_INIT() (struct spa_device_info){ SPA_VERSION_DEVICE_INFO, }
-+
-+/**
-+ * Information about a device object
-+ *
-+ * This information is part of the object_info event on the device.
-+ */
-+struct spa_device_object_info {
-+#define SPA_VERSION_DEVICE_OBJECT_INFO 0
-+ uint32_t version;
-+
-+ const char *type; /**< the object type managed by this device */
-+ const char *factory_name; /**< a factory name that implements the object */
-+
-+#define SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS (1u<<0)
-+#define SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS (1u<<1)
-+ uint64_t change_mask;
-+ uint64_t flags;
-+ const struct spa_dict *props; /**< extra object properties */
-+};
-+
-+#define SPA_DEVICE_OBJECT_INFO_INIT() (struct spa_device_object_info){ SPA_VERSION_DEVICE_OBJECT_INFO, }
-+
-+/** the result of spa_device_enum_params() */
-+#define SPA_RESULT_TYPE_DEVICE_PARAMS 1
-+struct spa_result_device_params {
-+ uint32_t id;
-+ uint32_t index;
-+ uint32_t next;
-+ struct spa_pod *param;
-+};
-+
-+#define SPA_DEVICE_EVENT_INFO 0
-+#define SPA_DEVICE_EVENT_RESULT 1
-+#define SPA_DEVICE_EVENT_EVENT 2
-+#define SPA_DEVICE_EVENT_OBJECT_INFO 3
-+#define SPA_DEVICE_EVENT_NUM 4
-+
-+/**
-+ * spa_device_events:
-+ *
-+ * Events are always emitted from the main thread
-+ */
-+struct spa_device_events {
-+ /** version of the structure */
-+#define SPA_VERSION_DEVICE_EVENTS 0
-+ uint32_t version;
-+
-+ /** notify extra information about the device */
-+ void (*info) (void *data, const struct spa_device_info *info);
-+
-+ /** notify a result */
-+ void (*result) (void *data, int seq, int res, uint32_t type, const void *result);
-+
-+ /** a device event */
-+ void (*event) (void *data, const struct spa_event *event);
-+
-+ /** info changed for an object managed by the device, info is NULL when
-+ * the object is removed */
-+ void (*object_info) (void *data, uint32_t id,
-+ const struct spa_device_object_info *info);
-+};
-+
-+#define SPA_DEVICE_METHOD_ADD_LISTENER 0
-+#define SPA_DEVICE_METHOD_SYNC 1
-+#define SPA_DEVICE_METHOD_ENUM_PARAMS 2
-+#define SPA_DEVICE_METHOD_SET_PARAM 3
-+#define SPA_DEVICE_METHOD_NUM 4
-+
-+/**
-+ * spa_device_methods:
-+ */
-+struct spa_device_methods {
-+ /* the version of the methods. This can be used to expand this
-+ * structure in the future */
-+#define SPA_VERSION_DEVICE_METHODS 0
-+ uint32_t version;
-+
-+ /**
-+ * Set events to receive asynchronous notifications from
-+ * the device.
-+ *
-+ * Setting the events will trigger the info event and an
-+ * object_info event for each managed object on the new
-+ * listener.
-+ *
-+ * \param device a #spa_device
-+ * \param listener a listener
-+ * \param events a #struct spa_device_events
-+ * \param data data passed as first argument in functions of \a events
-+ * \return 0 on success
-+ * < 0 errno on error
-+ */
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct spa_device_events *events,
-+ void *data);
-+ /**
-+ * Perform a sync operation.
-+ *
-+ * This method will emit the result event with the given sequence
-+ * number synchronously or with the returned async return value
-+ * asynchronously.
-+ *
-+ * Because all methods are serialized in the device, this can be used
-+ * to wait for completion of all previous method calls.
-+ *
-+ * \param seq a sequence number
-+ * \return 0 on success
-+ * -EINVAL when node is NULL
-+ * an async result
-+ */
-+ int (*sync) (void *object, int seq);
-+
-+ /**
-+ * Enumerate the parameters of a device.
-+ *
-+ * Parameters are identified with an \a id. Some parameters can have
-+ * multiple values, see the documentation of the parameter id.
-+ *
-+ * Parameters can be filtered by passing a non-NULL \a filter.
-+ *
-+ * The result callback will be called at most \max times with a
-+ * struct spa_result_device_params as the result.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param device a \ref spa_device
-+ * \param seq a sequence number to pass to the result function
-+ * \param id the param id to enumerate
-+ * \param index the index of enumeration, pass 0 for the first item.
-+ * \param max the maximum number of items to iterate
-+ * \param filter and optional filter to use
-+ * \return 0 when there are no more parameters to enumerate
-+ * -EINVAL when invalid arguments are given
-+ * -ENOENT the parameter \a id is unknown
-+ * -ENOTSUP when there are no parameters
-+ * implemented on \a device
-+ */
-+ int (*enum_params) (void *object, int seq,
-+ uint32_t id, uint32_t index, uint32_t max,
-+ const struct spa_pod *filter);
-+
-+ /**
-+ * Set the configurable parameter in \a device.
-+ *
-+ * Usually, \a param will be obtained from enum_params and then
-+ * modified but it is also possible to set another spa_pod
-+ * as long as its keys and types match a supported object.
-+ *
-+ * Objects with property keys that are not known are ignored.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param device a \ref spa_device
-+ * \param id the parameter id to configure
-+ * \param flags additional flags
-+ * \param param the parameter to configure
-+ *
-+ * \return 0 on success
-+ * -EINVAL when invalid arguments are given
-+ * -ENOTSUP when there are no parameters implemented on \a device
-+ * -ENOENT the parameter is unknown
-+ */
-+ int (*set_param) (void *object,
-+ uint32_t id, uint32_t flags,
-+ const struct spa_pod *param);
-+};
-+
-+#define spa_device_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_device *_o = o; \
-+ spa_interface_call_res(&_o->iface, \
-+ struct spa_device_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define spa_device_add_listener(d,...) spa_device_method(d, add_listener, 0, __VA_ARGS__)
-+#define spa_device_sync(d,...) spa_device_method(d, sync, 0, __VA_ARGS__)
-+#define spa_device_enum_params(d,...) spa_device_method(d, enum_params, 0, __VA_ARGS__)
-+#define spa_device_set_param(d,...) spa_device_method(d, set_param, 0, __VA_ARGS__)
-+
-+#define SPA_KEY_DEVICE_ENUM_API "device.enum.api" /**< the api used to discover this
-+ * device */
-+#define SPA_KEY_DEVICE_API "device.api" /**< the api used by the device
-+ * Ex. "udev", "alsa", "v4l2". */
-+#define SPA_KEY_DEVICE_NAME "device.name" /**< the name of the device */
-+#define SPA_KEY_DEVICE_ALIAS "device.alias" /**< alternative name of the device */
-+#define SPA_KEY_DEVICE_NICK "device.nick" /**< the device short name */
-+#define SPA_KEY_DEVICE_DESCRIPTION "device.description" /**< a device description */
-+#define SPA_KEY_DEVICE_ICON "device.icon" /**< icon for the device. A base64 blob
-+ * containing PNG image data */
-+#define SPA_KEY_DEVICE_ICON_NAME "device.icon-name" /**< an XDG icon name for the device.
-+ * Ex. "sound-card-speakers-usb" */
-+#define SPA_KEY_DEVICE_PLUGGED_USEC "device.plugged.usec" /**< when the device was plugged */
-+
-+#define SPA_KEY_DEVICE_BUS_ID "device.bus-id" /**< the device bus-id */
-+#define SPA_KEY_DEVICE_BUS_PATH "device.bus-path" /**< bus path to the device in the OS'
-+ * format.
-+ * Ex. "pci-0000:00:14.0-usb-0:3.2:1.0" */
-+#define SPA_KEY_DEVICE_BUS "device.bus" /**< bus of the device if applicable. One of
-+ * "isa", "pci", "usb", "firewire",
-+ * "bluetooth" */
-+#define SPA_KEY_DEVICE_SUBSYSTEM "device.subsystem" /**< device subsystem */
-+#define SPA_KEY_DEVICE_SYSFS_PATH "device.sysfs.path" /**< device sysfs path */
-+
-+#define SPA_KEY_DEVICE_VENDOR_ID "device.vendor.id" /**< vendor ID if applicable */
-+#define SPA_KEY_DEVICE_VENDOR_NAME "device.vendor.name" /**< vendor name if applicable */
-+#define SPA_KEY_DEVICE_PRODUCT_ID "device.product.id" /**< product ID if applicable */
-+#define SPA_KEY_DEVICE_PRODUCT_NAME "device.product.name" /**< product name if applicable */
-+#define SPA_KEY_DEVICE_SERIAL "device.serial" /**< Serial number if applicable */
-+#define SPA_KEY_DEVICE_CLASS "device.class" /**< device class */
-+#define SPA_KEY_DEVICE_CAPABILITIES "device.capabilities" /**< api specific device capabilities */
-+#define SPA_KEY_DEVICE_FORM_FACTOR "device.form-factor" /**< form factor if applicable. One of
-+ * "internal", "speaker", "handset", "tv",
-+ * "webcam", "microphone", "headset",
-+ * "headphone", "hands-free", "car", "hifi",
-+ * "computer", "portable" */
-+#define SPA_KEY_DEVICE_PROFILE "device.profile " /**< profile for the device */
-+#define SPA_KEY_DEVICE_PROFILE_SET "device.profile-set" /**< profile set for the device */
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEVICE_H */
-diff --git a/third_party/pipewire/spa/monitor/event.h b/third_party/pipewire/spa/monitor/event.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/monitor/event.h
-@@ -0,0 +1,54 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2020 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_EVENT_DEVICE_H
-+#define SPA_EVENT_DEVICE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/event.h>
-+
-+/* object id of SPA_TYPE_EVENT_Device */
-+enum spa_device_event {
-+ SPA_DEVICE_EVENT_ObjectConfig,
-+};
-+
-+#define SPA_DEVICE_EVENT_ID(ev) SPA_EVENT_ID(ev, SPA_TYPE_EVENT_Device)
-+#define SPA_DEVICE_EVENT_INIT(id) SPA_EVENT_INIT(SPA_TYPE_EVENT_Device, id)
-+
-+/* properties for SPA_TYPE_EVENT_Device */
-+enum spa_event_device {
-+ SPA_EVENT_DEVICE_START,
-+
-+ SPA_EVENT_DEVICE_Object, /* an object id (Int) */
-+ SPA_EVENT_DEVICE_Props, /* properties for an object (SPA_TYPE_OBJECT_Props) */
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_EVENT_DEVICE */
-diff --git a/third_party/pipewire/spa/monitor/utils.h b/third_party/pipewire/spa/monitor/utils.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/monitor/utils.h
-@@ -0,0 +1,95 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DEVICE_UTILS_H
-+#define SPA_DEVICE_UTILS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/builder.h>
-+#include <spa/monitor/device.h>
-+
-+struct spa_result_device_params_data {
-+ struct spa_pod_builder *builder;
-+ struct spa_result_device_params data;
-+};
-+
-+static inline void spa_result_func_device_params(void *data, int seq, int res,
-+ uint32_t type, const void *result)
-+{
-+ struct spa_result_device_params_data *d =
-+ (struct spa_result_device_params_data *)data;
-+ const struct spa_result_device_params *r =
-+ (const struct spa_result_device_params *)result;
-+ uint32_t offset = d->builder->state.offset;
-+ spa_pod_builder_raw_padded(d->builder, r->param, SPA_POD_SIZE(r->param));
-+ d->data.next = r->next;
-+ d->data.param = SPA_MEMBER(d->builder->data, offset, struct spa_pod);
-+}
-+
-+static inline int spa_device_enum_params_sync(struct spa_device *device,
-+ uint32_t id, uint32_t *index,
-+ const struct spa_pod *filter,
-+ struct spa_pod **param,
-+ struct spa_pod_builder *builder)
-+{
-+ struct spa_result_device_params_data data = { builder, };
-+ struct spa_hook listener = { 0 };
-+ static const struct spa_device_events device_events = {
-+ SPA_VERSION_DEVICE_EVENTS,
-+ .result = spa_result_func_device_params,
-+ };
-+ int res;
-+
-+ spa_device_add_listener(device, &listener, &device_events, &data);
-+ res = spa_device_enum_params(device, 0, id, *index, 1, filter);
-+ spa_hook_remove(&listener);
-+
-+ if (data.data.param == NULL) {
-+ if (res > 0)
-+ res = 0;
-+ } else {
-+ *index = data.data.next;
-+ *param = data.data.param;
-+ res = 1;
-+ }
-+ return res;
-+}
-+
-+#define spa_device_emit(hooks,method,version,...) \
-+ spa_hook_list_call_simple(hooks, struct spa_device_events, \
-+ method, version, ##__VA_ARGS__)
-+
-+#define spa_device_emit_info(hooks,i) spa_device_emit(hooks,info, 0, i)
-+#define spa_device_emit_result(hooks,s,r,t,res) spa_device_emit(hooks,result, 0, s, r, t, res)
-+#define spa_device_emit_event(hooks,e) spa_device_emit(hooks,event, 0, e)
-+#define spa_device_emit_object_info(hooks,id,i) spa_device_emit(hooks,object_info, 0, id, i)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DEVICE_UTILS_H */
-diff --git a/third_party/pipewire/spa/node/command.h b/third_party/pipewire/spa/node/command.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/command.h
-@@ -0,0 +1,54 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_COMMAND_NODE_H
-+#define SPA_COMMAND_NODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/command.h>
-+
-+/* object id of SPA_TYPE_COMMAND_Node */
-+enum spa_node_command {
-+ SPA_NODE_COMMAND_Suspend,
-+ SPA_NODE_COMMAND_Pause,
-+ SPA_NODE_COMMAND_Start,
-+ SPA_NODE_COMMAND_Enable,
-+ SPA_NODE_COMMAND_Disable,
-+ SPA_NODE_COMMAND_Flush,
-+ SPA_NODE_COMMAND_Drain,
-+ SPA_NODE_COMMAND_Marker,
-+};
-+
-+#define SPA_NODE_COMMAND_ID(cmd) SPA_COMMAND_ID(cmd, SPA_TYPE_COMMAND_Node)
-+#define SPA_NODE_COMMAND_INIT(id) SPA_COMMAND_INIT(SPA_TYPE_COMMAND_Node, id)
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_COMMAND_NODE_H */
-diff --git a/third_party/pipewire/spa/node/event.h b/third_party/pipewire/spa/node/event.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/event.h
-@@ -0,0 +1,48 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_EVENT_NODE_H
-+#define SPA_EVENT_NODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/event.h>
-+
-+/* object id of SPA_TYPE_EVENT_Node */
-+enum spa_node_event {
-+ SPA_NODE_EVENT_Error,
-+ SPA_NODE_EVENT_Buffering,
-+ SPA_NODE_EVENT_RequestRefresh,
-+};
-+
-+#define SPA_NODE_EVENT_ID(ev) SPA_EVENT_ID(ev, SPA_TYPE_EVENT_Node)
-+#define SPA_NODE_EVENT_INIT(id) SPA_EVENT_INIT(SPA_TYPE_EVENT_Node, id)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_EVENT_NODE_H */
-diff --git a/third_party/pipewire/spa/node/io.h b/third_party/pipewire/spa/node/io.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/io.h
-@@ -0,0 +1,294 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_IO_H
-+#define SPA_IO_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/pod/pod.h>
-+
-+/** IO areas
-+ *
-+ * IO information for a port on a node. This is allocated
-+ * by the host and configured on a node or all ports for which
-+ * IO is requested.
-+ *
-+ * The plugin will communicate with the host through the IO
-+ * areas.
-+ */
-+
-+/** Different IO area types */
-+enum spa_io_type {
-+ SPA_IO_Invalid,
-+ SPA_IO_Buffers, /**< area to exchange buffers, struct spa_io_buffers */
-+ SPA_IO_Range, /**< expected byte range, struct spa_io_range */
-+ SPA_IO_Clock, /**< area to update clock information, struct spa_io_clock */
-+ SPA_IO_Latency, /**< latency reporting, struct spa_io_latency */
-+ SPA_IO_Control, /**< area for control messages, struct spa_io_sequence */
-+ SPA_IO_Notify, /**< area for notify messages, struct spa_io_sequence */
-+ SPA_IO_Position, /**< position information in the graph, struct spa_io_position */
-+ SPA_IO_RateMatch, /**< rate matching between nodes, struct spa_io_rate_match */
-+ SPA_IO_Memory, /**< memory pointer, struct spa_io_memory */
-+};
-+
-+/**
-+ * IO area to exchange buffers.
-+ *
-+ * A set of buffers should first be configured on the node/port.
-+ * Further references to those buffers will be made by using the
-+ * id of the buffer.
-+ *
-+ * If status is SPA_STATUS_OK, the host should ignore
-+ * the io area.
-+ *
-+ * If status is SPA_STATUS_NEED_DATA, the host should:
-+ * 1) recycle the buffer in buffer_id, if possible
-+ * 2) prepare a new buffer and place the id in buffer_id.
-+ *
-+ * If status is SPA_STATUS_HAVE_DATA, the host should consume
-+ * the buffer in buffer_id and set the state to
-+ * SPA_STATUS_NEED_DATA when new data is requested.
-+ *
-+ * If status is SPA_STATUS_STOPPED, some error occurred on the
-+ * port.
-+ *
-+ * If status is SPA_STATUS_DRAINED, data from the io area was
-+ * used to drain.
-+ *
-+ * Status can also be a negative errno value to indicate errors.
-+ * such as:
-+ * -EINVAL: buffer_id is invalid
-+ * -EPIPE: no more buffers available
-+ */
-+struct spa_io_buffers {
-+#define SPA_STATUS_OK 0
-+#define SPA_STATUS_NEED_DATA (1<<0)
-+#define SPA_STATUS_HAVE_DATA (1<<1)
-+#define SPA_STATUS_STOPPED (1<<2)
-+#define SPA_STATUS_DRAINED (1<<3)
-+ int32_t status; /**< the status code */
-+ uint32_t buffer_id; /**< a buffer id */
-+};
-+
-+#define SPA_IO_BUFFERS_INIT (struct spa_io_buffers) { SPA_STATUS_OK, SPA_ID_INVALID, }
-+
-+/**
-+ * IO area to exchange a memory region
-+ */
-+struct spa_io_memory {
-+ int32_t status; /**< the status code */
-+ uint32_t size; /**< the size of \a data */
-+ void *data; /**< a memory pointer */
-+};
-+#define SPA_IO_MEMORY_INIT (struct spa_io_memory) { SPA_STATUS_OK, 0, NULL, }
-+
-+/** A range, suitable for input ports that can suggest a range to output ports */
-+struct spa_io_range {
-+ uint64_t offset; /**< offset in range */
-+ uint32_t min_size; /**< minimum size of data */
-+ uint32_t max_size; /**< maximum size of data */
-+};
-+
-+/**
-+ * Absolute time reporting.
-+ *
-+ * Nodes that can report clocking information will receive this io block.
-+ * The application sets the id. This is usually set as part of the
-+ * position information but can also be set separately.
-+ *
-+ * The clock counts the elapsed time according to the clock provider
-+ * since the provider was last started.
-+ */
-+struct spa_io_clock {
-+ uint32_t flags; /**< clock flags */
-+ uint32_t id; /**< unique clock id, set by application */
-+ char name[64]; /**< clock name prefixed with API, set by node. The clock name
-+ * is unique per clock and can be used to check if nodes
-+ * share the same clock. */
-+ uint64_t nsec; /**< time in nanoseconds against monotonic clock */
-+ struct spa_fraction rate; /**< rate for position/duration/delay */
-+ uint64_t position; /**< current position */
-+ uint64_t duration; /**< duration of current cycle */
-+ int64_t delay; /**< delay between position and hardware,
-+ * positive for capture, negative for playback */
-+ double rate_diff; /**< rate difference between clock and monotonic time */
-+ uint64_t next_nsec; /**< extimated next wakeup time in nanoseconds */
-+ uint32_t padding[8];
-+};
-+
-+/* the size of the video in this cycle */
-+struct spa_io_video_size {
-+#define SPA_IO_VIDEO_SIZE_VALID (1<<0)
-+ uint32_t flags; /**< optional flags */
-+ uint32_t stride; /**< video stride in bytes */
-+ struct spa_rectangle size; /**< the video size */
-+ struct spa_fraction framerate; /**< the minimum framerate, the cycle duration is
-+ * always smaller to ensure there is only one
-+ * video frame per cycle. */
-+ uint32_t padding[4];
-+};
-+
-+/** latency reporting */
-+struct spa_io_latency {
-+ struct spa_fraction rate; /**< rate for min/max */
-+ uint64_t min; /**< min latency */
-+ uint64_t max; /**< max latency */
-+};
-+
-+/** control stream, io area for SPA_IO_Control and SPA_IO_Notify */
-+struct spa_io_sequence {
-+ struct spa_pod_sequence sequence; /**< sequence of timed events */
-+};
-+
-+/** bar and beat segment */
-+struct spa_io_segment_bar {
-+#define SPA_IO_SEGMENT_BAR_FLAG_VALID (1<<0)
-+ uint32_t flags; /**< extra flags */
-+ uint32_t offset; /**< offset in segment of this beat */
-+ float signature_num; /**< time signature numerator */
-+ float signature_denom; /**< time signature denominator */
-+ double bpm; /**< beats per minute */
-+ double beat; /**< current beat in segment */
-+ uint32_t padding[8];
-+};
-+
-+/** video frame segment */
-+struct spa_io_segment_video {
-+#define SPA_IO_SEGMENT_VIDEO_FLAG_VALID (1<<0)
-+#define SPA_IO_SEGMENT_VIDEO_FLAG_DROP_FRAME (1<<1)
-+#define SPA_IO_SEGMENT_VIDEO_FLAG_PULL_DOWN (1<<2)
-+#define SPA_IO_SEGMENT_VIDEO_FLAG_INTERLACED (1<<3)
-+ uint32_t flags; /**< flags */
-+ uint32_t offset; /**< offset in segment */
-+ struct spa_fraction framerate;
-+ uint32_t hours;
-+ uint32_t minutes;
-+ uint32_t seconds;
-+ uint32_t frames;
-+ uint32_t field_count; /**< 0 for progressive, 1 and 2 for interlaced */
-+ uint32_t padding[11];
-+};
-+
-+/**
-+ * A segment converts a running time to a segment (stream) position.
-+ *
-+ * The segment position is valid when the current running time is between
-+ * start and start + duration. The position is then
-+ * calculated as:
-+ *
-+ * (running time - start) * rate + position;
-+ *
-+ * Support for looping is done by specifying the LOOPING flags with a
-+ * non-zero duration. When the running time reaches start + duration,
-+ * duration is added to start and the loop repeats.
-+ *
-+ * Care has to be taken when the running time + clock.duration extends
-+ * past the start + duration from the segment; the user should correctly
-+ * wrap around and partially repeat the loop in the current cycle.
-+ *
-+ * Extra information can be placed in the segment by setting the valid flags
-+ * and filling up the corresponding structures.
-+ */
-+struct spa_io_segment {
-+ uint32_t version;
-+#define SPA_IO_SEGMENT_FLAG_LOOPING (1<<0) /**< after the duration, the segment repeats */
-+#define SPA_IO_SEGMENT_FLAG_NO_POSITION (1<<1) /**< position is invalid. The position can be invalid
-+ * after a seek, for example, when the exact mapping
-+ * of the extra segment info (bar, video, ...) to
-+ * position has not been determined yet */
-+ uint32_t flags; /**< extra flags */
-+ uint64_t start; /**< value of running time when this
-+ * info is active. Can be in the future for
-+ * pending changes. It does not have to be in
-+ * exact multiples of the clock duration. */
-+ uint64_t duration; /**< duration when this info becomes invalid expressed
-+ * in running time. If the duration is 0, this
-+ * segment extends to the next segment. If the
-+ * segment becomes invalid and the looping flag is
-+ * set, the segment repeats. */
-+ double rate; /**< overal rate of the segment, can be negative for
-+ * backwards time reporting. */
-+ uint64_t position; /**< The position when the running time == start.
-+ * can be invalid when the owner of the extra segment
-+ * information has not yet made the mapping. */
-+
-+ struct spa_io_segment_bar bar;
-+ struct spa_io_segment_video video;
-+};
-+
-+enum spa_io_position_state {
-+ SPA_IO_POSITION_STATE_STOPPED,
-+ SPA_IO_POSITION_STATE_STARTING,
-+ SPA_IO_POSITION_STATE_RUNNING,
-+};
-+
-+/** the maximum number of segments visible in the future */
-+#define SPA_IO_POSITION_MAX_SEGMENTS 8
-+
-+/**
-+ * The position information adds extra meaning to the raw clock times.
-+ *
-+ * It is set on all nodes and the clock id will contain the clock of the
-+ * driving node in the graph.
-+ *
-+ * The position information contains 1 or more segments that convert the
-+ * raw clock times to a stream time. They are sorted based on their
-+ * start times, and thus the order in which they will activate in
-+ * the future. This makes it possible to look ahead in the scheduled
-+ * segments and anticipate the changes in the timeline.
-+ */
-+struct spa_io_position {
-+ struct spa_io_clock clock; /**< clock position of driver, always valid and
-+ * read only */
-+ struct spa_io_video_size video; /**< size of the video in the current cycle */
-+ int64_t offset; /**< an offset to subtract from the clock position
-+ * to get a running time. This is the time that
-+ * the state has been in the RUNNING state and the
-+ * time that should be used to compare the segment
-+ * start values against. */
-+ uint32_t state; /**< one of enum spa_io_position_state */
-+
-+ uint32_t n_segments; /**< number of segments */
-+ struct spa_io_segment segments[SPA_IO_POSITION_MAX_SEGMENTS]; /**< segments */
-+};
-+
-+/** rate matching */
-+struct spa_io_rate_match {
-+ uint32_t delay; /**< extra delay in samples for resampler */
-+ uint32_t size; /**< requested input size for resampler */
-+ double rate; /**< rate for resampler */
-+#define SPA_IO_RATE_MATCH_FLAG_ACTIVE (1 << 0)
-+ uint32_t flags; /**< extra flags */
-+ uint32_t padding[7];
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_IO_H */
-diff --git a/third_party/pipewire/spa/node/keys.h b/third_party/pipewire/spa/node/keys.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/keys.h
-@@ -0,0 +1,54 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_NODE_KEYS_H
-+#define SPA_NODE_KEYS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** node keys */
-+#define SPA_KEY_NODE_NAME "node.name" /**< a node name */
-+#define SPA_KEY_NODE_LATENCY "node.latency" /**< the requested node latency */
-+
-+#define SPA_KEY_NODE_DRIVER "node.driver" /**< the node can be a driver */
-+#define SPA_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< call the process function even if
-+ * not linked. */
-+#define SPA_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< if the node should be paused
-+ * immediately when idle. */
-+#define SPA_KEY_NODE_MONITOR "node.monitor" /**< the node has monitor ports */
-+
-+
-+/** port keys */
-+#define SPA_KEY_PORT_NAME "port.name" /**< a port name */
-+#define SPA_KEY_PORT_ALIAS "port.alias" /**< a port alias */
-+#define SPA_KEY_PORT_MONITOR "port.monitor" /**< this port is a monitor port */
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_NODE_KEYS_H */
-diff --git a/third_party/pipewire/spa/node/node.h b/third_party/pipewire/spa/node/node.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/node.h
-@@ -0,0 +1,662 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_NODE_H
-+#define SPA_NODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/type.h>
-+#include <spa/utils/hook.h>
-+#include <spa/buffer/buffer.h>
-+#include <spa/node/event.h>
-+#include <spa/node/command.h>
-+
-+
-+/**
-+ * A spa_node is a component that can consume and produce buffers.
-+ */
-+#define SPA_TYPE_INTERFACE_Node SPA_TYPE_INFO_INTERFACE_BASE "Node"
-+
-+#define SPA_VERSION_NODE 0
-+struct spa_node { struct spa_interface iface; };
-+
-+/**
-+ * Node information structure
-+ *
-+ * Contains the basic node information.
-+ */
-+struct spa_node_info {
-+ uint32_t max_input_ports;
-+ uint32_t max_output_ports;
-+#define SPA_NODE_CHANGE_MASK_FLAGS (1u<<0)
-+#define SPA_NODE_CHANGE_MASK_PROPS (1u<<1)
-+#define SPA_NODE_CHANGE_MASK_PARAMS (1u<<2)
-+ uint64_t change_mask;
-+
-+#define SPA_NODE_FLAG_RT (1u<<0) /**< node can do real-time processing */
-+#define SPA_NODE_FLAG_IN_DYNAMIC_PORTS (1u<<1) /**< input ports can be added/removed */
-+#define SPA_NODE_FLAG_OUT_DYNAMIC_PORTS (1u<<2) /**< output ports can be added/removed */
-+#define SPA_NODE_FLAG_IN_PORT_CONFIG (1u<<3) /**< input ports can be reconfigured with
-+ * PortConfig parameter */
-+#define SPA_NODE_FLAG_OUT_PORT_CONFIG (1u<<4) /**< output ports can be reconfigured with
-+ * PortConfig parameter */
-+#define SPA_NODE_FLAG_NEED_CONFIGURE (1u<<5) /**< node needs configuration before it can
-+ * be started. */
-+#define SPA_NODE_FLAG_ASYNC (1u<<6) /**< the process function might not
-+ * immediateley produce or consume data
-+ * but might offload the work to a worker
-+ * thread. */
-+ uint64_t flags;
-+ struct spa_dict *props; /**< extra node properties */
-+ struct spa_param_info *params; /**< parameter information */
-+ uint32_t n_params; /**< number of items in \a params */
-+};
-+
-+#define SPA_NODE_INFO_INIT() (struct spa_node_info) { 0, }
-+
-+/**
-+ * Port information structure
-+ *
-+ * Contains the basic port information.
-+ */
-+struct spa_port_info {
-+#define SPA_PORT_CHANGE_MASK_FLAGS (1u<<0)
-+#define SPA_PORT_CHANGE_MASK_RATE (1u<<1)
-+#define SPA_PORT_CHANGE_MASK_PROPS (1u<<2)
-+#define SPA_PORT_CHANGE_MASK_PARAMS (1u<<3)
-+ uint64_t change_mask;
-+
-+#define SPA_PORT_FLAG_REMOVABLE (1u<<0) /**< port can be removed */
-+#define SPA_PORT_FLAG_OPTIONAL (1u<<1) /**< processing on port is optional */
-+#define SPA_PORT_FLAG_CAN_ALLOC_BUFFERS (1u<<2) /**< the port can allocate buffer data */
-+#define SPA_PORT_FLAG_IN_PLACE (1u<<3) /**< the port can process data in-place and
-+ * will need a writable input buffer */
-+#define SPA_PORT_FLAG_NO_REF (1u<<4) /**< the port does not keep a ref on the buffer.
-+ * This means the node will always completely
-+ * consume the input buffer and it will be
-+ * recycled after process. */
-+#define SPA_PORT_FLAG_LIVE (1u<<5) /**< output buffers from this port are
-+ * timestamped against a live clock. */
-+#define SPA_PORT_FLAG_PHYSICAL (1u<<6) /**< connects to some device */
-+#define SPA_PORT_FLAG_TERMINAL (1u<<7) /**< data was not created from this port
-+ * or will not be made available on another
-+ * port */
-+#define SPA_PORT_FLAG_DYNAMIC_DATA (1u<<8) /**< data pointer on buffers can be changed.
-+ * Only the buffer data marked as DYNAMIC
-+ * can be changed. */
-+ uint64_t flags; /**< port flags */
-+ struct spa_fraction rate; /**< rate of sequence numbers on port */
-+ const struct spa_dict *props; /**< extra port properties */
-+ struct spa_param_info *params; /**< parameter information */
-+ uint32_t n_params; /**< number of items in \a params */
-+};
-+
-+#define SPA_PORT_INFO_INIT() (struct spa_port_info) { 0, }
-+
-+#define SPA_RESULT_TYPE_NODE_ERROR 1
-+#define SPA_RESULT_TYPE_NODE_PARAMS 2
-+
-+/** an error result */
-+struct spa_result_node_error {
-+ const char *message;
-+};
-+
-+/** the result of enum_params or port_enum_params. */
-+struct spa_result_node_params {
-+ uint32_t id; /**< id of parameter */
-+ uint32_t index; /**< index of parameter */
-+ uint32_t next; /**< next index of iteration */
-+ struct spa_pod *param; /**< the result param */
-+};
-+
-+#define SPA_NODE_EVENT_INFO 0
-+#define SPA_NODE_EVENT_PORT_INFO 1
-+#define SPA_NODE_EVENT_RESULT 2
-+#define SPA_NODE_EVENT_EVENT 3
-+#define SPA_NODE_EVENT_NUM 4
-+
-+/** events from the spa_node.
-+ *
-+ * All event are called from the main thread and multiple
-+ * listeners can be registered for the events with
-+ * spa_node_add_listener().
-+ */
-+struct spa_node_events {
-+#define SPA_VERSION_NODE_EVENTS 0
-+ uint32_t version; /**< version of this structure */
-+
-+ /** Emitted when info changes */
-+ void (*info) (void *data, const struct spa_node_info *info);
-+
-+ /** Emitted when port info changes, NULL when port is removed */
-+ void (*port_info) (void *data,
-+ enum spa_direction direction, uint32_t port,
-+ const struct spa_port_info *info);
-+
-+ /** notify a result.
-+ *
-+ * Some methods will trigger a result event with an optional
-+ * result of the given type. Look at the documentation of the
-+ * method to know when to expect a result event.
-+ *
-+ * The result event can be called synchronously, as an event
-+ * called from inside the method itself, in which case the seq
-+ * number passed to the method will be passed unchanged.
-+ *
-+ * The result event will be called asynchronously when the
-+ * method returned an async return value. In this case, the seq
-+ * number in the result will match the async return value of
-+ * the method call. Users should match the seq number from
-+ * request to the reply.
-+ */
-+ void (*result) (void *data, int seq, int res,
-+ uint32_t type, const void *result);
-+
-+ /**
-+ * \param node a spa_node
-+ * \param event the event that was emitted
-+ *
-+ * This will be called when an out-of-bound event is notified
-+ * on \a node.
-+ */
-+ void (*event) (void *data, const struct spa_event *event);
-+};
-+
-+#define SPA_NODE_CALLBACK_READY 0
-+#define SPA_NODE_CALLBACK_REUSE_BUFFER 1
-+#define SPA_NODE_CALLBACK_XRUN 2
-+#define SPA_NODE_CALLBACK_NUM 3
-+
-+/** Node callbacks
-+ *
-+ * Callbacks are called from the real-time data thread. Only
-+ * one callback structure can be set on an spa_node.
-+ */
-+struct spa_node_callbacks {
-+#define SPA_VERSION_NODE_CALLBACKS 0
-+ uint32_t version;
-+ /**
-+ * \param node a spa_node
-+ *
-+ * The node is ready for processing.
-+ *
-+ * When this function is NULL, synchronous operation is requested
-+ * on the ports.
-+ */
-+ int (*ready) (void *data, int state);
-+
-+ /**
-+ * \param node a spa_node
-+ * \param port_id an input port_id
-+ * \param buffer_id the buffer id to be reused
-+ *
-+ * The node has a buffer that can be reused.
-+ *
-+ * When this function is NULL, the buffers to reuse will be set in
-+ * the io area of the input ports.
-+ */
-+ int (*reuse_buffer) (void *data,
-+ uint32_t port_id,
-+ uint32_t buffer_id);
-+
-+ /**
-+ * \param data user data
-+ * \param trigger the timestamp in microseconds when the xrun happened
-+ * \param delay the amount of microseconds of xrun.
-+ * \param info an object with extra info (NULL for now)
-+ *
-+ * The node has encountered an over or underrun
-+ *
-+ * The info contains an object with more information
-+ */
-+ int (*xrun) (void *data, uint64_t trigger, uint64_t delay,
-+ struct spa_pod *info);
-+};
-+
-+
-+/** flags that can be passed to set_param and port_set_param functions */
-+#define SPA_NODE_PARAM_FLAG_TEST_ONLY (1 << 0) /**< Just check if the param is accepted */
-+#define SPA_NODE_PARAM_FLAG_FIXATE (1 << 1) /**< Fixate the non-optional unset fields */
-+#define SPA_NODE_PARAM_FLAG_NEAREST (1 << 2) /**< Allow set fields to be rounded to the
-+ * nearest allowed field value. */
-+
-+/** flags to pass to the use_buffers functions */
-+#define SPA_NODE_BUFFERS_FLAG_ALLOC (1 << 0) /**< Allocate memory for the buffers. This flag
-+ * is ignored when the port does not have the
-+ * SPA_PORT_FLAG_CAN_ALLOC_BUFFERS set. */
-+
-+
-+#define SPA_NODE_METHOD_ADD_LISTENER 0
-+#define SPA_NODE_METHOD_SET_CALLBACKS 1
-+#define SPA_NODE_METHOD_SYNC 2
-+#define SPA_NODE_METHOD_ENUM_PARAMS 3
-+#define SPA_NODE_METHOD_SET_PARAM 4
-+#define SPA_NODE_METHOD_SET_IO 5
-+#define SPA_NODE_METHOD_SEND_COMMAND 6
-+#define SPA_NODE_METHOD_ADD_PORT 7
-+#define SPA_NODE_METHOD_REMOVE_PORT 8
-+#define SPA_NODE_METHOD_PORT_ENUM_PARAMS 9
-+#define SPA_NODE_METHOD_PORT_SET_PARAM 10
-+#define SPA_NODE_METHOD_PORT_USE_BUFFERS 11
-+#define SPA_NODE_METHOD_PORT_SET_IO 12
-+#define SPA_NODE_METHOD_PORT_REUSE_BUFFER 13
-+#define SPA_NODE_METHOD_PROCESS 14
-+#define SPA_NODE_METHOD_NUM 15
-+
-+/**
-+ * Node methods
-+ */
-+struct spa_node_methods {
-+ /* the version of the node methods. This can be used to expand this
-+ * structure in the future */
-+#define SPA_VERSION_NODE_METHODS 0
-+ uint32_t version;
-+
-+ /**
-+ * Adds an event listener on \a node.
-+ *
-+ * Setting the events will trigger the info event and a
-+ * port_info event for each managed port on the new
-+ * listener.
-+ *
-+ * \param node a #spa_node
-+ * \param listener a listener
-+ * \param events a #struct spa_node_events
-+ * \param data data passed as first argument in functions of \a events
-+ * \return 0 on success
-+ * < 0 errno on error
-+ */
-+ int (*add_listener) (void *object,
-+ struct spa_hook *listener,
-+ const struct spa_node_events *events,
-+ void *data);
-+ /**
-+ * Set callbacks to on \a node.
-+ * if \a callbacks is NULL, the current callbacks are removed.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * All callbacks are called from the data thread.
-+ *
-+ * \param node a spa_node
-+ * \param callbacks callbacks to set
-+ * \return 0 on success
-+ * -EINVAL when node is NULL
-+ */
-+ int (*set_callbacks) (void *object,
-+ const struct spa_node_callbacks *callbacks,
-+ void *data);
-+ /**
-+ * Perform a sync operation.
-+ *
-+ * This method will emit the result event with the given sequence
-+ * number synchronously or with the returned async return value
-+ * asynchronously.
-+ *
-+ * Because all methods are serialized in the node, this can be used
-+ * to wait for completion of all previous method calls.
-+ *
-+ * \param seq a sequence number
-+ * \return 0 on success
-+ * -EINVAL when node is NULL
-+ * an async result
-+ */
-+ int (*sync) (void *object, int seq);
-+
-+ /**
-+ * Enumerate the parameters of a node.
-+ *
-+ * Parameters are identified with an \a id. Some parameters can have
-+ * multiple values, see the documentation of the parameter id.
-+ *
-+ * Parameters can be filtered by passing a non-NULL \a filter.
-+ *
-+ * The function will emit the result event up to \a max times with
-+ * the result value. The seq in the result will either be the \a seq
-+ * number when executed synchronously or the async return value of
-+ * this function when executed asynchronously.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param node a \ref spa_node
-+ * \param seq a sequence number to pass to the result event when
-+ * this method is executed synchronously.
-+ * \param id the param id to enumerate
-+ * \param start the index of enumeration, pass 0 for the first item
-+ * \param max the maximum number of parameters to enumerate
-+ * \param filter and optional filter to use
-+ *
-+ * \return 0 when no more items can be iterated.
-+ * -EINVAL when invalid arguments are given
-+ * -ENOENT the parameter \a id is unknown
-+ * -ENOTSUP when there are no parameters
-+ * implemented on \a node
-+ * an async return value when the result event will be
-+ * emitted later.
-+ */
-+ int (*enum_params) (void *object, int seq,
-+ uint32_t id, uint32_t start, uint32_t max,
-+ const struct spa_pod *filter);
-+
-+ /**
-+ * Set the configurable parameter in \a node.
-+ *
-+ * Usually, \a param will be obtained from enum_params and then
-+ * modified but it is also possible to set another spa_pod
-+ * as long as its keys and types match a supported object.
-+ *
-+ * Objects with property keys that are not known are ignored.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param node a \ref spa_node
-+ * \param id the parameter id to configure
-+ * \param flags additional flags
-+ * \param param the parameter to configure
-+ *
-+ * \return 0 on success
-+ * -EINVAL when node is NULL
-+ * -ENOTSUP when there are no parameters implemented on \a node
-+ * -ENOENT the parameter is unknown
-+ */
-+ int (*set_param) (void *object,
-+ uint32_t id, uint32_t flags,
-+ const struct spa_pod *param);
-+
-+ /**
-+ * Configure the given memory area with \a id on \a node. This
-+ * structure is allocated by the host and is used to exchange
-+ * data and parameters with the node.
-+ *
-+ * Setting an \a io of NULL will disable the node io.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param id the id of the io area, the available ids can be
-+ * enumerated with the node parameters.
-+ * \param data a io area memory
-+ * \param size the size of \a data
-+ * \return 0 on success
-+ * -EINVAL when invalid input is given
-+ * -ENOENT when \a id is unknown
-+ * -ENOSPC when \a size is too small
-+ */
-+ int (*set_io) (void *object,
-+ uint32_t id, void *data, size_t size);
-+
-+ /**
-+ * Send a command to a node.
-+ *
-+ * Upon completion, a command might change the state of a node.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param node a spa_node
-+ * \param command a spa_command
-+ * \return 0 on success
-+ * -EINVAL when node or command is NULL
-+ * -ENOTSUP when this node can't process commands
-+ * -EINVAL \a command is an invalid command
-+ */
-+ int (*send_command) (void *object, const struct spa_command *command);
-+
-+ /**
-+ * Make a new port with \a port_id. The caller should use the lowest unused
-+ * port id for the given \a direction.
-+ *
-+ * Port ids should be between 0 and max_ports as obtained from the info
-+ * event.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param node a spa_node
-+ * \param direction a #enum spa_direction
-+ * \param port_id an unused port id
-+ * \param props extra properties
-+ * \return 0 on success
-+ * -EINVAL when node is NULL
-+ */
-+ int (*add_port) (void *object,
-+ enum spa_direction direction, uint32_t port_id,
-+ const struct spa_dict *props);
-+
-+ /**
-+ * Remove a port with \a port_id.
-+ *
-+ * \param node a spa_node
-+ * \param direction a #enum spa_direction
-+ * \param port_id a port id
-+ * \return 0 on success
-+ * -EINVAL when node is NULL or when port_id is unknown or
-+ * when the port can't be removed.
-+ */
-+ int (*remove_port) (void *object,
-+ enum spa_direction direction, uint32_t port_id);
-+
-+ /**
-+ * Enumerate all possible parameters of \a id on \a port_id of \a node
-+ * that are compatible with \a filter.
-+ *
-+ * The result parameters can be queried and modified and ultimately be used
-+ * to call port_set_param.
-+ *
-+ * The function will emit the result event up to \a max times with
-+ * the result value. The seq in the result event will either be the
-+ * \a seq number when executed synchronously or the async return
-+ * value of this function when executed asynchronously.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param node a spa_node
-+ * \param seq a sequence number to pass to the result event when
-+ * this method is executed synchronously.
-+ * \param direction an spa_direction
-+ * \param port_id the port to query
-+ * \param id the parameter id to query
-+ * \param start the first index to query, 0 to get the first item
-+ * \param max the maximum number of params to query
-+ * \param filter a parameter filter or NULL for no filter
-+ *
-+ * \return 0 when no more items can be iterated.
-+ * -EINVAL when invalid parameters are given
-+ * -ENOENT when \a id is unknown
-+ * an async return value when the result event will be
-+ * emitted later.
-+ */
-+ int (*port_enum_params) (void *object, int seq,
-+ enum spa_direction direction, uint32_t port_id,
-+ uint32_t id, uint32_t start, uint32_t max,
-+ const struct spa_pod *filter);
-+ /**
-+ * Set a parameter on \a port_id of \a node.
-+ *
-+ * When \a param is NULL, the parameter will be unset.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param node a #struct spa_node
-+ * \param direction a #enum spa_direction
-+ * \param port_id the port to configure
-+ * \param id the parameter id to set
-+ * \param flags optional flags
-+ * \param param a #struct spa_pod with the parameter to set
-+ * \return 0 on success
-+ * 1 on success, the value of \a param might have been
-+ * changed depending on \a flags and the final value can be found by
-+ * doing port_enum_params.
-+ * -EINVAL when node is NULL or invalid arguments are given
-+ * -ESRCH when one of the mandatory param
-+ * properties is not specified and SPA_NODE_PARAM_FLAG_FIXATE was
-+ * not set in \a flags.
-+ * -ESRCH when the type or size of a property is not correct.
-+ * -ENOENT when the param id is not found
-+ */
-+ int (*port_set_param) (void *object,
-+ enum spa_direction direction,
-+ uint32_t port_id,
-+ uint32_t id, uint32_t flags,
-+ const struct spa_pod *param);
-+
-+ /**
-+ * Tell the port to use the given buffers
-+ *
-+ * When \a flags contains SPA_NODE_BUFFERS_FLAG_ALLOC, the data
-+ * in the buffers should point to an array of at least 1 data entry
-+ * with the desired supported type that will be filled by this function.
-+ *
-+ * The port should also have a spa_io_buffers io area configured to exchange
-+ * the buffers with the port.
-+ *
-+ * For an input port, all the buffers will remain dequeued.
-+ * Once a buffer has been queued on a port in the spa_io_buffers,
-+ * it should not be reused until the reuse_buffer callback is notified
-+ * or when the buffer has been returned in the spa_io_buffers of
-+ * the port.
-+ *
-+ * For output ports, all buffers will be queued in the port. When process
-+ * returns SPA_STATUS_HAVE_DATA, buffers are available in one or more
-+ * of the spa_io_buffers areas.
-+ *
-+ * When a buffer can be reused, port_reuse_buffer() should be called or the
-+ * buffer_id should be placed in the spa_io_buffers area before calling
-+ * process.
-+ *
-+ * Passing NULL as \a buffers will remove the reference that the port has
-+ * on the buffers.
-+ *
-+ * When this function returns async, use the spa_node_sync operation to
-+ * wait for completion.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param object an object implementing the interface
-+ * \param direction a port direction
-+ * \param port_id a port id
-+ * \param flags extra flags
-+ * \param buffers an array of buffer pointers
-+ * \param n_buffers number of elements in \a buffers
-+ * \return 0 on success
-+ */
-+ int (*port_use_buffers) (void *object,
-+ enum spa_direction direction,
-+ uint32_t port_id,
-+ uint32_t flags,
-+ struct spa_buffer **buffers,
-+ uint32_t n_buffers);
-+
-+ /**
-+ * Configure the given memory area with \a id on \a port_id. This
-+ * structure is allocated by the host and is used to exchange
-+ * data and parameters with the port.
-+ *
-+ * Setting an \a io of NULL will disable the port io.
-+ *
-+ * This function must be called from the main thread.
-+ *
-+ * \param direction a spa_direction
-+ * \param port_id a port id
-+ * \param id the id of the io area, the available ids can be
-+ * enumerated with the port parameters.
-+ * \param data a io area memory
-+ * \param size the size of \a data
-+ * \return 0 on success
-+ * -EINVAL when invalid input is given
-+ * -ENOENT when \a id is unknown
-+ * -ENOSPC when \a size is too small
-+ */
-+ int (*port_set_io) (void *object,
-+ enum spa_direction direction,
-+ uint32_t port_id,
-+ uint32_t id,
-+ void *data, size_t size);
-+
-+ /**
-+ * Tell an output port to reuse a buffer.
-+ *
-+ * This function must be called from the data thread.
-+ *
-+ * \param node a spa_node
-+ * \param port_id a port id
-+ * \param buffer_id a buffer id to reuse
-+ * \return 0 on success
-+ * -EINVAL when node is NULL
-+ */
-+ int (*port_reuse_buffer) (void *object, uint32_t port_id, uint32_t buffer_id);
-+
-+ /**
-+ * Process the node
-+ *
-+ * This function must be called from the data thread.
-+ *
-+ * Output io areas with SPA_STATUS_NEED_DATA will recycle the
-+ * buffers if any.
-+ *
-+ * Input areas with SPA_STATUS_HAVE_DATA are consumed if possible
-+ * and the status is set to SPA_STATUS_NEED_DATA or SPA_STATUS_OK.
-+ *
-+ * When the node has new output buffers, the SPA_STATUS_HAVE_DATA
-+ * bit will be set.
-+ *
-+ * When the node can accept new input in the next cycle, the
-+ * SPA_STATUS_NEED_DATA bit will be set.
-+ */
-+ int (*process) (void *object);
-+};
-+
-+#define spa_node_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_node *_n = o; \
-+ spa_interface_call_res(&_n->iface, \
-+ struct spa_node_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define spa_node_add_listener(n,...) spa_node_method(n, add_listener, 0, __VA_ARGS__)
-+#define spa_node_set_callbacks(n,...) spa_node_method(n, set_callbacks, 0, __VA_ARGS__)
-+#define spa_node_sync(n,...) spa_node_method(n, sync, 0, __VA_ARGS__)
-+#define spa_node_enum_params(n,...) spa_node_method(n, enum_params, 0, __VA_ARGS__)
-+#define spa_node_set_param(n,...) spa_node_method(n, set_param, 0, __VA_ARGS__)
-+#define spa_node_set_io(n,...) spa_node_method(n, set_io, 0, __VA_ARGS__)
-+#define spa_node_send_command(n,...) spa_node_method(n, send_command, 0, __VA_ARGS__)
-+#define spa_node_add_port(n,...) spa_node_method(n, add_port, 0, __VA_ARGS__)
-+#define spa_node_remove_port(n,...) spa_node_method(n, remove_port, 0, __VA_ARGS__)
-+#define spa_node_port_enum_params(n,...) spa_node_method(n, port_enum_params, 0, __VA_ARGS__)
-+#define spa_node_port_set_param(n,...) spa_node_method(n, port_set_param, 0, __VA_ARGS__)
-+#define spa_node_port_use_buffers(n,...) spa_node_method(n, port_use_buffers, 0, __VA_ARGS__)
-+#define spa_node_port_set_io(n,...) spa_node_method(n, port_set_io, 0, __VA_ARGS__)
-+
-+#define spa_node_port_reuse_buffer(n,...) spa_node_method(n, port_reuse_buffer, 0, __VA_ARGS__)
-+#define spa_node_process(n) spa_node_method(n, process, 0)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_NODE_H */
-diff --git a/third_party/pipewire/spa/node/type-info.h b/third_party/pipewire/spa/node/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/type-info.h
-@@ -0,0 +1,94 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_NODE_TYPES_H
-+#define SPA_NODE_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/type-info.h>
-+
-+#include <spa/node/command.h>
-+#include <spa/node/event.h>
-+#include <spa/node/io.h>
-+
-+#define SPA_TYPE_INFO_IO SPA_TYPE_INFO_ENUM_BASE "IO"
-+#define SPA_TYPE_INFO_IO_BASE SPA_TYPE_INFO_IO ":"
-+
-+static const struct spa_type_info spa_type_io[] = {
-+ { SPA_IO_Invalid, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Invalid", NULL },
-+ { SPA_IO_Buffers, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Buffers", NULL },
-+ { SPA_IO_Range, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Range", NULL },
-+ { SPA_IO_Clock, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Clock", NULL },
-+ { SPA_IO_Latency, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Latency", NULL },
-+ { SPA_IO_Control, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Control", NULL },
-+ { SPA_IO_Notify, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Notify", NULL },
-+ { SPA_IO_Position, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Position", NULL },
-+ { SPA_IO_RateMatch, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "RateMatch", NULL },
-+ { SPA_IO_Memory, SPA_TYPE_Int, SPA_TYPE_INFO_IO_BASE "Memory", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_NodeEvent SPA_TYPE_INFO_EVENT_BASE "Node"
-+#define SPA_TYPE_INFO_NODE_EVENT_BASE SPA_TYPE_INFO_NodeEvent ":"
-+
-+static const struct spa_type_info spa_type_node_event_id[] = {
-+ { SPA_NODE_EVENT_Error, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "Error", NULL },
-+ { SPA_NODE_EVENT_Buffering, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "Buffering", NULL },
-+ { SPA_NODE_EVENT_RequestRefresh, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestRefresh", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+static const struct spa_type_info spa_type_node_event[] = {
-+ { 0, SPA_TYPE_Id, SPA_TYPE_INFO_NODE_EVENT_BASE, spa_type_node_event_id },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_NodeCommand SPA_TYPE_INFO_COMMAND_BASE "Node"
-+#define SPA_TYPE_INFO_NODE_COMMAND_BASE SPA_TYPE_INFO_NodeCommand ":"
-+
-+static const struct spa_type_info spa_type_node_command_id[] = {
-+ { SPA_NODE_COMMAND_Suspend, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Suspend", NULL },
-+ { SPA_NODE_COMMAND_Pause, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Pause", NULL },
-+ { SPA_NODE_COMMAND_Start, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Start", NULL },
-+ { SPA_NODE_COMMAND_Enable, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Enable", NULL },
-+ { SPA_NODE_COMMAND_Disable, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Disable", NULL },
-+ { SPA_NODE_COMMAND_Flush, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Flush", NULL },
-+ { SPA_NODE_COMMAND_Drain, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Drain", NULL },
-+ { SPA_NODE_COMMAND_Marker, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Marker", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+static const struct spa_type_info spa_type_node_command[] = {
-+ { 0, SPA_TYPE_Id, SPA_TYPE_INFO_NODE_COMMAND_BASE, spa_type_node_command_id },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_NODE_TYPES_H */
-diff --git a/third_party/pipewire/spa/node/utils.h b/third_party/pipewire/spa/node/utils.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/node/utils.h
-@@ -0,0 +1,144 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_NODE_UTILS_H
-+#define SPA_NODE_UTILS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/builder.h>
-+
-+#include <spa/node/node.h>
-+
-+struct spa_result_node_params_data {
-+ struct spa_pod_builder *builder;
-+ struct spa_result_node_params data;
-+};
-+
-+static inline void spa_result_func_node_params(void *data,
-+ int seq, int res, uint32_t type, const void *result)
-+{
-+ struct spa_result_node_params_data *d =
-+ (struct spa_result_node_params_data *) data;
-+ const struct spa_result_node_params *r =
-+ (const struct spa_result_node_params *) result;
-+ uint32_t offset = d->builder->state.offset;
-+ spa_pod_builder_raw_padded(d->builder, r->param, SPA_POD_SIZE(r->param));
-+ d->data.next = r->next;
-+ d->data.param = SPA_MEMBER(d->builder->data, offset, struct spa_pod);
-+}
-+
-+static inline int spa_node_enum_params_sync(struct spa_node *node,
-+ uint32_t id, uint32_t *index,
-+ const struct spa_pod *filter,
-+ struct spa_pod **param,
-+ struct spa_pod_builder *builder)
-+{
-+ struct spa_result_node_params_data data = { builder, };
-+ struct spa_hook listener = { 0 };
-+ static const struct spa_node_events node_events = {
-+ SPA_VERSION_NODE_EVENTS,
-+ .result = spa_result_func_node_params,
-+ };
-+ int res;
-+
-+ res = spa_node_add_listener(node, &listener, &node_events, &data);
-+ if (res >= 0) {
-+ res = spa_node_enum_params(node, 0, id, *index, 1, filter);
-+ spa_hook_remove(&listener);
-+ }
-+
-+ if (data.data.param == NULL) {
-+ if (res > 0)
-+ res = 0;
-+ } else {
-+ *index = data.data.next;
-+ *param = data.data.param;
-+ res = 1;
-+ }
-+ return res;
-+}
-+
-+static inline int spa_node_port_enum_params_sync(struct spa_node *node,
-+ enum spa_direction direction, uint32_t port_id,
-+ uint32_t id, uint32_t *index,
-+ const struct spa_pod *filter,
-+ struct spa_pod **param,
-+ struct spa_pod_builder *builder)
-+{
-+ struct spa_result_node_params_data data = { builder, };
-+ struct spa_hook listener = { 0 };
-+ static const struct spa_node_events node_events = {
-+ SPA_VERSION_NODE_EVENTS,
-+ .result = spa_result_func_node_params,
-+ };
-+ int res;
-+
-+ res = spa_node_add_listener(node, &listener, &node_events, &data);
-+ if (res >= 0) {
-+ res = spa_node_port_enum_params(node, 0, direction, port_id,
-+ id, *index, 1, filter);
-+ spa_hook_remove(&listener);
-+ }
-+
-+ if (data.data.param == NULL) {
-+ if (res > 0)
-+ res = 0;
-+ } else {
-+ *index = data.data.next;
-+ *param = data.data.param;
-+ res = 1;
-+ }
-+ return res;
-+}
-+
-+#define spa_node_emit(hooks,method,version,...) \
-+ spa_hook_list_call_simple(hooks, struct spa_node_events, \
-+ method, version, ##__VA_ARGS__)
-+
-+#define spa_node_emit_info(hooks,...) spa_node_emit(hooks,info, 0, __VA_ARGS__)
-+#define spa_node_emit_port_info(hooks,...) spa_node_emit(hooks,port_info, 0, __VA_ARGS__)
-+#define spa_node_emit_result(hooks,...) spa_node_emit(hooks,result, 0, __VA_ARGS__)
-+#define spa_node_emit_event(hooks,...) spa_node_emit(hooks,event, 0, __VA_ARGS__)
-+
-+
-+#define spa_node_call(callbacks,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ spa_callbacks_call_res(callbacks, struct spa_node_callbacks, \
-+ _res, method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define spa_node_call_ready(hook,...) spa_node_call(hook, ready, 0, __VA_ARGS__)
-+#define spa_node_call_reuse_buffer(hook,...) spa_node_call(hook, reuse_buffer, 0, __VA_ARGS__)
-+#define spa_node_call_xrun(hook,...) spa_node_call(hook, xrun, 0, __VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_NODE_UTILS_H */
-diff --git a/third_party/pipewire/spa/param/audio/format-utils.h b/third_party/pipewire/spa/param/audio/format-utils.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/audio/format-utils.h
-@@ -0,0 +1,105 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_AUDIO_FORMAT_UTILS_H
-+#define SPA_PARAM_AUDIO_FORMAT_UTILS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+
-+#include <spa/pod/parser.h>
-+#include <spa/pod/builder.h>
-+#include <spa/param/audio/format.h>
-+#include <spa/param/format-utils.h>
-+
-+static inline int
-+spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info)
-+{
-+ struct spa_pod *position = NULL;
-+ int res;
-+ info->flags = 0;
-+ res = spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(&info->format),
-+ SPA_FORMAT_AUDIO_rate, SPA_POD_Int(&info->rate),
-+ SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&info->channels),
-+ SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
-+ if (position == NULL ||
-+ !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
-+ SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
-+
-+ return res;
-+}
-+
-+static inline int
-+spa_format_audio_dsp_parse(const struct spa_pod *format, struct spa_audio_info_dsp *info)
-+{
-+ int res;
-+ res = spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(&info->format));
-+ return res;
-+}
-+
-+static inline struct spa_pod *
-+spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_raw *info)
-+{
-+ struct spa_pod_frame f;
-+ spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
-+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
-+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format),
-+ SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info->rate),
-+ SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels),
-+ 0);
-+
-+ if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) {
-+ spa_pod_builder_prop(builder, SPA_FORMAT_AUDIO_position, 0);
-+ spa_pod_builder_array(builder, sizeof(uint32_t), SPA_TYPE_Id,
-+ info->channels, info->position);
-+ }
-+ return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
-+}
-+
-+static inline struct spa_pod *
-+spa_format_audio_dsp_build(struct spa_pod_builder *builder, uint32_t id, struct spa_audio_info_dsp *info)
-+{
-+ struct spa_pod_frame f;
-+ spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
-+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp),
-+ SPA_FORMAT_AUDIO_format, SPA_POD_Id(info->format),
-+ 0);
-+ return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_AUDIO_FORMAT_UTILS_H */
-diff --git a/third_party/pipewire/spa/param/audio/format.h b/third_party/pipewire/spa/param/audio/format.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/audio/format.h
-@@ -0,0 +1,48 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_AUDIO_FORMAT_H
-+#define SPA_PARAM_AUDIO_FORMAT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/format.h>
-+#include <spa/param/audio/raw.h>
-+
-+struct spa_audio_info {
-+ uint32_t media_type;
-+ uint32_t media_subtype;
-+ union {
-+ struct spa_audio_info_raw raw;
-+ struct spa_audio_info_dsp dsp;
-+ } info;
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_AUDIO_FORMAT_H */
-diff --git a/third_party/pipewire/spa/param/audio/layout.h b/third_party/pipewire/spa/param/audio/layout.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/audio/layout.h
-@@ -0,0 +1,184 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_AUDIO_LAYOUT_H
-+#define SPA_AUDIO_LAYOUT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifndef __FreeBSD__
-+#include <endian.h>
-+#endif
-+
-+#include <spa/param/audio/raw.h>
-+
-+struct spa_audio_layout_info {
-+ uint32_t n_channels;
-+ uint32_t position[SPA_AUDIO_MAX_CHANNELS];
-+};
-+
-+#define SPA_AUDIO_LAYOUT_Mono 1, { SPA_AUDIO_CHANNEL_MONO, }
-+#define SPA_AUDIO_LAYOUT_Stereo 2, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, }
-+#define SPA_AUDIO_LAYOUT_Quad 4, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, }
-+#define SPA_AUDIO_LAYOUT_Pentagonal 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_FC, }
-+#define SPA_AUDIO_LAYOUT_Hexagonal 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_Octagonal 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RC, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_Cube 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR }, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_TFL, SPA_AUDIO_CHANNEL_TFR, \
-+ SPA_AUDIO_CHANNEL_TRL, SPA_AUDIO_CHANNEL_TRR, }
-+
-+
-+#define SPA_AUDIO_LAYOUT_MPEG_1_0 SPA_AUDIO_LAYOUT_MONO
-+#define SPA_AUDIO_LAYOUT_MPEG_2_0 SPA_AUDIO_LAYOUT_STEREO
-+#define SPA_AUDIO_LAYOUT_MPEG_3_0A 3, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, }
-+#define SPA_AUDIO_LAYOUT_MPEG_3_0B 3, { SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_FL, \
-+ SPA_AUDIO_CHANNEL_FR, }
-+#define SPA_AUDIO_LAYOUT_MPEG_4_0A 4, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_MPEG_4_0B 4, { SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_FL, \
-+ SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_0A 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_0B 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, \
-+ SPA_AUDIO_CHANNEL_FC, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_0C 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FC, \
-+ SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_0D 5, { SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_FL, \
-+ SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_1A 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_1B 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_1C 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FC, \
-+ SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, SPA_AUDIO_CHANNEL_LFE, }
-+#define SPA_AUDIO_LAYOUT_MPEG_5_1D 6, { SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_FL, \
-+ SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, SPA_AUDIO_CHANNEL_LFE, }
-+#define SPA_AUDIO_LAYOUT_MPEG_6_1A 7, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, \
-+ SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_MPEG_7_1A 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_MPEG_7_1B 8, { SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, SPA_AUDIO_CHANNEL_FL, \
-+ SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_RL, \
-+ SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_LFE, }
-+#define SPA_AUDIO_LAYOUT_MPEG_7_1C 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, }
-+
-+
-+#define SPA_AUDIO_LAYOUT_2_1 3, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_LFE, }
-+
-+#define SPA_AUDIO_LAYOUT_2RC 3, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_2FC 3, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, }
-+
-+#define SPA_AUDIO_LAYOUT_3_1 4, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, }
-+#define SPA_AUDIO_LAYOUT_4_0 4, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_2_2 4, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+
-+#define SPA_AUDIO_LAYOUT_4_1 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_5_0 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_5_0R 5, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RL, \
-+ SPA_AUDIO_CHANNEL_RR, }
-+#define SPA_AUDIO_LAYOUT_5_1 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_5_1R 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, }
-+#define SPA_AUDIO_LAYOUT_6_0 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RC, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_6_0F 6, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FLC, SPA_AUDIO_CHANNEL_FRC, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_6_1 7, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RC, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_6_1F 7, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_RC, }
-+#define SPA_AUDIO_LAYOUT_7_0 7, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RL, \
-+ SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_7_0F 7, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_FLC, \
-+ SPA_AUDIO_CHANNEL_FRC, SPA_AUDIO_CHANNEL_SL, \
-+ SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_7_1 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_7_1W 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_FLC, SPA_AUDIO_CHANNEL_FRC, \
-+ SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR, }
-+#define SPA_AUDIO_LAYOUT_7_1WR 8, { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, \
-+ SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, \
-+ SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, \
-+ SPA_AUDIO_CHANNEL_FLC, SPA_AUDIO_CHANNEL_FRC, }
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_AUDIO_LAYOUT_H */
-diff --git a/third_party/pipewire/spa/param/audio/raw.h b/third_party/pipewire/spa/param/audio/raw.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/audio/raw.h
-@@ -0,0 +1,237 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_AUDIO_RAW_H
-+#define SPA_AUDIO_RAW_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdint.h>
-+
-+#ifndef __FreeBSD__
-+#include <endian.h>
-+#endif
-+
-+#define SPA_AUDIO_MAX_CHANNELS 64u
-+
-+enum spa_audio_format {
-+ SPA_AUDIO_FORMAT_UNKNOWN,
-+ SPA_AUDIO_FORMAT_ENCODED,
-+
-+ /* interleaved formats */
-+ SPA_AUDIO_FORMAT_START_Interleaved = 0x100,
-+ SPA_AUDIO_FORMAT_S8,
-+ SPA_AUDIO_FORMAT_U8,
-+ SPA_AUDIO_FORMAT_S16_LE,
-+ SPA_AUDIO_FORMAT_S16_BE,
-+ SPA_AUDIO_FORMAT_U16_LE,
-+ SPA_AUDIO_FORMAT_U16_BE,
-+ SPA_AUDIO_FORMAT_S24_32_LE,
-+ SPA_AUDIO_FORMAT_S24_32_BE,
-+ SPA_AUDIO_FORMAT_U24_32_LE,
-+ SPA_AUDIO_FORMAT_U24_32_BE,
-+ SPA_AUDIO_FORMAT_S32_LE,
-+ SPA_AUDIO_FORMAT_S32_BE,
-+ SPA_AUDIO_FORMAT_U32_LE,
-+ SPA_AUDIO_FORMAT_U32_BE,
-+ SPA_AUDIO_FORMAT_S24_LE,
-+ SPA_AUDIO_FORMAT_S24_BE,
-+ SPA_AUDIO_FORMAT_U24_LE,
-+ SPA_AUDIO_FORMAT_U24_BE,
-+ SPA_AUDIO_FORMAT_S20_LE,
-+ SPA_AUDIO_FORMAT_S20_BE,
-+ SPA_AUDIO_FORMAT_U20_LE,
-+ SPA_AUDIO_FORMAT_U20_BE,
-+ SPA_AUDIO_FORMAT_S18_LE,
-+ SPA_AUDIO_FORMAT_S18_BE,
-+ SPA_AUDIO_FORMAT_U18_LE,
-+ SPA_AUDIO_FORMAT_U18_BE,
-+ SPA_AUDIO_FORMAT_F32_LE,
-+ SPA_AUDIO_FORMAT_F32_BE,
-+ SPA_AUDIO_FORMAT_F64_LE,
-+ SPA_AUDIO_FORMAT_F64_BE,
-+
-+ /* planar formats */
-+ SPA_AUDIO_FORMAT_START_Planar = 0x200,
-+ SPA_AUDIO_FORMAT_U8P,
-+ SPA_AUDIO_FORMAT_S16P,
-+ SPA_AUDIO_FORMAT_S24_32P,
-+ SPA_AUDIO_FORMAT_S32P,
-+ SPA_AUDIO_FORMAT_S24P,
-+ SPA_AUDIO_FORMAT_F32P,
-+ SPA_AUDIO_FORMAT_F64P,
-+
-+ /* other formats start here */
-+ SPA_AUDIO_FORMAT_START_Other = 0x400,
-+
-+ /* Aliases */
-+
-+ /* DSP formats */
-+ SPA_AUDIO_FORMAT_DSP_S32 = SPA_AUDIO_FORMAT_S24_32P,
-+ SPA_AUDIO_FORMAT_DSP_F32 = SPA_AUDIO_FORMAT_F32P,
-+ SPA_AUDIO_FORMAT_DSP_F64 = SPA_AUDIO_FORMAT_F64P,
-+
-+ /* native endian */
-+#if __BYTE_ORDER == __BIG_ENDIAN
-+ SPA_AUDIO_FORMAT_S16 = SPA_AUDIO_FORMAT_S16_BE,
-+ SPA_AUDIO_FORMAT_U16 = SPA_AUDIO_FORMAT_U16_BE,
-+ SPA_AUDIO_FORMAT_S24_32 = SPA_AUDIO_FORMAT_S24_32_BE,
-+ SPA_AUDIO_FORMAT_U24_32 = SPA_AUDIO_FORMAT_U24_32_BE,
-+ SPA_AUDIO_FORMAT_S32 = SPA_AUDIO_FORMAT_S32_BE,
-+ SPA_AUDIO_FORMAT_U32 = SPA_AUDIO_FORMAT_U32_BE,
-+ SPA_AUDIO_FORMAT_S24 = SPA_AUDIO_FORMAT_S24_BE,
-+ SPA_AUDIO_FORMAT_U24 = SPA_AUDIO_FORMAT_U24_BE,
-+ SPA_AUDIO_FORMAT_S20 = SPA_AUDIO_FORMAT_S20_BE,
-+ SPA_AUDIO_FORMAT_U20 = SPA_AUDIO_FORMAT_U20_BE,
-+ SPA_AUDIO_FORMAT_S18 = SPA_AUDIO_FORMAT_S18_BE,
-+ SPA_AUDIO_FORMAT_U18 = SPA_AUDIO_FORMAT_U18_BE,
-+ SPA_AUDIO_FORMAT_F32 = SPA_AUDIO_FORMAT_F32_BE,
-+ SPA_AUDIO_FORMAT_F64 = SPA_AUDIO_FORMAT_F64_BE,
-+ SPA_AUDIO_FORMAT_S16_OE = SPA_AUDIO_FORMAT_S16_LE,
-+ SPA_AUDIO_FORMAT_U16_OE = SPA_AUDIO_FORMAT_U16_LE,
-+ SPA_AUDIO_FORMAT_S24_32_OE = SPA_AUDIO_FORMAT_S24_32_LE,
-+ SPA_AUDIO_FORMAT_U24_32_OE = SPA_AUDIO_FORMAT_U24_32_LE,
-+ SPA_AUDIO_FORMAT_S32_OE = SPA_AUDIO_FORMAT_S32_LE,
-+ SPA_AUDIO_FORMAT_U32_OE = SPA_AUDIO_FORMAT_U32_LE,
-+ SPA_AUDIO_FORMAT_S24_OE = SPA_AUDIO_FORMAT_S24_LE,
-+ SPA_AUDIO_FORMAT_U24_OE = SPA_AUDIO_FORMAT_U24_LE,
-+ SPA_AUDIO_FORMAT_S20_OE = SPA_AUDIO_FORMAT_S20_LE,
-+ SPA_AUDIO_FORMAT_U20_OE = SPA_AUDIO_FORMAT_U20_LE,
-+ SPA_AUDIO_FORMAT_S18_OE = SPA_AUDIO_FORMAT_S18_LE,
-+ SPA_AUDIO_FORMAT_U18_OE = SPA_AUDIO_FORMAT_U18_LE,
-+ SPA_AUDIO_FORMAT_F32_OE = SPA_AUDIO_FORMAT_F32_LE,
-+ SPA_AUDIO_FORMAT_F64_OE = SPA_AUDIO_FORMAT_F64_LE,
-+#elif __BYTE_ORDER == __LITTLE_ENDIAN
-+ SPA_AUDIO_FORMAT_S16 = SPA_AUDIO_FORMAT_S16_LE,
-+ SPA_AUDIO_FORMAT_U16 = SPA_AUDIO_FORMAT_U16_LE,
-+ SPA_AUDIO_FORMAT_S24_32 = SPA_AUDIO_FORMAT_S24_32_LE,
-+ SPA_AUDIO_FORMAT_U24_32 = SPA_AUDIO_FORMAT_U24_32_LE,
-+ SPA_AUDIO_FORMAT_S32 = SPA_AUDIO_FORMAT_S32_LE,
-+ SPA_AUDIO_FORMAT_U32 = SPA_AUDIO_FORMAT_U32_LE,
-+ SPA_AUDIO_FORMAT_S24 = SPA_AUDIO_FORMAT_S24_LE,
-+ SPA_AUDIO_FORMAT_U24 = SPA_AUDIO_FORMAT_U24_LE,
-+ SPA_AUDIO_FORMAT_S20 = SPA_AUDIO_FORMAT_S20_LE,
-+ SPA_AUDIO_FORMAT_U20 = SPA_AUDIO_FORMAT_U20_LE,
-+ SPA_AUDIO_FORMAT_S18 = SPA_AUDIO_FORMAT_S18_LE,
-+ SPA_AUDIO_FORMAT_U18 = SPA_AUDIO_FORMAT_U18_LE,
-+ SPA_AUDIO_FORMAT_F32 = SPA_AUDIO_FORMAT_F32_LE,
-+ SPA_AUDIO_FORMAT_F64 = SPA_AUDIO_FORMAT_F64_LE,
-+ SPA_AUDIO_FORMAT_S16_OE = SPA_AUDIO_FORMAT_S16_BE,
-+ SPA_AUDIO_FORMAT_U16_OE = SPA_AUDIO_FORMAT_U16_BE,
-+ SPA_AUDIO_FORMAT_S24_32_OE = SPA_AUDIO_FORMAT_S24_32_BE,
-+ SPA_AUDIO_FORMAT_U24_32_OE = SPA_AUDIO_FORMAT_U24_32_BE,
-+ SPA_AUDIO_FORMAT_S32_OE = SPA_AUDIO_FORMAT_S32_BE,
-+ SPA_AUDIO_FORMAT_U32_OE = SPA_AUDIO_FORMAT_U32_BE,
-+ SPA_AUDIO_FORMAT_S24_OE = SPA_AUDIO_FORMAT_S24_BE,
-+ SPA_AUDIO_FORMAT_U24_OE = SPA_AUDIO_FORMAT_U24_BE,
-+ SPA_AUDIO_FORMAT_S20_OE = SPA_AUDIO_FORMAT_S20_BE,
-+ SPA_AUDIO_FORMAT_U20_OE = SPA_AUDIO_FORMAT_U20_BE,
-+ SPA_AUDIO_FORMAT_S18_OE = SPA_AUDIO_FORMAT_S18_BE,
-+ SPA_AUDIO_FORMAT_U18_OE = SPA_AUDIO_FORMAT_U18_BE,
-+ SPA_AUDIO_FORMAT_F32_OE = SPA_AUDIO_FORMAT_F32_BE,
-+ SPA_AUDIO_FORMAT_F64_OE = SPA_AUDIO_FORMAT_F64_BE,
-+#endif
-+};
-+
-+#define SPA_AUDIO_FORMAT_IS_INTERLEAVED(fmt) ((fmt) > SPA_AUDIO_FORMAT_START_Interleaved && (fmt) < SPA_AUDIO_FORMAT_START_Planar)
-+#define SPA_AUDIO_FORMAT_IS_PLANAR(fmt) ((fmt) > SPA_AUDIO_FORMAT_START_Planar && (fmt) < SPA_AUDIO_FORMAT_START_Other)
-+
-+enum spa_audio_channel {
-+ SPA_AUDIO_CHANNEL_UNKNOWN, /**< unspecified */
-+ SPA_AUDIO_CHANNEL_NA, /**< N/A, silent */
-+
-+ SPA_AUDIO_CHANNEL_MONO, /**< mono stream */
-+
-+ SPA_AUDIO_CHANNEL_FL, /**< front left */
-+ SPA_AUDIO_CHANNEL_FR, /**< front right */
-+ SPA_AUDIO_CHANNEL_FC, /**< front center */
-+ SPA_AUDIO_CHANNEL_LFE, /**< LFE */
-+ SPA_AUDIO_CHANNEL_SL, /**< side left */
-+ SPA_AUDIO_CHANNEL_SR, /**< side right */
-+ SPA_AUDIO_CHANNEL_FLC, /**< front left center */
-+ SPA_AUDIO_CHANNEL_FRC, /**< front right center */
-+ SPA_AUDIO_CHANNEL_RC, /**< rear center */
-+ SPA_AUDIO_CHANNEL_RL, /**< rear left */
-+ SPA_AUDIO_CHANNEL_RR, /**< rear right */
-+ SPA_AUDIO_CHANNEL_TC, /**< top center */
-+ SPA_AUDIO_CHANNEL_TFL, /**< top front left */
-+ SPA_AUDIO_CHANNEL_TFC, /**< top front center */
-+ SPA_AUDIO_CHANNEL_TFR, /**< top front right */
-+ SPA_AUDIO_CHANNEL_TRL, /**< top rear left */
-+ SPA_AUDIO_CHANNEL_TRC, /**< top rear center */
-+ SPA_AUDIO_CHANNEL_TRR, /**< top rear right */
-+ SPA_AUDIO_CHANNEL_RLC, /**< rear left center */
-+ SPA_AUDIO_CHANNEL_RRC, /**< rear right center */
-+ SPA_AUDIO_CHANNEL_FLW, /**< front left wide */
-+ SPA_AUDIO_CHANNEL_FRW, /**< front right wide */
-+ SPA_AUDIO_CHANNEL_LFE2, /**< LFE 2 */
-+ SPA_AUDIO_CHANNEL_FLH, /**< front left high */
-+ SPA_AUDIO_CHANNEL_FCH, /**< front center high */
-+ SPA_AUDIO_CHANNEL_FRH, /**< front right high */
-+ SPA_AUDIO_CHANNEL_TFLC, /**< top front left center */
-+ SPA_AUDIO_CHANNEL_TFRC, /**< top front right center */
-+ SPA_AUDIO_CHANNEL_TSL, /**< top side left */
-+ SPA_AUDIO_CHANNEL_TSR, /**< top side right */
-+ SPA_AUDIO_CHANNEL_LLFE, /**< left LFE */
-+ SPA_AUDIO_CHANNEL_RLFE, /**< right LFE */
-+ SPA_AUDIO_CHANNEL_BC, /**< bottom center */
-+ SPA_AUDIO_CHANNEL_BLC, /**< bottom left center */
-+ SPA_AUDIO_CHANNEL_BRC, /**< bottom right center */
-+
-+ SPA_AUDIO_CHANNEL_CUSTOM_START = 0x10000,
-+};
-+
-+/** Extra audio flags */
-+#define SPA_AUDIO_FLAG_NONE (0) /*< no valid flag */
-+#define SPA_AUDIO_FLAG_UNPOSITIONED (1 << 0) /*< the position array explicitly
-+ * contains unpositioned channels. */
-+/** Audio information description */
-+struct spa_audio_info_raw {
-+ enum spa_audio_format format; /*< format, one of enum spa_audio_format */
-+ uint32_t flags; /*< extra flags */
-+ uint32_t rate; /*< sample rate */
-+ uint32_t channels; /*< number of channels */
-+ uint32_t position[SPA_AUDIO_MAX_CHANNELS]; /*< channel position from enum spa_audio_channel */
-+};
-+
-+#define SPA_AUDIO_INFO_RAW_INIT(...) (struct spa_audio_info_raw) { __VA_ARGS__ }
-+
-+#define SPA_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel as string,
-+ * Ex. "FL" */
-+#define SPA_KEY_AUDIO_CHANNELS "audio.channels" /**< an audio channel count as int */
-+#define SPA_KEY_AUDIO_RATE "audio.rate" /**< an audio sample rate as int */
-+
-+struct spa_audio_info_dsp {
-+ enum spa_audio_format format; /*< format, one of the DSP formats in enum spa_audio_format_dsp */
-+};
-+
-+#define SPA_AUDIO_INFO_DSP_INIT(...) (struct spa_audio_info_dsp) { __VA_ARGS__ }
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_AUDIO_RAW_H */
-diff --git a/third_party/pipewire/spa/param/audio/type-info.h b/third_party/pipewire/spa/param/audio/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/audio/type-info.h
-@@ -0,0 +1,140 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_AUDIO_TYPES_H
-+#define SPA_AUDIO_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/audio/raw.h>
-+
-+#define SPA_TYPE_INFO_AudioFormat SPA_TYPE_INFO_ENUM_BASE "AudioFormat"
-+#define SPA_TYPE_INFO_AUDIO_FORMAT_BASE SPA_TYPE_INFO_AudioFormat ":"
-+
-+static const struct spa_type_info spa_type_audio_format[] = {
-+ { SPA_AUDIO_FORMAT_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "UNKNOWN", NULL },
-+ { SPA_AUDIO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "ENCODED", NULL },
-+ { SPA_AUDIO_FORMAT_S8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S8", NULL },
-+ { SPA_AUDIO_FORMAT_U8, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8", NULL },
-+ { SPA_AUDIO_FORMAT_S16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16LE", NULL },
-+ { SPA_AUDIO_FORMAT_S16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16BE", NULL },
-+ { SPA_AUDIO_FORMAT_U16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16LE", NULL },
-+ { SPA_AUDIO_FORMAT_U16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U16BE", NULL },
-+ { SPA_AUDIO_FORMAT_S24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32LE", NULL },
-+ { SPA_AUDIO_FORMAT_S24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32BE", NULL },
-+ { SPA_AUDIO_FORMAT_U24_32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32LE", NULL },
-+ { SPA_AUDIO_FORMAT_U24_32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24_32BE", NULL },
-+ { SPA_AUDIO_FORMAT_S32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32LE", NULL },
-+ { SPA_AUDIO_FORMAT_S32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32BE", NULL },
-+ { SPA_AUDIO_FORMAT_U32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32LE", NULL },
-+ { SPA_AUDIO_FORMAT_U32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U32BE", NULL },
-+ { SPA_AUDIO_FORMAT_S24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24LE", NULL },
-+ { SPA_AUDIO_FORMAT_S24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24BE", NULL },
-+ { SPA_AUDIO_FORMAT_U24_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24LE", NULL },
-+ { SPA_AUDIO_FORMAT_U24_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U24BE", NULL },
-+ { SPA_AUDIO_FORMAT_S20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20LE", NULL },
-+ { SPA_AUDIO_FORMAT_S20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S20BE", NULL },
-+ { SPA_AUDIO_FORMAT_U20_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20LE", NULL },
-+ { SPA_AUDIO_FORMAT_U20_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U20BE", NULL },
-+ { SPA_AUDIO_FORMAT_S18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18LE", NULL },
-+ { SPA_AUDIO_FORMAT_S18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S18BE", NULL },
-+ { SPA_AUDIO_FORMAT_U18_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18LE", NULL },
-+ { SPA_AUDIO_FORMAT_U18_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U18BE", NULL },
-+ { SPA_AUDIO_FORMAT_F32_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32LE", NULL },
-+ { SPA_AUDIO_FORMAT_F32_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32BE", NULL },
-+ { SPA_AUDIO_FORMAT_F64_LE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64LE", NULL },
-+ { SPA_AUDIO_FORMAT_F64_BE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64BE", NULL },
-+
-+ { SPA_AUDIO_FORMAT_U8P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "U8P", NULL },
-+ { SPA_AUDIO_FORMAT_S16P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S16P", NULL },
-+ { SPA_AUDIO_FORMAT_S24_32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24_32P", NULL },
-+ { SPA_AUDIO_FORMAT_S32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S32P", NULL },
-+ { SPA_AUDIO_FORMAT_S24P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "S24P", NULL },
-+ { SPA_AUDIO_FORMAT_F32P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F32P", NULL },
-+ { SPA_AUDIO_FORMAT_F64P, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FORMAT_BASE "F64P", NULL },
-+
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_AudioFlags SPA_TYPE_INFO_FLAGS_BASE "AudioFlags"
-+#define SPA_TYPE_INFO_AUDIO_FLAGS_BASE SPA_TYPE_INFO_AudioFlags ":"
-+
-+static const struct spa_type_info spa_type_audio_flags[] = {
-+ { SPA_AUDIO_FLAG_NONE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "none", NULL },
-+ { SPA_AUDIO_FLAG_UNPOSITIONED, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_FLAGS_BASE "unpositioned", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_AudioChannel SPA_TYPE_INFO_ENUM_BASE "AudioChannel"
-+#define SPA_TYPE_INFO_AUDIO_CHANNEL_BASE SPA_TYPE_INFO_AudioChannel ":"
-+
-+static const struct spa_type_info spa_type_audio_channel[] = {
-+ { SPA_AUDIO_CHANNEL_UNKNOWN, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "UNK", NULL },
-+ { SPA_AUDIO_CHANNEL_NA, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "NA", NULL },
-+ { SPA_AUDIO_CHANNEL_MONO, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "MONO", NULL },
-+ { SPA_AUDIO_CHANNEL_FL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FL", NULL },
-+ { SPA_AUDIO_CHANNEL_FR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FR", NULL },
-+ { SPA_AUDIO_CHANNEL_FC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FC", NULL },
-+ { SPA_AUDIO_CHANNEL_LFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE", NULL },
-+ { SPA_AUDIO_CHANNEL_SL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SL", NULL },
-+ { SPA_AUDIO_CHANNEL_SR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "SR", NULL },
-+ { SPA_AUDIO_CHANNEL_FLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLC", NULL },
-+ { SPA_AUDIO_CHANNEL_FRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRC", NULL },
-+ { SPA_AUDIO_CHANNEL_RC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RC", NULL },
-+ { SPA_AUDIO_CHANNEL_RL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RL", NULL },
-+ { SPA_AUDIO_CHANNEL_RR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RR", NULL },
-+ { SPA_AUDIO_CHANNEL_TC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TC", NULL },
-+ { SPA_AUDIO_CHANNEL_TFL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFL", NULL },
-+ { SPA_AUDIO_CHANNEL_TFC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFC", NULL },
-+ { SPA_AUDIO_CHANNEL_TFR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFR", NULL },
-+ { SPA_AUDIO_CHANNEL_TRL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRL", NULL },
-+ { SPA_AUDIO_CHANNEL_TRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRC", NULL },
-+ { SPA_AUDIO_CHANNEL_TRR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TRR", NULL },
-+ { SPA_AUDIO_CHANNEL_RLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLC", NULL },
-+ { SPA_AUDIO_CHANNEL_RRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RRC", NULL },
-+ { SPA_AUDIO_CHANNEL_FLW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLW", NULL },
-+ { SPA_AUDIO_CHANNEL_FRW, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRW", NULL },
-+ { SPA_AUDIO_CHANNEL_LFE2, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LFE2", NULL },
-+ { SPA_AUDIO_CHANNEL_FLH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FLH", NULL },
-+ { SPA_AUDIO_CHANNEL_FCH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FCH", NULL },
-+ { SPA_AUDIO_CHANNEL_FRH, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "FRH", NULL },
-+ { SPA_AUDIO_CHANNEL_TFLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFLC", NULL },
-+ { SPA_AUDIO_CHANNEL_TFRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFRC", NULL },
-+ { SPA_AUDIO_CHANNEL_TSL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSL", NULL },
-+ { SPA_AUDIO_CHANNEL_TSR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSR", NULL },
-+ { SPA_AUDIO_CHANNEL_LLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LLFR", NULL },
-+ { SPA_AUDIO_CHANNEL_RLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLFE", NULL },
-+ { SPA_AUDIO_CHANNEL_BC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BC", NULL },
-+ { SPA_AUDIO_CHANNEL_BLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BLC", NULL },
-+ { SPA_AUDIO_CHANNEL_BRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BRC", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_AUDIO_RAW_TYPES_H */
-diff --git a/third_party/pipewire/spa/param/format-utils.h b/third_party/pipewire/spa/param/format-utils.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/format-utils.h
-@@ -0,0 +1,49 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_FORMAT_UTILS_H
-+#define SPA_PARAM_FORMAT_UTILS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+
-+#include <spa/pod/parser.h>
-+#include <spa/param/format.h>
-+
-+static inline int
-+spa_format_parse(const struct spa_pod *format, uint32_t *media_type, uint32_t *media_subtype)
-+{
-+ return spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_mediaType, SPA_POD_Id(media_type),
-+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(media_subtype));
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_FORMAT_UTILS_H */
-diff --git a/third_party/pipewire/spa/param/format.h b/third_party/pipewire/spa/param/format.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/format.h
-@@ -0,0 +1,147 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_FORMAT_H
-+#define SPA_PARAM_FORMAT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/param.h>
-+
-+/** media type for SPA_TYPE_OBJECT_Format */
-+enum spa_media_type {
-+ SPA_MEDIA_TYPE_unknown,
-+ SPA_MEDIA_TYPE_audio,
-+ SPA_MEDIA_TYPE_video,
-+ SPA_MEDIA_TYPE_image,
-+ SPA_MEDIA_TYPE_binary,
-+ SPA_MEDIA_TYPE_stream,
-+ SPA_MEDIA_TYPE_application,
-+};
-+
-+/** media subtype for SPA_TYPE_OBJECT_Format */
-+enum spa_media_subtype {
-+ SPA_MEDIA_SUBTYPE_unknown,
-+ SPA_MEDIA_SUBTYPE_raw,
-+ SPA_MEDIA_SUBTYPE_dsp,
-+
-+ SPA_MEDIA_SUBTYPE_START_Audio = 0x10000,
-+ SPA_MEDIA_SUBTYPE_mp3,
-+ SPA_MEDIA_SUBTYPE_aac,
-+ SPA_MEDIA_SUBTYPE_vorbis,
-+ SPA_MEDIA_SUBTYPE_wma,
-+ SPA_MEDIA_SUBTYPE_ra,
-+ SPA_MEDIA_SUBTYPE_sbc,
-+ SPA_MEDIA_SUBTYPE_adpcm,
-+ SPA_MEDIA_SUBTYPE_g723,
-+ SPA_MEDIA_SUBTYPE_g726,
-+ SPA_MEDIA_SUBTYPE_g729,
-+ SPA_MEDIA_SUBTYPE_amr,
-+ SPA_MEDIA_SUBTYPE_gsm,
-+
-+ SPA_MEDIA_SUBTYPE_START_Video = 0x20000,
-+ SPA_MEDIA_SUBTYPE_h264,
-+ SPA_MEDIA_SUBTYPE_mjpg,
-+ SPA_MEDIA_SUBTYPE_dv,
-+ SPA_MEDIA_SUBTYPE_mpegts,
-+ SPA_MEDIA_SUBTYPE_h263,
-+ SPA_MEDIA_SUBTYPE_mpeg1,
-+ SPA_MEDIA_SUBTYPE_mpeg2,
-+ SPA_MEDIA_SUBTYPE_mpeg4,
-+ SPA_MEDIA_SUBTYPE_xvid,
-+ SPA_MEDIA_SUBTYPE_vc1,
-+ SPA_MEDIA_SUBTYPE_vp8,
-+ SPA_MEDIA_SUBTYPE_vp9,
-+ SPA_MEDIA_SUBTYPE_bayer,
-+
-+ SPA_MEDIA_SUBTYPE_START_Image = 0x30000,
-+ SPA_MEDIA_SUBTYPE_jpeg,
-+
-+ SPA_MEDIA_SUBTYPE_START_Binary = 0x40000,
-+
-+ SPA_MEDIA_SUBTYPE_START_Stream = 0x50000,
-+ SPA_MEDIA_SUBTYPE_midi,
-+
-+ SPA_MEDIA_SUBTYPE_START_Application = 0x60000,
-+ SPA_MEDIA_SUBTYPE_control, /**< control stream, data contains
-+ * spa_pod_sequence with control info. */
-+};
-+
-+/** properties for audio SPA_TYPE_OBJECT_Format */
-+enum spa_format {
-+ SPA_FORMAT_START,
-+
-+ SPA_FORMAT_mediaType, /**< media type (Id enum spa_media_type) */
-+ SPA_FORMAT_mediaSubtype, /**< media subtype (Id enum spa_media_subtype) */
-+
-+ /* Audio format keys */
-+ SPA_FORMAT_START_Audio = 0x10000,
-+ SPA_FORMAT_AUDIO_format, /**< audio format, (Id enum spa_audio_format) */
-+ SPA_FORMAT_AUDIO_flags, /**< optional flags (Int) */
-+ SPA_FORMAT_AUDIO_rate, /**< sample rate (Int) */
-+ SPA_FORMAT_AUDIO_channels, /**< number of audio channels (Int) */
-+ SPA_FORMAT_AUDIO_position, /**< channel positions (Id enum spa_audio_position) */
-+
-+ /* Video Format keys */
-+ SPA_FORMAT_START_Video = 0x20000,
-+ SPA_FORMAT_VIDEO_format, /**< video format (Id enum spa_video_format) */
-+ SPA_FORMAT_VIDEO_modifier, /**< format modifier (Long) */
-+ SPA_FORMAT_VIDEO_size, /**< size (Rectangle) */
-+ SPA_FORMAT_VIDEO_framerate, /**< frame rate (Fraction) */
-+ SPA_FORMAT_VIDEO_maxFramerate, /**< maximum frame rate (Fraction) */
-+ SPA_FORMAT_VIDEO_views, /**< number of views (Int) */
-+ SPA_FORMAT_VIDEO_interlaceMode, /**< (Id enum spa_video_interlace_mode) */
-+ SPA_FORMAT_VIDEO_pixelAspectRatio, /**< (Rectangle) */
-+ SPA_FORMAT_VIDEO_multiviewMode, /**< (Id enum spa_video_multiview_mode) */
-+ SPA_FORMAT_VIDEO_multiviewFlags, /**< (Id enum spa_video_multiview_flags) */
-+ SPA_FORMAT_VIDEO_chromaSite, /**< /Id enum spa_video_chroma_site) */
-+ SPA_FORMAT_VIDEO_colorRange, /**< /Id enum spa_video_color_range) */
-+ SPA_FORMAT_VIDEO_colorMatrix, /**< /Id enum spa_video_color_matrix) */
-+ SPA_FORMAT_VIDEO_transferFunction, /**< /Id enum spa_video_transfer_function) */
-+ SPA_FORMAT_VIDEO_colorPrimaries, /**< /Id enum spa_video_color_primaries) */
-+ SPA_FORMAT_VIDEO_profile, /**< (Int) */
-+ SPA_FORMAT_VIDEO_level, /**< (Int) */
-+ SPA_FORMAT_VIDEO_H264_streamFormat, /**< (Id enum spa_h264_stream_format) */
-+ SPA_FORMAT_VIDEO_H264_alignment, /**< (Id enum spa_h264_alignment) */
-+
-+ /* Image Format keys */
-+ SPA_FORMAT_START_Image = 0x30000,
-+ /* Binary Format keys */
-+ SPA_FORMAT_START_Binary = 0x40000,
-+ /* Stream Format keys */
-+ SPA_FORMAT_START_Stream = 0x50000,
-+ /* Application Format keys */
-+ SPA_FORMAT_START_Application = 0x60000,
-+};
-+
-+#define SPA_KEY_FORMAT_DSP "format.dsp" /**< a predefined DSP format,
-+ * Ex. "32 bit float mono audio" */
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_FORMAT_H */
-diff --git a/third_party/pipewire/spa/param/param.h b/third_party/pipewire/spa/param/param.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/param.h
-@@ -0,0 +1,166 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_H
-+#define SPA_PARAM_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+
-+/** different parameter types that can be queried */
-+enum spa_param_type {
-+ SPA_PARAM_Invalid, /**< invalid */
-+ SPA_PARAM_PropInfo, /**< property information as SPA_TYPE_OBJECT_PropInfo */
-+ SPA_PARAM_Props, /**< properties as SPA_TYPE_OBJECT_Props */
-+ SPA_PARAM_EnumFormat, /**< available formats as SPA_TYPE_OBJECT_Format */
-+ SPA_PARAM_Format, /**< configured format as SPA_TYPE_OBJECT_Format */
-+ SPA_PARAM_Buffers, /**< buffer configurations as SPA_TYPE_OBJECT_ParamBuffers*/
-+ SPA_PARAM_Meta, /**< allowed metadata for buffers as SPA_TYPE_OBJECT_ParamMeta*/
-+ SPA_PARAM_IO, /**< configurable IO areas as SPA_TYPE_OBJECT_ParamIO */
-+ SPA_PARAM_EnumProfile, /**< profile enumeration as SPA_TYPE_OBJECT_ParamProfile */
-+ SPA_PARAM_Profile, /**< profile configuration as SPA_TYPE_OBJECT_ParamProfile */
-+ SPA_PARAM_EnumPortConfig, /**< port configuration enumeration as SPA_TYPE_OBJECT_ParamPortConfig */
-+ SPA_PARAM_PortConfig, /**< port configuration as SPA_TYPE_OBJECT_ParamPortConfig */
-+ SPA_PARAM_EnumRoute, /**< routing enumeration as SPA_TYPE_OBJECT_ParamRoute */
-+ SPA_PARAM_Route, /**< routing configuration as SPA_TYPE_OBJECT_ParamRoute */
-+ SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */
-+};
-+
-+/** information about a parameter */
-+struct spa_param_info {
-+ uint32_t id; /**< enum spa_param_type */
-+#define SPA_PARAM_INFO_SERIAL (1<<0) /**< bit to signal update even when the
-+ * read/write flags don't change */
-+#define SPA_PARAM_INFO_READ (1<<1)
-+#define SPA_PARAM_INFO_WRITE (1<<2)
-+#define SPA_PARAM_INFO_READWRITE (SPA_PARAM_INFO_WRITE|SPA_PARAM_INFO_READ)
-+ uint32_t flags;
-+ uint32_t user; /**< private user field. You can use this to keep
-+ * state. */
-+ uint32_t padding[5];
-+};
-+
-+#define SPA_PARAM_INFO(id,flags) (struct spa_param_info){ (id), (flags) }
-+
-+/** properties for SPA_TYPE_OBJECT_ParamBuffers */
-+enum spa_param_buffers {
-+ SPA_PARAM_BUFFERS_START,
-+ SPA_PARAM_BUFFERS_buffers, /**< number of buffers (Int) */
-+ SPA_PARAM_BUFFERS_blocks, /**< number of data blocks per buffer (Int) */
-+ SPA_PARAM_BUFFERS_size, /**< size of a data block memory (Int)*/
-+ SPA_PARAM_BUFFERS_stride, /**< stride of data block memory (Int) */
-+ SPA_PARAM_BUFFERS_align, /**< alignment of data block memory (Int) */
-+ SPA_PARAM_BUFFERS_dataType, /**< possible memory types (Int, mask of enum spa_data_type) */
-+};
-+
-+/** properties for SPA_TYPE_OBJECT_ParamMeta */
-+enum spa_param_meta {
-+ SPA_PARAM_META_START,
-+ SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */
-+ SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */
-+};
-+
-+/** properties for SPA_TYPE_OBJECT_ParamIO */
-+enum spa_param_io {
-+ SPA_PARAM_IO_START,
-+ SPA_PARAM_IO_id, /**< type ID, uniquely identifies the io area (Id enum spa_io_type) */
-+ SPA_PARAM_IO_size, /**< size of the io area (Int) */
-+};
-+
-+enum spa_param_availability {
-+ SPA_PARAM_AVAILABILITY_unknown, /**< unknown availability */
-+ SPA_PARAM_AVAILABILITY_no, /**< not available */
-+ SPA_PARAM_AVAILABILITY_yes, /**< available */
-+};
-+
-+/** properties for SPA_TYPE_OBJECT_ParamProfile */
-+enum spa_param_profile {
-+ SPA_PARAM_PROFILE_START,
-+ SPA_PARAM_PROFILE_index, /**< profile index (Int) */
-+ SPA_PARAM_PROFILE_name, /**< profile name (String) */
-+ SPA_PARAM_PROFILE_description, /**< profile description (String) */
-+ SPA_PARAM_PROFILE_priority, /**< profile priority (Int) */
-+ SPA_PARAM_PROFILE_available, /**< availability of the profile
-+ * (Id enum spa_param_availability) */
-+ SPA_PARAM_PROFILE_info, /**< info (Struct(
-+ * Int : n_items,
-+ * (String : key,
-+ * String : value)*)) */
-+ SPA_PARAM_PROFILE_classes, /**< node classes provided by this profile
-+ * (Struct(
-+ * Int : number of items following
-+ * Struct(
-+ * String : class name (eg. "Audio/Source"),
-+ * Int : number of nodes)*)) */
-+};
-+
-+enum spa_param_port_config_mode {
-+ SPA_PARAM_PORT_CONFIG_MODE_none, /**< no configuration */
-+ SPA_PARAM_PORT_CONFIG_MODE_passthrough, /**< passthrough configuration */
-+ SPA_PARAM_PORT_CONFIG_MODE_convert, /**< convert configuration */
-+ SPA_PARAM_PORT_CONFIG_MODE_dsp, /**< dsp configuration, depending on the external
-+ * format. For audio, ports will be configured for
-+ * the given number of channels with F32 format. */
-+};
-+
-+/** properties for SPA_TYPE_OBJECT_ParamPortConfig */
-+enum spa_param_port_config {
-+ SPA_PARAM_PORT_CONFIG_START,
-+ SPA_PARAM_PORT_CONFIG_direction, /**< direction, input/output (Id enum spa_direction) */
-+ SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */
-+ SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */
-+ SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */
-+ SPA_PARAM_PORT_CONFIG_format, /**< (Object) format filter */
-+};
-+
-+/** properties for SPA_TYPE_OBJECT_ParamRoute */
-+enum spa_param_route {
-+ SPA_PARAM_ROUTE_START,
-+ SPA_PARAM_ROUTE_index, /**< index of the routing destination (Int) */
-+ SPA_PARAM_ROUTE_direction, /**< direction, input/output (Id enum spa_direction) */
-+ SPA_PARAM_ROUTE_device, /**< device id (Int) */
-+ SPA_PARAM_ROUTE_name, /**< name of the routing destination (String) */
-+ SPA_PARAM_ROUTE_description, /**< description of the destination (String) */
-+ SPA_PARAM_ROUTE_priority, /**< priority of the destination (Int) */
-+ SPA_PARAM_ROUTE_available, /**< availability of the destination
-+ * (Id enum spa_param_availability) */
-+ SPA_PARAM_ROUTE_info, /**< info (Struct(
-+ * Int : n_items,
-+ * (String : key,
-+ * String : value)*)) */
-+ SPA_PARAM_ROUTE_profiles, /**< associated profile indexes (Array of Int) */
-+ SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */
-+ SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */
-+ SPA_PARAM_ROUTE_profile, /**< profile id (Int) */
-+};
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_H */
-diff --git a/third_party/pipewire/spa/param/profiler.h b/third_party/pipewire/spa/param/profiler.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/profiler.h
-@@ -0,0 +1,84 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2020 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_PROFILER_H
-+#define SPA_PARAM_PROFILER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/param.h>
-+
-+/** properties for SPA_TYPE_OBJECT_Profiler */
-+enum spa_profiler {
-+ SPA_PROFILER_START,
-+
-+ SPA_PROFILER_START_Driver = 0x10000, /**< driver related profiler properties */
-+ SPA_PROFILER_info, /**< Generic info, counter and CPU load,
-+ * (Struct(
-+ * Long : counter,
-+ * Float : cpu_load fast,
-+ * Float : cpu_load medium,
-+ * Float : cpu_load slow)) */
-+ SPA_PROFILER_clock, /**< clock information
-+ * (Struct(
-+ * Int : clock flags,
-+ * Int : clock id,
-+ * String: clock name,
-+ * Long : clock nsec,
-+ * Fraction : clock rate,
-+ * Long : clock position,
-+ * Long : clock duration,
-+ * Long : clock delay,
-+ * Double : clock rate_diff,
-+ * Long : clock next_nsec)) */
-+ SPA_PROFILER_driverBlock, /**< generic driver info block
-+ * (Struct(
-+ * Int : driver_id,
-+ * String : name,
-+ * Long : driver prev_signal,
-+ * Long : driver signal,
-+ * Long : driver awake,
-+ * Long : driver finish,
-+ * Int : driver status)) */
-+
-+ SPA_PROFILER_START_Follower = 0x20000, /**< follower related profiler properties */
-+ SPA_PROFILER_followerBlock, /**< generic follower info block
-+ * (Struct(
-+ * Int : id,
-+ * String : name,
-+ * Long : prev_signal,
-+ * Long : signal,
-+ * Long : awake,
-+ * Long : finish,
-+ * Int : status)) */
-+ SPA_PROFILER_START_CUSTOM = 0x1000000,
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_PROFILER_H */
-diff --git a/third_party/pipewire/spa/param/props.h b/third_party/pipewire/spa/param/props.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/props.h
-@@ -0,0 +1,99 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_PROPS_H
-+#define SPA_PARAM_PROPS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/param.h>
-+
-+/** properties of SPA_TYPE_OBJECT_PropInfo */
-+enum spa_prop_info {
-+ SPA_PROP_INFO_START,
-+ SPA_PROP_INFO_id, /**< associated id of the property */
-+ SPA_PROP_INFO_name, /**< name of the property */
-+ SPA_PROP_INFO_type, /**< type and range/enums of property */
-+ SPA_PROP_INFO_labels, /**< labels of property if any, this is a
-+ * struct with pairs of values, the first one
-+ * is of the type of the property, the second
-+ * one is a string with a user readable label
-+ * for the value. */
-+};
-+
-+/** predefined properties for SPA_TYPE_OBJECT_Props */
-+enum spa_prop {
-+ SPA_PROP_START,
-+
-+ SPA_PROP_unknown, /**< an unknown property */
-+
-+ SPA_PROP_START_Device = 0x100, /**< device related properties */
-+ SPA_PROP_device,
-+ SPA_PROP_deviceName,
-+ SPA_PROP_deviceFd,
-+ SPA_PROP_card,
-+ SPA_PROP_cardName,
-+
-+ SPA_PROP_minLatency,
-+ SPA_PROP_maxLatency,
-+ SPA_PROP_periods,
-+ SPA_PROP_periodSize,
-+ SPA_PROP_periodEvent,
-+ SPA_PROP_live,
-+ SPA_PROP_rate,
-+ SPA_PROP_quality,
-+
-+ SPA_PROP_START_Audio = 0x10000, /**< audio related properties */
-+ SPA_PROP_waveType,
-+ SPA_PROP_frequency,
-+ SPA_PROP_volume, /**< a volume (Float), 0.0 silence, 1.0 normal */
-+ SPA_PROP_mute, /**< mute (Bool) */
-+ SPA_PROP_patternType,
-+ SPA_PROP_ditherType,
-+ SPA_PROP_truncate,
-+ SPA_PROP_channelVolumes, /**< a volume array, one volume per
-+ * channel (Array of Float) */
-+ SPA_PROP_volumeBase, /**< a volume base (Float) */
-+ SPA_PROP_volumeStep, /**< a volume step (Float) */
-+
-+ SPA_PROP_START_Video = 0x20000, /**< video related properties */
-+ SPA_PROP_brightness,
-+ SPA_PROP_contrast,
-+ SPA_PROP_saturation,
-+ SPA_PROP_hue,
-+ SPA_PROP_gamma,
-+ SPA_PROP_exposure,
-+ SPA_PROP_gain,
-+ SPA_PROP_sharpness,
-+
-+ SPA_PROP_START_CUSTOM = 0x1000000,
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_PROPS_H */
-diff --git a/third_party/pipewire/spa/param/type-info.h b/third_party/pipewire/spa/param/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/type-info.h
-@@ -0,0 +1,362 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_TYPES_H
-+#define SPA_PARAM_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/param/props.h>
-+#include <spa/param/format.h>
-+#include <spa/buffer/type-info.h>
-+
-+/* base for parameter object enumerations */
-+#define SPA_TYPE_INFO_ParamId SPA_TYPE_INFO_ENUM_BASE "ParamId"
-+#define SPA_TYPE_INFO_PARAM_ID_BASE SPA_TYPE_INFO_ParamId ":"
-+
-+static const struct spa_type_info spa_type_param[] = {
-+ { SPA_PARAM_Invalid, SPA_TYPE_None, SPA_TYPE_INFO_PARAM_ID_BASE "Invalid", NULL },
-+ { SPA_PARAM_PropInfo, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ID_BASE "PropInfo", NULL },
-+ { SPA_PARAM_Props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ID_BASE "Props", NULL },
-+ { SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "EnumFormat", NULL },
-+ { SPA_PARAM_Format, SPA_TYPE_OBJECT_Format, SPA_TYPE_INFO_PARAM_ID_BASE "Format", NULL },
-+ { SPA_PARAM_Buffers, SPA_TYPE_OBJECT_ParamBuffers, SPA_TYPE_INFO_PARAM_ID_BASE "Buffers", NULL },
-+ { SPA_PARAM_Meta, SPA_TYPE_OBJECT_ParamMeta, SPA_TYPE_INFO_PARAM_ID_BASE "Meta", NULL },
-+ { SPA_PARAM_IO, SPA_TYPE_OBJECT_ParamIO, SPA_TYPE_INFO_PARAM_ID_BASE "IO", NULL },
-+ { SPA_PARAM_EnumProfile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "EnumProfile", NULL },
-+ { SPA_PARAM_Profile, SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_INFO_PARAM_ID_BASE "Profile", NULL },
-+ { SPA_PARAM_EnumPortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "EnumPortConfig", NULL },
-+ { SPA_PARAM_PortConfig, SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_INFO_PARAM_ID_BASE "PortConfig", NULL },
-+ { SPA_PARAM_EnumRoute, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "EnumRoute", NULL },
-+ { SPA_PARAM_Route, SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_INFO_PARAM_ID_BASE "Route", NULL },
-+ { SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+/* base for parameter objects */
-+#define SPA_TYPE_INFO_Param SPA_TYPE_INFO_OBJECT_BASE "Param"
-+#define SPA_TYPE_INFO_PARAM_BASE SPA_TYPE_INFO_Param ":"
-+
-+#define SPA_TYPE_INFO_Props SPA_TYPE_INFO_PARAM_BASE "Props"
-+#define SPA_TYPE_INFO_PROPS_BASE SPA_TYPE_INFO_Props ":"
-+
-+static const struct spa_type_info spa_type_props[] = {
-+ { SPA_PROP_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE, spa_type_param, },
-+ { SPA_PROP_unknown, SPA_TYPE_None, SPA_TYPE_INFO_PROPS_BASE "unknown", NULL },
-+ { SPA_PROP_device, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "device", NULL },
-+ { SPA_PROP_deviceName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "deviceName", NULL },
-+ { SPA_PROP_deviceFd, SPA_TYPE_Fd, SPA_TYPE_INFO_PROPS_BASE "deviceFd", NULL },
-+ { SPA_PROP_card, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "card", NULL },
-+ { SPA_PROP_cardName, SPA_TYPE_String, SPA_TYPE_INFO_PROPS_BASE "cardName", NULL },
-+ { SPA_PROP_minLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "minLatency", NULL },
-+ { SPA_PROP_maxLatency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "maxLatency", NULL },
-+ { SPA_PROP_periods, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periods", NULL },
-+ { SPA_PROP_periodSize, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "periodSize", NULL },
-+ { SPA_PROP_periodEvent, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "periodEvent", NULL },
-+ { SPA_PROP_live, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "live", NULL },
-+ { SPA_PROP_rate, SPA_TYPE_Double, SPA_TYPE_INFO_PROPS_BASE "rate", NULL },
-+ { SPA_PROP_quality, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "quality", NULL },
-+
-+ { SPA_PROP_waveType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "waveType", NULL },
-+ { SPA_PROP_frequency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "frequency", NULL },
-+ { SPA_PROP_volume, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volume", NULL },
-+ { SPA_PROP_mute, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "mute", NULL },
-+ { SPA_PROP_patternType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "patternType", NULL },
-+ { SPA_PROP_ditherType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "ditherType", NULL },
-+ { SPA_PROP_truncate, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "truncate", NULL },
-+ { SPA_PROP_channelVolumes, SPA_TYPE_Array, SPA_TYPE_INFO_PROPS_BASE "channelVolumes", NULL },
-+ { SPA_PROP_volumeBase, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeBase", NULL },
-+ { SPA_PROP_volumeStep, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "volumeStep", NULL },
-+
-+ { SPA_PROP_brightness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL },
-+ { SPA_PROP_contrast, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL },
-+ { SPA_PROP_saturation, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "saturation", NULL },
-+ { SPA_PROP_hue, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "hue", NULL },
-+ { SPA_PROP_gamma, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gamma", NULL },
-+ { SPA_PROP_exposure, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "exposure", NULL },
-+ { SPA_PROP_gain, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "gain", NULL },
-+ { SPA_PROP_sharpness, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "sharpness", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+/** Enum Property info */
-+#define SPA_TYPE_INFO_PropInfo SPA_TYPE_INFO_PARAM_BASE "PropInfo"
-+#define SPA_TYPE_INFO_PROP_INFO_BASE SPA_TYPE_INFO_PropInfo ":"
-+
-+static const struct spa_type_info spa_type_prop_info[] = {
-+ { SPA_PROP_INFO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE, spa_type_param, },
-+ { SPA_PROP_INFO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PROP_INFO_BASE "id", spa_type_props },
-+ { SPA_PROP_INFO_name, SPA_TYPE_String, SPA_TYPE_INFO_PROP_INFO_BASE "name", NULL },
-+ { SPA_PROP_INFO_type, SPA_TYPE_Pod, SPA_TYPE_INFO_PROP_INFO_BASE "type", NULL },
-+ { SPA_PROP_INFO_labels, SPA_TYPE_Struct, SPA_TYPE_INFO_PROP_INFO_BASE "labels", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_PARAM_Meta SPA_TYPE_INFO_PARAM_BASE "Meta"
-+#define SPA_TYPE_INFO_PARAM_META_BASE SPA_TYPE_INFO_PARAM_Meta ":"
-+
-+static const struct spa_type_info spa_type_param_meta[] = {
-+ { SPA_PARAM_META_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE, spa_type_param },
-+ { SPA_PARAM_META_type, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_META_BASE "type", spa_type_meta_type },
-+ { SPA_PARAM_META_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_META_BASE "size", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+/** Base for parameters that describe IO areas to exchange data,
-+ * control and properties with a node.
-+ */
-+#define SPA_TYPE_INFO_PARAM_IO SPA_TYPE_INFO_PARAM_BASE "IO"
-+#define SPA_TYPE_INFO_PARAM_IO_BASE SPA_TYPE_INFO_PARAM_IO ":"
-+
-+static const struct spa_type_info spa_type_param_io[] = {
-+ { SPA_PARAM_IO_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE, spa_type_param, },
-+ { SPA_PARAM_IO_id, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_IO_BASE "id", spa_type_io },
-+ { SPA_PARAM_IO_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_IO_BASE "size", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_Format SPA_TYPE_INFO_PARAM_BASE "Format"
-+#define SPA_TYPE_INFO_FORMAT_BASE SPA_TYPE_INFO_Format ":"
-+
-+#define SPA_TYPE_INFO_MediaType SPA_TYPE_INFO_ENUM_BASE "MediaType"
-+#define SPA_TYPE_INFO_MEDIA_TYPE_BASE SPA_TYPE_INFO_MediaType ":"
-+
-+#include <spa/param/audio/type-info.h>
-+#include <spa/param/video/type-info.h>
-+
-+static const struct spa_type_info spa_type_media_type[] = {
-+ { SPA_MEDIA_TYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "unknown", NULL },
-+ { SPA_MEDIA_TYPE_audio, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "audio", NULL },
-+ { SPA_MEDIA_TYPE_video, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "video", NULL },
-+ { SPA_MEDIA_TYPE_image, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "image", NULL },
-+ { SPA_MEDIA_TYPE_binary, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "binary", NULL },
-+ { SPA_MEDIA_TYPE_stream, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "stream", NULL },
-+ { SPA_MEDIA_TYPE_application, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_TYPE_BASE "application", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_MediaSubtype SPA_TYPE_INFO_ENUM_BASE "MediaSubtype"
-+#define SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE SPA_TYPE_INFO_MediaSubtype ":"
-+
-+static const struct spa_type_info spa_type_media_subtype[] = {
-+ { SPA_MEDIA_SUBTYPE_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "unknown", NULL },
-+ /* generic subtypes */
-+ { SPA_MEDIA_SUBTYPE_raw, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "raw", NULL },
-+ { SPA_MEDIA_SUBTYPE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dsp", NULL },
-+ /* audio subtypes */
-+ { SPA_MEDIA_SUBTYPE_mp3, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mp3", NULL },
-+ { SPA_MEDIA_SUBTYPE_aac, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "aac", NULL },
-+ { SPA_MEDIA_SUBTYPE_vorbis, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vorbis", NULL },
-+ { SPA_MEDIA_SUBTYPE_wma, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "wma", NULL },
-+ { SPA_MEDIA_SUBTYPE_ra, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "ra", NULL },
-+ { SPA_MEDIA_SUBTYPE_sbc, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "sbc", NULL },
-+ { SPA_MEDIA_SUBTYPE_adpcm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "adpcm", NULL },
-+ { SPA_MEDIA_SUBTYPE_g723, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g723", NULL },
-+ { SPA_MEDIA_SUBTYPE_g726, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g726", NULL },
-+ { SPA_MEDIA_SUBTYPE_g729, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "g729", NULL },
-+ { SPA_MEDIA_SUBTYPE_amr, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "amr", NULL },
-+ { SPA_MEDIA_SUBTYPE_gsm, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "gsm", NULL },
-+ /* video subtypes */
-+ { SPA_MEDIA_SUBTYPE_h264, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h264", NULL },
-+ { SPA_MEDIA_SUBTYPE_mjpg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mjpg", NULL },
-+ { SPA_MEDIA_SUBTYPE_dv, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "dv", NULL },
-+ { SPA_MEDIA_SUBTYPE_mpegts, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpegts", NULL },
-+ { SPA_MEDIA_SUBTYPE_h263, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "h263", NULL },
-+ { SPA_MEDIA_SUBTYPE_mpeg1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg1", NULL },
-+ { SPA_MEDIA_SUBTYPE_mpeg2, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg2", NULL },
-+ { SPA_MEDIA_SUBTYPE_mpeg4, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "mpeg4", NULL },
-+ { SPA_MEDIA_SUBTYPE_xvid, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "xvid", NULL },
-+ { SPA_MEDIA_SUBTYPE_vc1, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vc1", NULL },
-+ { SPA_MEDIA_SUBTYPE_vp8, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp8", NULL },
-+ { SPA_MEDIA_SUBTYPE_vp9, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "vp9", NULL },
-+ { SPA_MEDIA_SUBTYPE_bayer, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "bayer", NULL },
-+ /* image subtypes */
-+ { SPA_MEDIA_SUBTYPE_jpeg, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "jpeg", NULL },
-+ /* stream subtypes */
-+ { SPA_MEDIA_SUBTYPE_midi, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "midi", NULL },
-+ /* application subtypes */
-+ { SPA_MEDIA_SUBTYPE_control, SPA_TYPE_Int, SPA_TYPE_INFO_MEDIA_SUBTYPE_BASE "control", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_FormatAudio SPA_TYPE_INFO_FORMAT_BASE "Audio"
-+#define SPA_TYPE_INFO_FORMAT_AUDIO_BASE SPA_TYPE_INFO_FormatAudio ":"
-+
-+#define SPA_TYPE_INFO_FormatVideo SPA_TYPE_INFO_FORMAT_BASE "Video"
-+#define SPA_TYPE_INFO_FORMAT_VIDEO_BASE SPA_TYPE_INFO_FormatVideo ":"
-+
-+#define SPA_TYPE_INFO_FORMAT_VIDEO_H264 SPA_TYPE_INFO_FORMAT_VIDEO_BASE "H264"
-+#define SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE SPA_TYPE_INFO_FORMAT_VIDEO_H264 ":"
-+
-+static const struct spa_type_info spa_type_format[] = {
-+ { SPA_FORMAT_START, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE, spa_type_param, },
-+
-+ { SPA_FORMAT_mediaType, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaType",
-+ spa_type_media_type, },
-+ { SPA_FORMAT_mediaSubtype, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_BASE "mediaSubtype",
-+ spa_type_media_subtype, },
-+
-+ { SPA_FORMAT_AUDIO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "format",
-+ spa_type_audio_format },
-+ { SPA_FORMAT_AUDIO_flags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "flags",
-+ spa_type_audio_flags },
-+ { SPA_FORMAT_AUDIO_rate, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "rate", NULL },
-+ { SPA_FORMAT_AUDIO_channels, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "channels", NULL },
-+ { SPA_FORMAT_AUDIO_position, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_AUDIO_BASE "position",
-+ spa_type_audio_channel },
-+
-+ { SPA_FORMAT_VIDEO_format, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "format",
-+ spa_type_video_format, },
-+ { SPA_FORMAT_VIDEO_modifier, SPA_TYPE_Long, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "modifier", NULL },
-+ { SPA_FORMAT_VIDEO_size, SPA_TYPE_Rectangle, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "size", NULL },
-+ { SPA_FORMAT_VIDEO_framerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "framerate", NULL },
-+ { SPA_FORMAT_VIDEO_maxFramerate, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "maxFramerate", NULL },
-+ { SPA_FORMAT_VIDEO_views, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "views", NULL },
-+ { SPA_FORMAT_VIDEO_interlaceMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "interlaceMode", NULL },
-+ { SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_TYPE_Fraction, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "pixelAspectRatio", NULL },
-+ { SPA_FORMAT_VIDEO_multiviewMode, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewMode", NULL },
-+ { SPA_FORMAT_VIDEO_multiviewFlags, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "multiviewFlags", NULL },
-+ { SPA_FORMAT_VIDEO_chromaSite, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "chromaSite", NULL },
-+ { SPA_FORMAT_VIDEO_colorRange, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorRange", NULL },
-+ { SPA_FORMAT_VIDEO_colorMatrix, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorMatrix", NULL },
-+ { SPA_FORMAT_VIDEO_transferFunction, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "transferFunction", NULL },
-+ { SPA_FORMAT_VIDEO_colorPrimaries, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "colorPrimaries", NULL },
-+ { SPA_FORMAT_VIDEO_profile, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "profile", NULL },
-+ { SPA_FORMAT_VIDEO_level, SPA_TYPE_Int, SPA_TYPE_INFO_FORMAT_VIDEO_BASE "level", NULL },
-+
-+ { SPA_FORMAT_VIDEO_H264_streamFormat, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "streamFormat", NULL },
-+ { SPA_FORMAT_VIDEO_H264_alignment, SPA_TYPE_Id, SPA_TYPE_INFO_FORMAT_VIDEO_H264_BASE "alignment", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_PARAM_Buffers SPA_TYPE_INFO_PARAM_BASE "Buffers"
-+#define SPA_TYPE_INFO_PARAM_BUFFERS_BASE SPA_TYPE_INFO_PARAM_Buffers ":"
-+
-+#define SPA_TYPE_INFO_PARAM_BlockInfo SPA_TYPE_INFO_PARAM_BUFFERS_BASE "BlockInfo"
-+#define SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE SPA_TYPE_INFO_PARAM_BlockInfo ":"
-+
-+static const struct spa_type_info spa_type_param_buffers[] = {
-+ { SPA_PARAM_BUFFERS_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_BUFFERS_BASE, spa_type_param, },
-+ { SPA_PARAM_BUFFERS_buffers, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "buffers", NULL },
-+ { SPA_PARAM_BUFFERS_blocks, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BUFFERS_BASE "blocks", NULL },
-+ { SPA_PARAM_BUFFERS_size, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "size", NULL },
-+ { SPA_PARAM_BUFFERS_stride, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "stride", NULL },
-+ { SPA_PARAM_BUFFERS_align, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "align", NULL },
-+ { SPA_PARAM_BUFFERS_dataType, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_BLOCK_INFO_BASE "dataType", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_ParamAvailability SPA_TYPE_INFO_ENUM_BASE "ParamAvailability"
-+#define SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE SPA_TYPE_INFO_ParamAvailability ":"
-+
-+static const struct spa_type_info spa_type_param_availability[] = {
-+ { SPA_PARAM_AVAILABILITY_unknown, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "unknown", NULL },
-+ { SPA_PARAM_AVAILABILITY_no, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "no", NULL },
-+ { SPA_PARAM_AVAILABILITY_yes, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_AVAILABILITY_BASE "yes", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_PARAM_Profile SPA_TYPE_INFO_PARAM_BASE "Profile"
-+#define SPA_TYPE_INFO_PARAM_PROFILE_BASE SPA_TYPE_INFO_PARAM_Profile ":"
-+
-+static const struct spa_type_info spa_type_param_profile[] = {
-+ { SPA_PARAM_PROFILE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE, spa_type_param, },
-+ { SPA_PARAM_PROFILE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "index", NULL },
-+ { SPA_PARAM_PROFILE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "name", NULL },
-+ { SPA_PARAM_PROFILE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_PROFILE_BASE "description", NULL },
-+ { SPA_PARAM_PROFILE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PROFILE_BASE "priority", NULL },
-+ { SPA_PARAM_PROFILE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE "available", spa_type_param_availability, },
-+ { SPA_PARAM_PROFILE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "info", NULL, },
-+ { SPA_PARAM_PROFILE_classes, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "classes", NULL, },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_ParamPortConfigMode SPA_TYPE_INFO_ENUM_BASE "ParamPortConfigMode"
-+#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE SPA_TYPE_INFO_ParamPortConfigMode ":"
-+
-+static const struct spa_type_info spa_type_param_port_config_mode[] = {
-+ { SPA_PARAM_PORT_CONFIG_MODE_none, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "none", NULL },
-+ { SPA_PARAM_PORT_CONFIG_MODE_passthrough, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "passthrough", NULL },
-+ { SPA_PARAM_PORT_CONFIG_MODE_convert, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "convert", NULL },
-+ { SPA_PARAM_PORT_CONFIG_MODE_dsp, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_PORT_CONFIG_MODE_BASE "dsp", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#define SPA_TYPE_INFO_PARAM_PortConfig SPA_TYPE_INFO_PARAM_BASE "PortConfig"
-+#define SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE SPA_TYPE_INFO_PARAM_PortConfig ":"
-+
-+static const struct spa_type_info spa_type_param_port_config[] = {
-+ { SPA_PARAM_PORT_CONFIG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE, spa_type_param, },
-+ { SPA_PARAM_PORT_CONFIG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "direction", spa_type_direction, },
-+ { SPA_PARAM_PORT_CONFIG_mode, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "mode", spa_type_param_port_config_mode },
-+ { SPA_PARAM_PORT_CONFIG_monitor, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "monitor", NULL },
-+ { SPA_PARAM_PORT_CONFIG_control, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "control", NULL },
-+ { SPA_PARAM_PORT_CONFIG_format, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_PORT_CONFIG_BASE "format", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+
-+#define SPA_TYPE_INFO_PARAM_Route SPA_TYPE_INFO_PARAM_BASE "Route"
-+#define SPA_TYPE_INFO_PARAM_ROUTE_BASE SPA_TYPE_INFO_PARAM_Route ":"
-+
-+static const struct spa_type_info spa_type_param_route[] = {
-+ { SPA_PARAM_ROUTE_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE, spa_type_param, },
-+ { SPA_PARAM_ROUTE_index, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "index", NULL, },
-+ { SPA_PARAM_ROUTE_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "direction", spa_type_direction, },
-+ { SPA_PARAM_ROUTE_device, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "device", NULL, },
-+ { SPA_PARAM_ROUTE_name, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "name", NULL, },
-+ { SPA_PARAM_ROUTE_description, SPA_TYPE_String, SPA_TYPE_INFO_PARAM_ROUTE_BASE "description", NULL, },
-+ { SPA_PARAM_ROUTE_priority, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "priority", NULL, },
-+ { SPA_PARAM_ROUTE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_ROUTE_BASE "available", spa_type_param_availability, },
-+ { SPA_PARAM_ROUTE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ROUTE_BASE "info", NULL, },
-+ { SPA_PARAM_ROUTE_profiles, SPA_TYPE_Array, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profiles", NULL, },
-+ { SPA_PARAM_ROUTE_props, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, },
-+ { SPA_PARAM_ROUTE_devices, SPA_TYPE_Array, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, },
-+ { SPA_PARAM_ROUTE_profile, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profile", NULL, },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#include <spa/param/profiler.h>
-+
-+#define SPA_TYPE_INFO_Profiler SPA_TYPE_INFO_OBJECT_BASE "Profiler"
-+#define SPA_TYPE_INFO_PROFILER_BASE SPA_TYPE_INFO_Profiler ":"
-+
-+static const struct spa_type_info spa_type_profiler[] = {
-+ { SPA_PROFILER_START, SPA_TYPE_Id, SPA_TYPE_INFO_PROFILER_BASE, spa_type_param, },
-+ { SPA_PROFILER_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "info", NULL, },
-+ { SPA_PROFILER_clock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "clock", NULL, },
-+ { SPA_PROFILER_driverBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "driverBlock", NULL, },
-+ { SPA_PROFILER_followerBlock, SPA_TYPE_Struct, SPA_TYPE_INFO_PROFILER_BASE "followerBlock", NULL, },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_TYPES_H */
-diff --git a/third_party/pipewire/spa/param/video/chroma.h b/third_party/pipewire/spa/param/video/chroma.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/chroma.h
-@@ -0,0 +1,60 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_VIDEO_CHROMA_H
-+#define SPA_VIDEO_CHROMA_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** Various Chroma sitings.
-+ * @SPA_VIDEO_CHROMA_SITE_UNKNOWN: unknown cositing
-+ * @SPA_VIDEO_CHROMA_SITE_NONE: no cositing
-+ * @SPA_VIDEO_CHROMA_SITE_H_COSITED: chroma is horizontally cosited
-+ * @SPA_VIDEO_CHROMA_SITE_V_COSITED: chroma is vertically cosited
-+ * @SPA_VIDEO_CHROMA_SITE_ALT_LINE: choma samples are sited on alternate lines
-+ * @SPA_VIDEO_CHROMA_SITE_COSITED: chroma samples cosited with luma samples
-+ * @SPA_VIDEO_CHROMA_SITE_JPEG: jpeg style cositing, also for mpeg1 and mjpeg
-+ * @SPA_VIDEO_CHROMA_SITE_MPEG2: mpeg2 style cositing
-+ * @SPA_VIDEO_CHROMA_SITE_DV: DV style cositing
-+ */
-+enum spa_video_chroma_site {
-+ SPA_VIDEO_CHROMA_SITE_UNKNOWN = 0,
-+ SPA_VIDEO_CHROMA_SITE_NONE = (1 << 0),
-+ SPA_VIDEO_CHROMA_SITE_H_COSITED = (1 << 1),
-+ SPA_VIDEO_CHROMA_SITE_V_COSITED = (1 << 2),
-+ SPA_VIDEO_CHROMA_SITE_ALT_LINE = (1 << 3),
-+ /* some common chroma cositing */
-+ SPA_VIDEO_CHROMA_SITE_COSITED = (SPA_VIDEO_CHROMA_SITE_H_COSITED | SPA_VIDEO_CHROMA_SITE_V_COSITED),
-+ SPA_VIDEO_CHROMA_SITE_JPEG = (SPA_VIDEO_CHROMA_SITE_NONE),
-+ SPA_VIDEO_CHROMA_SITE_MPEG2 = (SPA_VIDEO_CHROMA_SITE_H_COSITED),
-+ SPA_VIDEO_CHROMA_SITE_DV = (SPA_VIDEO_CHROMA_SITE_COSITED | SPA_VIDEO_CHROMA_SITE_ALT_LINE),
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_VIDEO_CHROMA_H */
-diff --git a/third_party/pipewire/spa/param/video/color.h b/third_party/pipewire/spa/param/video/color.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/color.h
-@@ -0,0 +1,162 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_VIDEO_COLOR_H
-+#define SPA_VIDEO_COLOR_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * spa_video_color_range:
-+ * @SPA_VIDEO_COLOR_RANGE_UNKNOWN: unknown range
-+ * @SPA_VIDEO_COLOR_RANGE_0_255: [0..255] for 8 bit components
-+ * @SPA_VIDEO_COLOR_RANGE_16_235: [16..235] for 8 bit components. Chroma has
-+ * [16..240] range.
-+ *
-+ * Possible color range values. These constants are defined for 8 bit color
-+ * values and can be scaled for other bit depths.
-+ */
-+enum spa_video_color_range {
-+ SPA_VIDEO_COLOR_RANGE_UNKNOWN = 0,
-+ SPA_VIDEO_COLOR_RANGE_0_255,
-+ SPA_VIDEO_COLOR_RANGE_16_235
-+};
-+
-+/**
-+ * spa_video_color_matrix:
-+ * @SPA_VIDEO_COLOR_MATRIX_UNKNOWN: unknown matrix
-+ * @SPA_VIDEO_COLOR_MATRIX_RGB: identity matrix
-+ * @SPA_VIDEO_COLOR_MATRIX_FCC: FCC color matrix
-+ * @SPA_VIDEO_COLOR_MATRIX_BT709: ITU-R BT.709 color matrix
-+ * @SPA_VIDEO_COLOR_MATRIX_BT601: ITU-R BT.601 color matrix
-+ * @SPA_VIDEO_COLOR_MATRIX_SMPTE240M: SMPTE 240M color matrix
-+ * @SPA_VIDEO_COLOR_MATRIX_BT2020: ITU-R BT.2020 color matrix. Since: 1.6.
-+ *
-+ * The color matrix is used to convert between Y'PbPr and
-+ * non-linear RGB (R'G'B')
-+ */
-+enum spa_video_color_matrix {
-+ SPA_VIDEO_COLOR_MATRIX_UNKNOWN = 0,
-+ SPA_VIDEO_COLOR_MATRIX_RGB,
-+ SPA_VIDEO_COLOR_MATRIX_FCC,
-+ SPA_VIDEO_COLOR_MATRIX_BT709,
-+ SPA_VIDEO_COLOR_MATRIX_BT601,
-+ SPA_VIDEO_COLOR_MATRIX_SMPTE240M,
-+ SPA_VIDEO_COLOR_MATRIX_BT2020
-+};
-+
-+/**
-+ * spa_video_transfer_function:
-+ * @SPA_VIDEO_TRANSFER_UNKNOWN: unknown transfer function
-+ * @SPA_VIDEO_TRANSFER_GAMMA10: linear RGB, gamma 1.0 curve
-+ * @SPA_VIDEO_TRANSFER_GAMMA18: Gamma 1.8 curve
-+ * @SPA_VIDEO_TRANSFER_GAMMA20: Gamma 2.0 curve
-+ * @SPA_VIDEO_TRANSFER_GAMMA22: Gamma 2.2 curve
-+ * @SPA_VIDEO_TRANSFER_BT709: Gamma 2.2 curve with a linear segment in the lower
-+ * range
-+ * @SPA_VIDEO_TRANSFER_SMPTE240M: Gamma 2.2 curve with a linear segment in the
-+ * lower range
-+ * @SPA_VIDEO_TRANSFER_SRGB: Gamma 2.4 curve with a linear segment in the lower
-+ * range
-+ * @SPA_VIDEO_TRANSFER_GAMMA28: Gamma 2.8 curve
-+ * @SPA_VIDEO_TRANSFER_LOG100: Logarithmic transfer characteristic
-+ * 100:1 range
-+ * @SPA_VIDEO_TRANSFER_LOG316: Logarithmic transfer characteristic
-+ * 316.22777:1 range
-+ * @SPA_VIDEO_TRANSFER_BT2020_12: Gamma 2.2 curve with a linear segment in the lower
-+ * range. Used for BT.2020 with 12 bits per
-+ * component. Since: 1.6.
-+ * @SPA_VIDEO_TRANSFER_ADOBERGB: Gamma 2.19921875. Since: 1.8
-+ *
-+ * The video transfer function defines the formula for converting between
-+ * non-linear RGB (R'G'B') and linear RGB
-+ */
-+enum spa_video_transfer_function {
-+ SPA_VIDEO_TRANSFER_UNKNOWN = 0,
-+ SPA_VIDEO_TRANSFER_GAMMA10,
-+ SPA_VIDEO_TRANSFER_GAMMA18,
-+ SPA_VIDEO_TRANSFER_GAMMA20,
-+ SPA_VIDEO_TRANSFER_GAMMA22,
-+ SPA_VIDEO_TRANSFER_BT709,
-+ SPA_VIDEO_TRANSFER_SMPTE240M,
-+ SPA_VIDEO_TRANSFER_SRGB,
-+ SPA_VIDEO_TRANSFER_GAMMA28,
-+ SPA_VIDEO_TRANSFER_LOG100,
-+ SPA_VIDEO_TRANSFER_LOG316,
-+ SPA_VIDEO_TRANSFER_BT2020_12,
-+ SPA_VIDEO_TRANSFER_ADOBERGB
-+};
-+
-+/**
-+ * spa_video_color_primaries:
-+ * @SPA_VIDEO_COLOR_PRIMARIES_UNKNOWN: unknown color primaries
-+ * @SPA_VIDEO_COLOR_PRIMARIES_BT709: BT709 primaries
-+ * @SPA_VIDEO_COLOR_PRIMARIES_BT470M: BT470M primaries
-+ * @SPA_VIDEO_COLOR_PRIMARIES_BT470BG: BT470BG primaries
-+ * @SPA_VIDEO_COLOR_PRIMARIES_SMPTE170M: SMPTE170M primaries
-+ * @SPA_VIDEO_COLOR_PRIMARIES_SMPTE240M: SMPTE240M primaries
-+ * @SPA_VIDEO_COLOR_PRIMARIES_FILM: Generic film
-+ * @SPA_VIDEO_COLOR_PRIMARIES_BT2020: BT2020 primaries. Since: 1.6.
-+ * @SPA_VIDEO_COLOR_PRIMARIES_ADOBERGB: Adobe RGB primaries. Since: 1.8
-+ *
-+ * The color primaries define the how to transform linear RGB values to and from
-+ * the CIE XYZ colorspace.
-+ */
-+enum spa_video_color_primaries {
-+ SPA_VIDEO_COLOR_PRIMARIES_UNKNOWN = 0,
-+ SPA_VIDEO_COLOR_PRIMARIES_BT709,
-+ SPA_VIDEO_COLOR_PRIMARIES_BT470M,
-+ SPA_VIDEO_COLOR_PRIMARIES_BT470BG,
-+ SPA_VIDEO_COLOR_PRIMARIES_SMPTE170M,
-+ SPA_VIDEO_COLOR_PRIMARIES_SMPTE240M,
-+ SPA_VIDEO_COLOR_PRIMARIES_FILM,
-+ SPA_VIDEO_COLOR_PRIMARIES_BT2020,
-+ SPA_VIDEO_COLOR_PRIMARIES_ADOBERGB
-+};
-+
-+/**
-+ * spa_video_colorimetry:
-+ * @range: the color range. This is the valid range for the samples.
-+ * It is used to convert the samples to Y'PbPr values.
-+ * @matrix: the color matrix. Used to convert between Y'PbPr and
-+ * non-linear RGB (R'G'B')
-+ * @transfer: the transfer function. used to convert between R'G'B' and RGB
-+ * @primaries: color primaries. used to convert between R'G'B' and CIE XYZ
-+ *
-+ * Structure describing the color info.
-+ */
-+struct spa_video_colorimetry {
-+ enum spa_video_color_range range;
-+ enum spa_video_color_matrix matrix;
-+ enum spa_video_transfer_function transfer;
-+ enum spa_video_color_primaries primaries;
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_VIDEO_COLOR_H */
-diff --git a/third_party/pipewire/spa/param/video/encoded.h b/third_party/pipewire/spa/param/video/encoded.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/encoded.h
-@@ -0,0 +1,65 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_VIDEO_ENCODED_H
-+#define SPA_VIDEO_ENCODED_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/format.h>
-+
-+enum spa_h264_stream_format {
-+ SPA_H264_STREAM_FORMAT_UNKNOWN = 0,
-+ SPA_H264_STREAM_FORMAT_AVC,
-+ SPA_H264_STREAM_FORMAT_AVC3,
-+ SPA_H264_STREAM_FORMAT_BYTESTREAM
-+};
-+
-+enum spa_h264_alignment {
-+ SPA_H264_ALIGNMENT_UNKNOWN = 0,
-+ SPA_H264_ALIGNMENT_AU,
-+ SPA_H264_ALIGNMENT_NAL
-+};
-+
-+struct spa_video_info_h264 {
-+ struct spa_rectangle size;
-+ struct spa_fraction framerate;
-+ struct spa_fraction max_framerate;
-+ enum spa_h264_stream_format stream_format;
-+ enum spa_h264_alignment alignment;
-+};
-+
-+struct spa_video_info_mjpg {
-+ struct spa_rectangle size;
-+ struct spa_fraction framerate;
-+ struct spa_fraction max_framerate;
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_VIDEO_ENCODED_H */
-diff --git a/third_party/pipewire/spa/param/video/format-utils.h b/third_party/pipewire/spa/param/video/format-utils.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/format-utils.h
-@@ -0,0 +1,167 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_VIDEO_FORMAT_UTILS_H
-+#define SPA_PARAM_VIDEO_FORMAT_UTILS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/parser.h>
-+#include <spa/pod/builder.h>
-+#include <spa/param/video/format.h>
-+#include <spa/param/format-utils.h>
-+
-+static inline int
-+spa_format_video_raw_parse(const struct spa_pod *format,
-+ struct spa_video_info_raw *info)
-+{
-+ return spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_VIDEO_format, SPA_POD_Id(&info->format),
-+ SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier),
-+ SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size),
-+ SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate),
-+ SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate),
-+ SPA_FORMAT_VIDEO_views, SPA_POD_OPT_Int(&info->views),
-+ SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_OPT_Id(&info->interlace_mode),
-+ SPA_FORMAT_VIDEO_pixelAspectRatio, SPA_POD_OPT_Fraction(&info->pixel_aspect_ratio),
-+ SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_OPT_Id(&info->multiview_mode),
-+ SPA_FORMAT_VIDEO_multiviewFlags, SPA_POD_OPT_Id(&info->multiview_flags),
-+ SPA_FORMAT_VIDEO_chromaSite, SPA_POD_OPT_Id(&info->chroma_site),
-+ SPA_FORMAT_VIDEO_colorRange, SPA_POD_OPT_Id(&info->color_range),
-+ SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_OPT_Id(&info->color_matrix),
-+ SPA_FORMAT_VIDEO_transferFunction, SPA_POD_OPT_Id(&info->transfer_function),
-+ SPA_FORMAT_VIDEO_colorPrimaries, SPA_POD_OPT_Id(&info->color_primaries));
-+}
-+
-+static inline int
-+spa_format_video_dsp_parse(const struct spa_pod *format,
-+ struct spa_video_info_dsp *info)
-+{
-+ return spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_VIDEO_format, SPA_POD_Id(&info->format),
-+ SPA_FORMAT_VIDEO_modifier, SPA_POD_OPT_Long(&info->modifier));
-+}
-+
-+static inline struct spa_pod *
-+spa_format_video_raw_build(struct spa_pod_builder *builder, uint32_t id,
-+ struct spa_video_info_raw *info)
-+{
-+ struct spa_pod_frame f;
-+ spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
-+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
-+ SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format),
-+ SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&info->size),
-+ SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&info->framerate),
-+ 0);
-+ if (info->modifier != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0);
-+ if (info->max_framerate.denom != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_Fraction(info->max_framerate), 0);
-+ if (info->views != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_views, SPA_POD_Int(info->views), 0);
-+ if (info->interlace_mode != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_interlaceMode, SPA_POD_Id(info->interlace_mode), 0);
-+ if (info->pixel_aspect_ratio.denom != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_pixelAspectRatio,SPA_POD_Fraction(info->pixel_aspect_ratio), 0);
-+ if (info->multiview_mode != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_multiviewMode, SPA_POD_Id(info->multiview_mode), 0);
-+ if (info->multiview_flags != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_multiviewFlags,SPA_POD_Id(info->multiview_flags), 0);
-+ if (info->chroma_site != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_chromaSite, SPA_POD_Id(info->chroma_site), 0);
-+ if (info->color_range != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_colorRange, SPA_POD_Id(info->color_range), 0);
-+ if (info->color_matrix != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_colorMatrix, SPA_POD_Id(info->color_matrix), 0);
-+ if (info->transfer_function != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_transferFunction,SPA_POD_Id(info->transfer_function), 0);
-+ if (info->color_primaries != 0)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_colorPrimaries,SPA_POD_Id(info->color_primaries), 0);
-+ return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
-+}
-+
-+static inline struct spa_pod *
-+spa_format_video_dsp_build(struct spa_pod_builder *builder, uint32_t id,
-+ struct spa_video_info_dsp *info)
-+{
-+ struct spa_pod_frame f;
-+ spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
-+ SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp),
-+ SPA_FORMAT_VIDEO_format, SPA_POD_Id(info->format),
-+ 0);
-+ if (info->modifier)
-+ spa_pod_builder_add(builder,
-+ SPA_FORMAT_VIDEO_modifier, SPA_POD_Long(info->modifier), 0);
-+ return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
-+}
-+
-+static inline int
-+spa_format_video_h264_parse(const struct spa_pod *format,
-+ struct spa_video_info_h264 *info)
-+{
-+ return spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size),
-+ SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate),
-+ SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate),
-+ SPA_FORMAT_VIDEO_H264_streamFormat, SPA_POD_OPT_Id(&info->stream_format),
-+ SPA_FORMAT_VIDEO_H264_alignment, SPA_POD_OPT_Id(&info->alignment));
-+}
-+
-+static inline int
-+spa_format_video_mjpg_parse(const struct spa_pod *format,
-+ struct spa_video_info_mjpg *info)
-+{
-+ return spa_pod_parse_object(format,
-+ SPA_TYPE_OBJECT_Format, NULL,
-+ SPA_FORMAT_VIDEO_size, SPA_POD_OPT_Rectangle(&info->size),
-+ SPA_FORMAT_VIDEO_framerate, SPA_POD_OPT_Fraction(&info->framerate),
-+ SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_OPT_Fraction(&info->max_framerate));
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_VIDEO_FORMAT_UTILS_H */
-diff --git a/third_party/pipewire/spa/param/video/format.h b/third_party/pipewire/spa/param/video/format.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/format.h
-@@ -0,0 +1,50 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PARAM_VIDEO_FORMAT_H
-+#define SPA_PARAM_VIDEO_FORMAT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/video/raw.h>
-+#include <spa/param/video/encoded.h>
-+
-+struct spa_video_info {
-+ uint32_t media_type;
-+ uint32_t media_subtype;
-+ union {
-+ struct spa_video_info_raw raw;
-+ struct spa_video_info_dsp dsp;
-+ struct spa_video_info_h264 h264;
-+ struct spa_video_info_mjpg mjpg;
-+ } info;
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PARAM_VIDEO_FORMAT_H */
-diff --git a/third_party/pipewire/spa/param/video/multiview.h b/third_party/pipewire/spa/param/video/multiview.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/multiview.h
-@@ -0,0 +1,140 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_VIDEO_MULTIVIEW_H
-+#define SPA_VIDEO_MULTIVIEW_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * spa_video_multiview_mode:
-+ * @SPA_VIDEO_MULTIVIEW_MODE_NONE: A special value indicating
-+ * no multiview information. Used in spa_video_info and other places to
-+ * indicate that no specific multiview handling has been requested or
-+ * provided. This value is never carried on caps.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_MONO: All frames are monoscopic.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_LEFT: All frames represent a left-eye view.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_RIGHT: All frames represent a right-eye view.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE: Left and right eye views are
-+ * provided in the left and right half of the frame respectively.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX: Left and right eye
-+ * views are provided in the left and right half of the frame, but
-+ * have been sampled using quincunx method, with half-pixel offset
-+ * between the 2 views.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED: Alternating vertical
-+ * columns of pixels represent the left and right eye view respectively.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED: Alternating horizontal
-+ * rows of pixels represent the left and right eye view respectively.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM: The top half of the frame
-+ * contains the left eye, and the bottom half the right eye.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_CHECKERBOARD: Pixels are arranged with
-+ * alternating pixels representing left and right eye views in a
-+ * checkerboard fashion.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME: Left and right eye views
-+ * are provided in separate frames alternately.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME: Multiple
-+ * independent views are provided in separate frames in sequence.
-+ * This method only applies to raw video buffers at the moment.
-+ * Specific view identification is via the #spa_video_multiview_meta
-+ * on raw video buffers.
-+ * @SPA_VIDEO_MULTIVIEW_MODE_SEPARATED: Multiple views are
-+ * provided as separate #spa_data framebuffers attached to each
-+ * #spa_buffer, described by the #spa_video_multiview_meta
-+ *
-+ * All possible stereoscopic 3D and multiview representations.
-+ * In conjunction with #soa_video_multiview_flags, describes how
-+ * multiview content is being transported in the stream.
-+ */
-+enum spa_video_multiview_mode {
-+ SPA_VIDEO_MULTIVIEW_MODE_NONE = -1,
-+ SPA_VIDEO_MULTIVIEW_MODE_MONO = 0,
-+ /* Single view modes */
-+ SPA_VIDEO_MULTIVIEW_MODE_LEFT,
-+ SPA_VIDEO_MULTIVIEW_MODE_RIGHT,
-+ /* Stereo view modes */
-+ SPA_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE,
-+ SPA_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX,
-+ SPA_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED,
-+ SPA_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED,
-+ SPA_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM,
-+ SPA_VIDEO_MULTIVIEW_MODE_CHECKERBOARD,
-+ /* Padding for new frame packing modes */
-+
-+ SPA_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME = 32,
-+ /* Multivew mode(s) */
-+ SPA_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME,
-+ SPA_VIDEO_MULTIVIEW_MODE_SEPARATED
-+ /* future expansion for annotated modes */
-+};
-+
-+/**
-+ * spa_video_multiview_flags:
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_NONE: No flags
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST: For stereo streams, the
-+ * normal arrangement of left and right views is reversed.
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED: The left view is vertically
-+ * mirrored.
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED: The left view is horizontally
-+ * mirrored.
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED: The right view is
-+ * vertically mirrored.
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED: The right view is
-+ * horizontally mirrored.
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT: For frame-packed
-+ * multiview modes, indicates that the individual
-+ * views have been encoded with half the true width or height
-+ * and should be scaled back up for display. This flag
-+ * is used for overriding input layout interpretation
-+ * by adjusting pixel-aspect-ratio.
-+ * For side-by-side, column interleaved or checkerboard packings, the
-+ * pixel width will be doubled. For row interleaved and top-bottom
-+ * encodings, pixel height will be doubled.
-+ * @SPA_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO: The video stream contains both
-+ * mono and multiview portions, signalled on each buffer by the
-+ * absence or presence of the @SPA_VIDEO_BUFFER_FLAG_MULTIPLE_VIEW
-+ * buffer flag.
-+ *
-+ * spa_video_multiview_flags are used to indicate extra properties of a
-+ * stereo/multiview stream beyond the frame layout and buffer mapping
-+ * that is conveyed in the #spa_video_multiview_mode.
-+ */
-+enum spa_video_multiview_flags {
-+ SPA_VIDEO_MULTIVIEW_FLAGS_NONE = 0,
-+ SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST = (1 << 0),
-+ SPA_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED = (1 << 1),
-+ SPA_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED = (1 << 2),
-+ SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED = (1 << 3),
-+ SPA_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED = (1 << 4),
-+ SPA_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT = (1 << 14),
-+ SPA_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO = (1 << 15)
-+};
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_VIDEO_MULTIVIEW_H */
-diff --git a/third_party/pipewire/spa/param/video/raw.h b/third_party/pipewire/spa/param/video/raw.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/raw.h
-@@ -0,0 +1,221 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_VIDEO_RAW_H
-+#define SPA_VIDEO_RAW_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/param/video/chroma.h>
-+#include <spa/param/video/color.h>
-+#include <spa/param/video/multiview.h>
-+
-+#define SPA_VIDEO_MAX_PLANES 4
-+#define SPA_VIDEO_MAX_COMPONENTS 4
-+
-+enum spa_video_format {
-+ SPA_VIDEO_FORMAT_UNKNOWN,
-+ SPA_VIDEO_FORMAT_ENCODED,
-+
-+ SPA_VIDEO_FORMAT_I420,
-+ SPA_VIDEO_FORMAT_YV12,
-+ SPA_VIDEO_FORMAT_YUY2,
-+ SPA_VIDEO_FORMAT_UYVY,
-+ SPA_VIDEO_FORMAT_AYUV,
-+ SPA_VIDEO_FORMAT_RGBx,
-+ SPA_VIDEO_FORMAT_BGRx,
-+ SPA_VIDEO_FORMAT_xRGB,
-+ SPA_VIDEO_FORMAT_xBGR,
-+ SPA_VIDEO_FORMAT_RGBA,
-+ SPA_VIDEO_FORMAT_BGRA,
-+ SPA_VIDEO_FORMAT_ARGB,
-+ SPA_VIDEO_FORMAT_ABGR,
-+ SPA_VIDEO_FORMAT_RGB,
-+ SPA_VIDEO_FORMAT_BGR,
-+ SPA_VIDEO_FORMAT_Y41B,
-+ SPA_VIDEO_FORMAT_Y42B,
-+ SPA_VIDEO_FORMAT_YVYU,
-+ SPA_VIDEO_FORMAT_Y444,
-+ SPA_VIDEO_FORMAT_v210,
-+ SPA_VIDEO_FORMAT_v216,
-+ SPA_VIDEO_FORMAT_NV12,
-+ SPA_VIDEO_FORMAT_NV21,
-+ SPA_VIDEO_FORMAT_GRAY8,
-+ SPA_VIDEO_FORMAT_GRAY16_BE,
-+ SPA_VIDEO_FORMAT_GRAY16_LE,
-+ SPA_VIDEO_FORMAT_v308,
-+ SPA_VIDEO_FORMAT_RGB16,
-+ SPA_VIDEO_FORMAT_BGR16,
-+ SPA_VIDEO_FORMAT_RGB15,
-+ SPA_VIDEO_FORMAT_BGR15,
-+ SPA_VIDEO_FORMAT_UYVP,
-+ SPA_VIDEO_FORMAT_A420,
-+ SPA_VIDEO_FORMAT_RGB8P,
-+ SPA_VIDEO_FORMAT_YUV9,
-+ SPA_VIDEO_FORMAT_YVU9,
-+ SPA_VIDEO_FORMAT_IYU1,
-+ SPA_VIDEO_FORMAT_ARGB64,
-+ SPA_VIDEO_FORMAT_AYUV64,
-+ SPA_VIDEO_FORMAT_r210,
-+ SPA_VIDEO_FORMAT_I420_10BE,
-+ SPA_VIDEO_FORMAT_I420_10LE,
-+ SPA_VIDEO_FORMAT_I422_10BE,
-+ SPA_VIDEO_FORMAT_I422_10LE,
-+ SPA_VIDEO_FORMAT_Y444_10BE,
-+ SPA_VIDEO_FORMAT_Y444_10LE,
-+ SPA_VIDEO_FORMAT_GBR,
-+ SPA_VIDEO_FORMAT_GBR_10BE,
-+ SPA_VIDEO_FORMAT_GBR_10LE,
-+ SPA_VIDEO_FORMAT_NV16,
-+ SPA_VIDEO_FORMAT_NV24,
-+ SPA_VIDEO_FORMAT_NV12_64Z32,
-+ SPA_VIDEO_FORMAT_A420_10BE,
-+ SPA_VIDEO_FORMAT_A420_10LE,
-+ SPA_VIDEO_FORMAT_A422_10BE,
-+ SPA_VIDEO_FORMAT_A422_10LE,
-+ SPA_VIDEO_FORMAT_A444_10BE,
-+ SPA_VIDEO_FORMAT_A444_10LE,
-+ SPA_VIDEO_FORMAT_NV61,
-+ SPA_VIDEO_FORMAT_P010_10BE,
-+ SPA_VIDEO_FORMAT_P010_10LE,
-+ SPA_VIDEO_FORMAT_IYU2,
-+ SPA_VIDEO_FORMAT_VYUY,
-+ SPA_VIDEO_FORMAT_GBRA,
-+ SPA_VIDEO_FORMAT_GBRA_10BE,
-+ SPA_VIDEO_FORMAT_GBRA_10LE,
-+ SPA_VIDEO_FORMAT_GBR_12BE,
-+ SPA_VIDEO_FORMAT_GBR_12LE,
-+ SPA_VIDEO_FORMAT_GBRA_12BE,
-+ SPA_VIDEO_FORMAT_GBRA_12LE,
-+ SPA_VIDEO_FORMAT_I420_12BE,
-+ SPA_VIDEO_FORMAT_I420_12LE,
-+ SPA_VIDEO_FORMAT_I422_12BE,
-+ SPA_VIDEO_FORMAT_I422_12LE,
-+ SPA_VIDEO_FORMAT_Y444_12BE,
-+ SPA_VIDEO_FORMAT_Y444_12LE,
-+
-+ SPA_VIDEO_FORMAT_RGBA_F16,
-+ SPA_VIDEO_FORMAT_RGBA_F32,
-+
-+ /* Aliases */
-+ SPA_VIDEO_FORMAT_DSP_F32 = SPA_VIDEO_FORMAT_RGBA_F32,
-+};
-+
-+/**
-+ * spa_video_flags:
-+ * @SPA_VIDEO_FLAG_NONE: no flags
-+ * @SPA_VIDEO_FLAG_VARIABLE_FPS: a variable fps is selected, fps_n and fps_d
-+ * denote the maximum fps of the video
-+ * @SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA: Each color has been scaled by the alpha
-+ * value.
-+ *
-+ * Extra video flags
-+ */
-+enum spa_video_flags {
-+ SPA_VIDEO_FLAG_NONE = 0,
-+ SPA_VIDEO_FLAG_VARIABLE_FPS = (1 << 0),
-+ SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA = (1 << 1)
-+};
-+
-+/**
-+ * spa_video_interlace_mode:
-+ * @SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE: all frames are progressive
-+ * @SPA_VIDEO_INTERLACE_MODE_INTERLEAVED: 2 fields are interleaved in one video
-+ * frame. Extra buffer flags describe the field order.
-+ * @SPA_VIDEO_INTERLACE_MODE_MIXED: frames contains both interlaced and
-+ * progressive video, the buffer flags describe the frame and fields.
-+ * @SPA_VIDEO_INTERLACE_MODE_FIELDS: 2 fields are stored in one buffer, use the
-+ * frame ID to get access to the required field. For multiview (the
-+ * 'views' property > 1) the fields of view N can be found at frame ID
-+ * (N * 2) and (N * 2) + 1.
-+ * Each field has only half the amount of lines as noted in the
-+ * height property. This mode requires multiple spa_data
-+ * to describe the fields.
-+ *
-+ * The possible values of the #spa_video_interlace_mode describing the interlace
-+ * mode of the stream.
-+ */
-+enum spa_video_interlace_mode {
-+ SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE = 0,
-+ SPA_VIDEO_INTERLACE_MODE_INTERLEAVED,
-+ SPA_VIDEO_INTERLACE_MODE_MIXED,
-+ SPA_VIDEO_INTERLACE_MODE_FIELDS
-+};
-+
-+/**
-+ * spa_video_info_raw:
-+ * @format: the format
-+ * @modifier: format modifier
-+ * @size: the frame size of the video
-+ * @framerate: the framerate of the video 0/1 means variable rate
-+ * @max_framerate: the maximum framerate of the video. This is only valid when
-+ * @framerate is 0/1
-+ * @views: the number of views in this video
-+ * @interlace_mode: the interlace mode
-+ * @pixel_aspect_ratio: The pixel aspect ratio
-+ * @multiview_mode: multiview mode
-+ * @multiview_flags: multiview flags
-+ * @chroma_site: the chroma siting
-+ * @color_range: the color range. This is the valid range for the samples.
-+ * It is used to convert the samples to Y'PbPr values.
-+ * @color_matrix: the color matrix. Used to convert between Y'PbPr and
-+ * non-linear RGB (R'G'B')
-+ * @transfer_function: the transfer function. used to convert between R'G'B' and RGB
-+ * @color_primaries: color primaries. used to convert between R'G'B' and CIE XYZ
-+ */
-+struct spa_video_info_raw {
-+ enum spa_video_format format;
-+ int64_t modifier;
-+ struct spa_rectangle size;
-+ struct spa_fraction framerate;
-+ struct spa_fraction max_framerate;
-+ uint32_t views;
-+ enum spa_video_interlace_mode interlace_mode;
-+ struct spa_fraction pixel_aspect_ratio;
-+ enum spa_video_multiview_mode multiview_mode;
-+ enum spa_video_multiview_flags multiview_flags;
-+ enum spa_video_chroma_site chroma_site;
-+ enum spa_video_color_range color_range;
-+ enum spa_video_color_matrix color_matrix;
-+ enum spa_video_transfer_function transfer_function;
-+ enum spa_video_color_primaries color_primaries;
-+};
-+
-+#define SPA_VIDEO_INFO_RAW_INIT(...) (struct spa_video_info_raw) { __VA_ARGS__ }
-+
-+struct spa_video_info_dsp {
-+ enum spa_video_format format;
-+ int64_t modifier;
-+};
-+
-+#define SPA_VIDEO_INFO_DSP_INIT(...) (struct spa_video_info_dsp) { __VA_ARGS__ }
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_VIDEO_RAW_H */
-diff --git a/third_party/pipewire/spa/param/video/type-info.h b/third_party/pipewire/spa/param/video/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/param/video/type-info.h
-@@ -0,0 +1,124 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_VIDEO_TYPES_H
-+#define SPA_VIDEO_TYPES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/param/video/raw.h>
-+
-+#define SPA_TYPE_INFO_VideoFormat SPA_TYPE_INFO_ENUM_BASE "VideoFormat"
-+#define SPA_TYPE_INFO_VIDEO_FORMAT_BASE SPA_TYPE_INFO_VideoFormat ":"
-+
-+static const struct spa_type_info spa_type_video_format[] = {
-+ { SPA_VIDEO_FORMAT_ENCODED, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "encoded", NULL },
-+ { SPA_VIDEO_FORMAT_I420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420", NULL },
-+ { SPA_VIDEO_FORMAT_YV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YV12", NULL },
-+ { SPA_VIDEO_FORMAT_YUY2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUY2", NULL },
-+ { SPA_VIDEO_FORMAT_UYVY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVY", NULL },
-+ { SPA_VIDEO_FORMAT_AYUV, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV", NULL },
-+ { SPA_VIDEO_FORMAT_RGBx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBx", NULL },
-+ { SPA_VIDEO_FORMAT_BGRx, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRx", NULL },
-+ { SPA_VIDEO_FORMAT_xRGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xRGB", NULL },
-+ { SPA_VIDEO_FORMAT_xBGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "xBGR", NULL },
-+ { SPA_VIDEO_FORMAT_RGBA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA", NULL },
-+ { SPA_VIDEO_FORMAT_BGRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGRA", NULL },
-+ { SPA_VIDEO_FORMAT_ARGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB", NULL },
-+ { SPA_VIDEO_FORMAT_ABGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ABGR", NULL },
-+ { SPA_VIDEO_FORMAT_RGB, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB", NULL },
-+ { SPA_VIDEO_FORMAT_BGR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR", NULL },
-+ { SPA_VIDEO_FORMAT_Y41B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y41B", NULL },
-+ { SPA_VIDEO_FORMAT_Y42B, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y42B", NULL },
-+ { SPA_VIDEO_FORMAT_YVYU, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVYU", NULL },
-+ { SPA_VIDEO_FORMAT_Y444, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444", NULL },
-+ { SPA_VIDEO_FORMAT_v210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v210", NULL },
-+ { SPA_VIDEO_FORMAT_v216, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v216", NULL },
-+ { SPA_VIDEO_FORMAT_NV12, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12", NULL },
-+ { SPA_VIDEO_FORMAT_NV21, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV21", NULL },
-+ { SPA_VIDEO_FORMAT_GRAY8, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY8", NULL },
-+ { SPA_VIDEO_FORMAT_GRAY16_BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_BE", NULL },
-+ { SPA_VIDEO_FORMAT_GRAY16_LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GRAY16_LE", NULL },
-+ { SPA_VIDEO_FORMAT_v308, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "v308", NULL },
-+ { SPA_VIDEO_FORMAT_RGB16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB16", NULL },
-+ { SPA_VIDEO_FORMAT_BGR16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR16", NULL },
-+ { SPA_VIDEO_FORMAT_RGB15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB15", NULL },
-+ { SPA_VIDEO_FORMAT_BGR15, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "BGR15", NULL },
-+ { SPA_VIDEO_FORMAT_UYVP, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "UYVP", NULL },
-+ { SPA_VIDEO_FORMAT_A420, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420", NULL },
-+ { SPA_VIDEO_FORMAT_RGB8P, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGB8P", NULL },
-+ { SPA_VIDEO_FORMAT_YUV9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YUV9", NULL },
-+ { SPA_VIDEO_FORMAT_YVU9, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "YVU9", NULL },
-+ { SPA_VIDEO_FORMAT_IYU1, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU1", NULL },
-+ { SPA_VIDEO_FORMAT_ARGB64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "ARGB64", NULL },
-+ { SPA_VIDEO_FORMAT_AYUV64, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "AYUV64", NULL },
-+ { SPA_VIDEO_FORMAT_r210, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "r210", NULL },
-+ { SPA_VIDEO_FORMAT_I420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_I420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_I422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_I422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_Y444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_Y444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_GBR, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR", NULL },
-+ { SPA_VIDEO_FORMAT_GBR_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_GBR_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_NV16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV16", NULL },
-+ { SPA_VIDEO_FORMAT_NV24, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV24", NULL },
-+ { SPA_VIDEO_FORMAT_NV12_64Z32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV12_64Z32", NULL },
-+ { SPA_VIDEO_FORMAT_A420_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_A420_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A420_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_A422_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_A422_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A422_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_A444_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_A444_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "A444_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_NV61, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "NV61", NULL },
-+ { SPA_VIDEO_FORMAT_P010_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_P010_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "P010_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_IYU2, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "IYU2", NULL },
-+ { SPA_VIDEO_FORMAT_VYUY, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "VYUY", NULL },
-+ { SPA_VIDEO_FORMAT_GBRA, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA", NULL },
-+ { SPA_VIDEO_FORMAT_GBRA_10BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10BE", NULL },
-+ { SPA_VIDEO_FORMAT_GBRA_10LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_10LE", NULL },
-+ { SPA_VIDEO_FORMAT_GBR_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12BE", NULL },
-+ { SPA_VIDEO_FORMAT_GBR_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBR_12LE", NULL },
-+ { SPA_VIDEO_FORMAT_GBRA_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12BE", NULL },
-+ { SPA_VIDEO_FORMAT_GBRA_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "GBRA_12LE", NULL },
-+ { SPA_VIDEO_FORMAT_I420_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12BE", NULL },
-+ { SPA_VIDEO_FORMAT_I420_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I420_12LE", NULL },
-+ { SPA_VIDEO_FORMAT_I422_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12BE", NULL },
-+ { SPA_VIDEO_FORMAT_I422_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "I422_12LE", NULL },
-+ { SPA_VIDEO_FORMAT_Y444_12BE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12BE", NULL },
-+ { SPA_VIDEO_FORMAT_Y444_12LE, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "Y444_12LE", NULL },
-+ { SPA_VIDEO_FORMAT_RGBA_F16, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F16", NULL },
-+ { SPA_VIDEO_FORMAT_RGBA_F32, SPA_TYPE_Int, SPA_TYPE_INFO_VIDEO_FORMAT_BASE "RGBA_F32", NULL },
-+ { 0, 0, NULL, NULL },
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_VIDEO_RAW_TYPES_H */
-diff --git a/third_party/pipewire/spa/pod/builder.h b/third_party/pipewire/spa/pod/builder.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/builder.h
-@@ -0,0 +1,671 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_POD_BUILDER_H
-+#define SPA_POD_BUILDER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+
-+#include <spa/utils/hook.h>
-+#include <spa/pod/iter.h>
-+#include <spa/pod/vararg.h>
-+
-+struct spa_pod_builder_state {
-+ uint32_t offset;
-+#define SPA_POD_BUILDER_FLAG_BODY (1<<0)
-+#define SPA_POD_BUILDER_FLAG_FIRST (1<<1)
-+ uint32_t flags;
-+ struct spa_pod_frame *frame;
-+};
-+
-+struct spa_pod_builder;
-+
-+struct spa_pod_builder_callbacks {
-+#define SPA_VERSION_POD_BUILDER_CALLBACKS 0
-+ uint32_t version;
-+
-+ int (*overflow) (void *data, uint32_t size);
-+};
-+
-+struct spa_pod_builder {
-+ void *data;
-+ uint32_t size;
-+ uint32_t _padding;
-+ struct spa_pod_builder_state state;
-+ struct spa_callbacks callbacks;
-+};
-+
-+#define SPA_POD_BUILDER_INIT(buffer,size) (struct spa_pod_builder){ buffer, size, }
-+
-+static inline void
-+spa_pod_builder_get_state(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
-+{
-+ *state = builder->state;
-+}
-+
-+static inline void
-+spa_pod_builder_set_callbacks(struct spa_pod_builder *builder,
-+ const struct spa_pod_builder_callbacks *callbacks, void *data)
-+{
-+ builder->callbacks = SPA_CALLBACKS_INIT(callbacks, data);
-+}
-+
-+static inline void
-+spa_pod_builder_reset(struct spa_pod_builder *builder, struct spa_pod_builder_state *state)
-+{
-+ struct spa_pod_frame *f;
-+ uint32_t size = builder->state.offset - state->offset;
-+ builder->state = *state;
-+ for (f = builder->state.frame; f ; f = f->parent)
-+ f->pod.size -= size;
-+}
-+
-+static inline void spa_pod_builder_init(struct spa_pod_builder *builder, void *data, uint32_t size)
-+{
-+ *builder = SPA_POD_BUILDER_INIT(data, size);
-+}
-+
-+static inline struct spa_pod *
-+spa_pod_builder_deref(struct spa_pod_builder *builder, uint32_t offset)
-+{
-+ uint32_t size = builder->size;
-+ if (offset + 8 <= size) {
-+ struct spa_pod *pod = SPA_MEMBER(builder->data, offset, struct spa_pod);
-+ if (offset + SPA_POD_SIZE(pod) <= size)
-+ return pod;
-+ }
-+ return NULL;
-+}
-+
-+static inline struct spa_pod *
-+spa_pod_builder_frame(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
-+{
-+ if (frame->offset + SPA_POD_SIZE(&frame->pod) <= builder->size)
-+ return SPA_MEMBER(builder->data, frame->offset, struct spa_pod);
-+ return NULL;
-+}
-+
-+static inline void
-+spa_pod_builder_push(struct spa_pod_builder *builder,
-+ struct spa_pod_frame *frame,
-+ const struct spa_pod *pod,
-+ uint32_t offset)
-+{
-+ frame->pod = *pod;
-+ frame->offset = offset;
-+ frame->parent = builder->state.frame;
-+ frame->flags = builder->state.flags;
-+ builder->state.frame = frame;
-+
-+ if (frame->pod.type == SPA_TYPE_Array || frame->pod.type == SPA_TYPE_Choice)
-+ builder->state.flags = SPA_POD_BUILDER_FLAG_FIRST | SPA_POD_BUILDER_FLAG_BODY;
-+}
-+
-+static inline int spa_pod_builder_raw(struct spa_pod_builder *builder, const void *data, uint32_t size)
-+{
-+ int res = 0;
-+ struct spa_pod_frame *f;
-+ uint32_t offset = builder->state.offset;
-+
-+ if (offset + size > builder->size) {
-+ res = -ENOSPC;
-+ spa_callbacks_call_res(&builder->callbacks, struct spa_pod_builder_callbacks, res,
-+ overflow, 0, offset + size);
-+ }
-+ if (res == 0 && data)
-+ memcpy(SPA_MEMBER(builder->data, offset, void), data, size);
-+
-+ builder->state.offset += size;
-+
-+ for (f = builder->state.frame; f ; f = f->parent)
-+ f->pod.size += size;
-+
-+ return res;
-+}
-+
-+static inline int spa_pod_builder_pad(struct spa_pod_builder *builder, uint32_t size)
-+{
-+ uint64_t zeroes = 0;
-+ size = SPA_ROUND_UP_N(size, 8) - size;
-+ return size ? spa_pod_builder_raw(builder, &zeroes, size) : 0;
-+}
-+
-+static inline int
-+spa_pod_builder_raw_padded(struct spa_pod_builder *builder, const void *data, uint32_t size)
-+{
-+ int r, res = spa_pod_builder_raw(builder, data, size);
-+ if ((r = spa_pod_builder_pad(builder, size)) < 0)
-+ res = r;
-+ return res;
-+}
-+
-+static inline void *spa_pod_builder_pop(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
-+{
-+ struct spa_pod *pod;
-+
-+ if ((pod = (struct spa_pod*)spa_pod_builder_frame(builder, frame)) != NULL)
-+ *pod = frame->pod;
-+
-+ builder->state.frame = frame->parent;
-+ builder->state.flags = frame->flags;
-+ spa_pod_builder_pad(builder, builder->state.offset);
-+ return pod;
-+}
-+
-+static inline int
-+spa_pod_builder_primitive(struct spa_pod_builder *builder, const struct spa_pod *p)
-+{
-+ const void *data;
-+ uint32_t size;
-+ int r, res;
-+
-+ if (builder->state.flags == SPA_POD_BUILDER_FLAG_BODY) {
-+ data = SPA_POD_BODY_CONST(p);
-+ size = SPA_POD_BODY_SIZE(p);
-+ } else {
-+ data = p;
-+ size = SPA_POD_SIZE(p);
-+ SPA_FLAG_CLEAR(builder->state.flags, SPA_POD_BUILDER_FLAG_FIRST);
-+ }
-+ res = spa_pod_builder_raw(builder, data, size);
-+ if (builder->state.flags != SPA_POD_BUILDER_FLAG_BODY)
-+ if ((r = spa_pod_builder_pad(builder, size)) < 0)
-+ res = r;
-+ return res;
-+}
-+
-+#define SPA_POD_INIT(size,type) (struct spa_pod) { size, type }
-+
-+#define SPA_POD_INIT_None() SPA_POD_INIT(0, SPA_TYPE_None)
-+
-+static inline int spa_pod_builder_none(struct spa_pod_builder *builder)
-+{
-+ const struct spa_pod p = SPA_POD_INIT_None();
-+ return spa_pod_builder_primitive(builder, &p);
-+}
-+
-+#define SPA_POD_INIT_Bool(val) (struct spa_pod_bool){ { sizeof(uint32_t), SPA_TYPE_Bool }, val ? 1 : 0, 0 }
-+
-+static inline int spa_pod_builder_bool(struct spa_pod_builder *builder, bool val)
-+{
-+ const struct spa_pod_bool p = SPA_POD_INIT_Bool(val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Id(val) (struct spa_pod_id){ { sizeof(uint32_t), SPA_TYPE_Id }, (uint32_t)val, 0 }
-+
-+static inline int spa_pod_builder_id(struct spa_pod_builder *builder, uint32_t val)
-+{
-+ const struct spa_pod_id p = SPA_POD_INIT_Id(val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Int(val) (struct spa_pod_int){ { sizeof(int32_t), SPA_TYPE_Int }, (int32_t)val, 0 }
-+
-+static inline int spa_pod_builder_int(struct spa_pod_builder *builder, int32_t val)
-+{
-+ const struct spa_pod_int p = SPA_POD_INIT_Int(val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Long(val) (struct spa_pod_long){ { sizeof(int64_t), SPA_TYPE_Long }, (int64_t)val }
-+
-+static inline int spa_pod_builder_long(struct spa_pod_builder *builder, int64_t val)
-+{
-+ const struct spa_pod_long p = SPA_POD_INIT_Long(val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Float(val) (struct spa_pod_float){ { sizeof(float), SPA_TYPE_Float }, val }
-+
-+static inline int spa_pod_builder_float(struct spa_pod_builder *builder, float val)
-+{
-+ const struct spa_pod_float p = SPA_POD_INIT_Float(val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Double(val) (struct spa_pod_double){ { sizeof(double), SPA_TYPE_Double }, val }
-+
-+static inline int spa_pod_builder_double(struct spa_pod_builder *builder, double val)
-+{
-+ const struct spa_pod_double p = SPA_POD_INIT_Double(val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_String(len) (struct spa_pod_string){ { len, SPA_TYPE_String } }
-+
-+static inline int
-+spa_pod_builder_write_string(struct spa_pod_builder *builder, const char *str, uint32_t len)
-+{
-+ int r, res;
-+ res = spa_pod_builder_raw(builder, str, len);
-+ if ((r = spa_pod_builder_raw(builder, "", 1)) < 0)
-+ res = r;
-+ if ((r = spa_pod_builder_pad(builder, builder->state.offset)) < 0)
-+ res = r;
-+ return res;
-+}
-+
-+static inline int
-+spa_pod_builder_string_len(struct spa_pod_builder *builder, const char *str, uint32_t len)
-+{
-+ const struct spa_pod_string p = SPA_POD_INIT_String(len+1);
-+ int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
-+ if ((r = spa_pod_builder_write_string(builder, str, len)) < 0)
-+ res = r;
-+ return res;
-+}
-+
-+static inline int spa_pod_builder_string(struct spa_pod_builder *builder, const char *str)
-+{
-+ uint32_t len = str ? strlen(str) : 0;
-+ return spa_pod_builder_string_len(builder, str ? str : "", len);
-+}
-+
-+#define SPA_POD_INIT_Bytes(len) (struct spa_pod_bytes){ { len, SPA_TYPE_Bytes } }
-+
-+static inline int
-+spa_pod_builder_bytes(struct spa_pod_builder *builder, const void *bytes, uint32_t len)
-+{
-+ const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(len);
-+ int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
-+ if ((r = spa_pod_builder_raw_padded(builder, bytes, len)) < 0)
-+ res = r;
-+ return res;
-+}
-+static inline void *
-+spa_pod_builder_reserve_bytes(struct spa_pod_builder *builder, uint32_t len)
-+{
-+ uint32_t offset = builder->state.offset;
-+ if (spa_pod_builder_bytes(builder, NULL, len) < 0)
-+ return NULL;
-+ return SPA_POD_BODY(spa_pod_builder_deref(builder, offset));
-+}
-+
-+#define SPA_POD_INIT_Pointer(type,value) (struct spa_pod_pointer){ { sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { type, 0, value } }
-+
-+static inline int
-+spa_pod_builder_pointer(struct spa_pod_builder *builder, uint32_t type, const void *val)
-+{
-+ const struct spa_pod_pointer p = SPA_POD_INIT_Pointer(type, val);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Fd(fd) (struct spa_pod_fd){ { sizeof(int64_t), SPA_TYPE_Fd }, fd }
-+
-+static inline int spa_pod_builder_fd(struct spa_pod_builder *builder, int64_t fd)
-+{
-+ const struct spa_pod_fd p = SPA_POD_INIT_Fd(fd);
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Rectangle(val) (struct spa_pod_rectangle){ { sizeof(struct spa_rectangle), SPA_TYPE_Rectangle }, val }
-+
-+static inline int
-+spa_pod_builder_rectangle(struct spa_pod_builder *builder, uint32_t width, uint32_t height)
-+{
-+ const struct spa_pod_rectangle p = SPA_POD_INIT_Rectangle(SPA_RECTANGLE(width, height));
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+#define SPA_POD_INIT_Fraction(val) (struct spa_pod_fraction){ { sizeof(struct spa_fraction), SPA_TYPE_Fraction }, val }
-+
-+static inline int
-+spa_pod_builder_fraction(struct spa_pod_builder *builder, uint32_t num, uint32_t denom)
-+{
-+ const struct spa_pod_fraction p = SPA_POD_INIT_Fraction(SPA_FRACTION(num, denom));
-+ return spa_pod_builder_primitive(builder, &p.pod);
-+}
-+
-+static inline int
-+spa_pod_builder_push_array(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
-+{
-+ const struct spa_pod_array p =
-+ { {sizeof(struct spa_pod_array_body) - sizeof(struct spa_pod), SPA_TYPE_Array},
-+ {{0, 0}} };
-+ uint32_t offset = builder->state.offset;
-+ int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
-+ spa_pod_builder_push(builder, frame, &p.pod, offset);
-+ return res;
-+}
-+
-+static inline int
-+spa_pod_builder_array(struct spa_pod_builder *builder,
-+ uint32_t child_size, uint32_t child_type, uint32_t n_elems, const void *elems)
-+{
-+ const struct spa_pod_array p = {
-+ {(uint32_t)(sizeof(struct spa_pod_array_body) + n_elems * child_size), SPA_TYPE_Array},
-+ {{child_size, child_type}}
-+ };
-+ int r, res = spa_pod_builder_raw(builder, &p, sizeof(p));
-+ if ((r = spa_pod_builder_raw_padded(builder, elems, child_size * n_elems)) < 0)
-+ res = r;
-+ return res;
-+}
-+
-+#define SPA_POD_INIT_CHOICE_BODY(type, flags, child_size, child_type) \
-+ (struct spa_pod_choice_body) { type, flags, { child_size, child_type }}
-+
-+#define SPA_POD_INIT_Choice(type, ctype, child_type, n_vals, ...) \
-+ (struct { struct spa_pod_choice choice; ctype vals[n_vals];}) \
-+ { { { n_vals * sizeof(ctype) + sizeof(struct spa_pod_choice_body), SPA_TYPE_Choice }, \
-+ { type, 0, { sizeof(ctype), child_type } } }, { __VA_ARGS__ } }
-+
-+static inline int
-+spa_pod_builder_push_choice(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
-+ uint32_t type, uint32_t flags)
-+{
-+ const struct spa_pod_choice p =
-+ { {sizeof(struct spa_pod_choice_body) - sizeof(struct spa_pod), SPA_TYPE_Choice},
-+ { type, flags, {0, 0}} };
-+ uint32_t offset = builder->state.offset;
-+ int res = spa_pod_builder_raw(builder, &p, sizeof(p) - sizeof(struct spa_pod));
-+ spa_pod_builder_push(builder, frame, &p.pod, offset);
-+ return res;
-+}
-+
-+#define SPA_POD_INIT_Struct(size) (struct spa_pod_struct){ { size, SPA_TYPE_Struct } }
-+
-+static inline int
-+spa_pod_builder_push_struct(struct spa_pod_builder *builder, struct spa_pod_frame *frame)
-+{
-+ const struct spa_pod_struct p = SPA_POD_INIT_Struct(0);
-+ uint32_t offset = builder->state.offset;
-+ int res = spa_pod_builder_raw(builder, &p, sizeof(p));
-+ spa_pod_builder_push(builder, frame, &p.pod, offset);
-+ return res;
-+}
-+
-+#define SPA_POD_INIT_Object(size,type,id,...) (struct spa_pod_object){ { size, SPA_TYPE_Object }, { type, id }, ##__VA_ARGS__ }
-+
-+static inline int
-+spa_pod_builder_push_object(struct spa_pod_builder *builder, struct spa_pod_frame *frame,
-+ uint32_t type, uint32_t id)
-+{
-+ const struct spa_pod_object p =
-+ SPA_POD_INIT_Object(sizeof(struct spa_pod_object_body), type, id);
-+ uint32_t offset = builder->state.offset;
-+ int res = spa_pod_builder_raw(builder, &p, sizeof(p));
-+ spa_pod_builder_push(builder, frame, &p.pod, offset);
-+ return res;
-+}
-+
-+#define SPA_POD_INIT_Prop(key,flags,size,type) \
-+ (struct spa_pod_prop){ key, flags, { size, type } }
-+
-+static inline int
-+spa_pod_builder_prop(struct spa_pod_builder *builder, uint32_t key, uint32_t flags)
-+{
-+ const struct { uint32_t key; uint32_t flags; } p = { key, flags };
-+ return spa_pod_builder_raw(builder, &p, sizeof(p));
-+}
-+
-+#define SPA_POD_INIT_Sequence(size,unit) \
-+ (struct spa_pod_sequence){ { size, SPA_TYPE_Sequence}, {unit, 0 } }
-+
-+static inline int
-+spa_pod_builder_push_sequence(struct spa_pod_builder *builder, struct spa_pod_frame *frame, uint32_t unit)
-+{
-+ const struct spa_pod_sequence p =
-+ SPA_POD_INIT_Sequence(sizeof(struct spa_pod_sequence_body), unit);
-+ uint32_t offset = builder->state.offset;
-+ int res = spa_pod_builder_raw(builder, &p, sizeof(p));
-+ spa_pod_builder_push(builder, frame, &p.pod, offset);
-+ return res;
-+}
-+
-+static inline uint32_t
-+spa_pod_builder_control(struct spa_pod_builder *builder, uint32_t offset, uint32_t type)
-+{
-+ const struct { uint32_t offset; uint32_t type; } p = { offset, type };
-+ return spa_pod_builder_raw(builder, &p, sizeof(p));
-+}
-+
-+static inline uint32_t spa_choice_from_id(char id)
-+{
-+ switch (id) {
-+ case 'r':
-+ return SPA_CHOICE_Range;
-+ case 's':
-+ return SPA_CHOICE_Step;
-+ case 'e':
-+ return SPA_CHOICE_Enum;
-+ case 'f':
-+ return SPA_CHOICE_Flags;
-+ case 'n':
-+ default:
-+ return SPA_CHOICE_None;
-+ }
-+}
-+
-+#define SPA_POD_BUILDER_COLLECT(builder,type,args) \
-+do { \
-+ switch (type) { \
-+ case 'b': \
-+ spa_pod_builder_bool(builder, !!va_arg(args, int)); \
-+ break; \
-+ case 'I': \
-+ spa_pod_builder_id(builder, va_arg(args, uint32_t)); \
-+ break; \
-+ case 'i': \
-+ spa_pod_builder_int(builder, va_arg(args, int)); \
-+ break; \
-+ case 'l': \
-+ spa_pod_builder_long(builder, va_arg(args, int64_t)); \
-+ break; \
-+ case 'f': \
-+ spa_pod_builder_float(builder, va_arg(args, double)); \
-+ break; \
-+ case 'd': \
-+ spa_pod_builder_double(builder, va_arg(args, double)); \
-+ break; \
-+ case 's': \
-+ { \
-+ char *strval = va_arg(args, char *); \
-+ if (strval != NULL) { \
-+ size_t len = strlen(strval); \
-+ spa_pod_builder_string_len(builder, strval, len); \
-+ } \
-+ else \
-+ spa_pod_builder_none(builder); \
-+ break; \
-+ } \
-+ case 'S': \
-+ { \
-+ char *strval = va_arg(args, char *); \
-+ size_t len = va_arg(args, int); \
-+ spa_pod_builder_string_len(builder, strval, len); \
-+ break; \
-+ } \
-+ case 'y': \
-+ { \
-+ void *ptr = va_arg(args, void *); \
-+ int len = va_arg(args, int); \
-+ spa_pod_builder_bytes(builder, ptr, len); \
-+ break; \
-+ } \
-+ case 'R': \
-+ { \
-+ struct spa_rectangle *rectval = \
-+ va_arg(args, struct spa_rectangle *); \
-+ spa_pod_builder_rectangle(builder, \
-+ rectval->width, rectval->height); \
-+ break; \
-+ } \
-+ case 'F': \
-+ { \
-+ struct spa_fraction *fracval = \
-+ va_arg(args, struct spa_fraction *); \
-+ spa_pod_builder_fraction(builder, fracval->num, fracval->denom);\
-+ break; \
-+ } \
-+ case 'a': \
-+ { \
-+ int child_size = va_arg(args, int); \
-+ int child_type = va_arg(args, int); \
-+ int n_elems = va_arg(args, int); \
-+ void *elems = va_arg(args, void *); \
-+ spa_pod_builder_array(builder, child_size, \
-+ child_type, n_elems, elems); \
-+ break; \
-+ } \
-+ case 'p': \
-+ { \
-+ int t = va_arg(args, uint32_t); \
-+ spa_pod_builder_pointer(builder, t, va_arg(args, void *)); \
-+ break; \
-+ } \
-+ case 'h': \
-+ spa_pod_builder_fd(builder, va_arg(args, int)); \
-+ break; \
-+ case 'P': \
-+ case 'O': \
-+ case 'T': \
-+ case 'V': \
-+ { \
-+ struct spa_pod *pod = va_arg(args, struct spa_pod *); \
-+ if (pod == NULL) \
-+ spa_pod_builder_none(builder); \
-+ else \
-+ spa_pod_builder_primitive(builder, pod); \
-+ break; \
-+ } \
-+ } \
-+} while(false)
-+
-+static inline int
-+spa_pod_builder_addv(struct spa_pod_builder *builder, va_list args)
-+{
-+ int res = 0;
-+ struct spa_pod_frame *f = builder->state.frame;
-+ uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_None;
-+
-+ do {
-+ const char *format;
-+ int n_values = 1;
-+ struct spa_pod_frame f;
-+ bool choice;
-+
-+ switch (ftype) {
-+ case SPA_TYPE_Object:
-+ {
-+ uint32_t key = va_arg(args, uint32_t);
-+ if (key == 0)
-+ goto exit;
-+ spa_pod_builder_prop(builder, key, 0);
-+ break;
-+ }
-+ case SPA_TYPE_Sequence:
-+ {
-+ uint32_t offset = va_arg(args, uint32_t);
-+ uint32_t type = va_arg(args, uint32_t);
-+ if (type == 0)
-+ goto exit;
-+ spa_pod_builder_control(builder, offset, type);
-+ }
-+ default:
-+ break;
-+ }
-+ if ((format = va_arg(args, const char *)) == NULL)
-+ break;
-+
-+ choice = *format == '?';
-+ if (choice) {
-+ uint32_t type = spa_choice_from_id(*++format);
-+ if (*format != '\0')
-+ format++;
-+
-+ spa_pod_builder_push_choice(builder, &f, type, 0);
-+
-+ n_values = va_arg(args, int);
-+ }
-+ while (n_values-- > 0)
-+ SPA_POD_BUILDER_COLLECT(builder, *format, args);
-+
-+ if (choice)
-+ spa_pod_builder_pop(builder, &f);
-+ } while (true);
-+
-+ exit:
-+ return res;
-+}
-+
-+static inline int spa_pod_builder_add(struct spa_pod_builder *builder, ...)
-+{
-+ int res;
-+ va_list args;
-+
-+ va_start(args, builder);
-+ res = spa_pod_builder_addv(builder, args);
-+ va_end(args);
-+
-+ return res;
-+}
-+
-+#define spa_pod_builder_add_object(b,type,id,...) \
-+({ \
-+ struct spa_pod_frame _f; \
-+ spa_pod_builder_push_object(b, &_f, type, id); \
-+ spa_pod_builder_add(b, ##__VA_ARGS__, 0); \
-+ spa_pod_builder_pop(b, &_f); \
-+})
-+
-+#define spa_pod_builder_add_struct(b,...) \
-+({ \
-+ struct spa_pod_frame _f; \
-+ spa_pod_builder_push_struct(b, &_f); \
-+ spa_pod_builder_add(b, ##__VA_ARGS__, NULL); \
-+ spa_pod_builder_pop(b, &_f); \
-+})
-+
-+#define spa_pod_builder_add_sequence(b,unit,...) \
-+({ \
-+ struct spa_pod_frame _f; \
-+ spa_pod_builder_push_sequence(b, &_f, unit); \
-+ spa_pod_builder_add(b, ##__VA_ARGS__, 0, 0); \
-+ spa_pod_builder_pop(b, &_f); \
-+})
-+
-+/** Copy a pod structure */
-+static inline struct spa_pod *
-+spa_pod_copy(const struct spa_pod *pod)
-+{
-+ size_t size;
-+ struct spa_pod *c;
-+
-+ size = SPA_POD_SIZE(pod);
-+ if ((c = (struct spa_pod *) malloc(size)) == NULL)
-+ return NULL;
-+ return (struct spa_pod *) memcpy(c, pod, size);
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_POD_BUILDER_H */
-diff --git a/third_party/pipewire/spa/pod/command.h b/third_party/pipewire/spa/pod/command.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/command.h
-@@ -0,0 +1,61 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_COMMAND_H
-+#define SPA_COMMAND_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/pod/pod.h>
-+
-+struct spa_command_body {
-+ struct spa_pod_object_body body;
-+};
-+
-+struct spa_command {
-+ struct spa_pod pod;
-+ struct spa_command_body body;
-+};
-+
-+#define SPA_COMMAND_TYPE(cmd) ((cmd)->body.body.type)
-+#define SPA_COMMAND_ID(cmd,type) (SPA_COMMAND_TYPE(cmd) == type ? \
-+ (cmd)->body.body.id : SPA_ID_INVALID)
-+
-+#define SPA_COMMAND_INIT_FULL(t,size,type,id,...) (t) \
-+ { { size, SPA_TYPE_Object }, \
-+ { { type, id }, ##__VA_ARGS__ } } \
-+
-+#define SPA_COMMAND_INIT(type,id) \
-+ SPA_COMMAND_INIT_FULL(struct spa_command, \
-+ sizeof(struct spa_command_body), type, id)
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_COMMAND_H */
-diff --git a/third_party/pipewire/spa/pod/compare.h b/third_party/pipewire/spa/pod/compare.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/compare.h
-@@ -0,0 +1,181 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_POD_COMPARE_H
-+#define SPA_POD_COMPARE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+#include <errno.h>
-+#include <stdint.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <string.h>
-+
-+#include <spa/param/props.h>
-+#include <spa/pod/iter.h>
-+#include <spa/pod/builder.h>
-+
-+static inline int spa_pod_compare_value(uint32_t type, const void *r1, const void *r2, uint32_t size)
-+{
-+ switch (type) {
-+ case SPA_TYPE_None:
-+ return 0;
-+ case SPA_TYPE_Bool:
-+ case SPA_TYPE_Id:
-+ return *(uint32_t *) r1 == *(uint32_t *) r2 ? 0 : 1;
-+ case SPA_TYPE_Int:
-+ return *(int32_t *) r1 - *(int32_t *) r2;
-+ case SPA_TYPE_Long:
-+ return *(int64_t *) r1 - *(int64_t *) r2;
-+ case SPA_TYPE_Float:
-+ return *(float *) r1 - *(float *) r2;
-+ case SPA_TYPE_Double:
-+ return *(double *) r1 - *(double *) r2;
-+ case SPA_TYPE_String:
-+ return strcmp((char *)r1, (char *)r2);
-+ case SPA_TYPE_Bytes:
-+ return memcmp((char *)r1, (char *)r2, size);
-+ case SPA_TYPE_Rectangle:
-+ {
-+ const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1,
-+ *rec2 = (struct spa_rectangle *) r2;
-+ if (rec1->width == rec2->width && rec1->height == rec2->height)
-+ return 0;
-+ else if (rec1->width < rec2->width || rec1->height < rec2->height)
-+ return -1;
-+ else
-+ return 1;
-+ }
-+ case SPA_TYPE_Fraction:
-+ {
-+ const struct spa_fraction *f1 = (struct spa_fraction *) r1,
-+ *f2 = (struct spa_fraction *) r2;
-+ int64_t n1, n2;
-+ n1 = ((int64_t) f1->num) * f2->denom;
-+ n2 = ((int64_t) f2->num) * f1->denom;
-+ if (n1 < n2)
-+ return -1;
-+ else if (n1 > n2)
-+ return 1;
-+ else
-+ return 0;
-+ }
-+ default:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static inline int spa_pod_compare(const struct spa_pod *pod1,
-+ const struct spa_pod *pod2)
-+{
-+ int res = 0;
-+ uint32_t n_vals1, n_vals2;
-+ uint32_t choice1, choice2;
-+
-+ spa_return_val_if_fail(pod1 != NULL, -EINVAL);
-+ spa_return_val_if_fail(pod2 != NULL, -EINVAL);
-+
-+ pod1 = spa_pod_get_values(pod1, &n_vals1, &choice1);
-+ pod2 = spa_pod_get_values(pod2, &n_vals2, &choice2);
-+
-+ if (n_vals1 != n_vals2)
-+ return -EINVAL;
-+
-+ if (SPA_POD_TYPE(pod1) != SPA_POD_TYPE(pod2))
-+ return -EINVAL;
-+
-+ switch (SPA_POD_TYPE(pod1)) {
-+ case SPA_TYPE_Struct:
-+ {
-+ const struct spa_pod *p1, *p2;
-+ size_t p1s, p2s;
-+
-+ p1 = (const struct spa_pod*)SPA_POD_BODY_CONST(pod1);
-+ p1s = SPA_POD_BODY_SIZE(pod1);
-+ p2 = (const struct spa_pod*)SPA_POD_BODY_CONST(pod2);
-+ p2s = SPA_POD_BODY_SIZE(pod2);
-+
-+ while (true) {
-+ if (!spa_pod_is_inside(pod1, p1s, p1) ||
-+ !spa_pod_is_inside(pod2, p2s, p2))
-+ return -EINVAL;
-+
-+ if ((res = spa_pod_compare(p1, p2)) != 0)
-+ return res;
-+
-+ p1 = (const struct spa_pod*)spa_pod_next(p1);
-+ p2 = (const struct spa_pod*)spa_pod_next(p2);
-+ }
-+ break;
-+ }
-+ case SPA_TYPE_Object:
-+ {
-+ const struct spa_pod_prop *p1, *p2;
-+ const struct spa_pod_object *o1, *o2;
-+
-+ o1 = (const struct spa_pod_object*)pod1;
-+ o2 = (const struct spa_pod_object*)pod2;
-+
-+ p2 = NULL;
-+ SPA_POD_OBJECT_FOREACH(o1, p1) {
-+ if ((p2 = spa_pod_object_find_prop(o2, p2, p1->key)) == NULL)
-+ return 1;
-+ if ((res = spa_pod_compare(&p1->value, &p2->value)) != 0)
-+ return res;
-+ }
-+ p1 = NULL;
-+ SPA_POD_OBJECT_FOREACH(o2, p2) {
-+ if ((p1 = spa_pod_object_find_prop(o1, p1, p2->key)) == NULL)
-+ return -1;
-+ }
-+ break;
-+ }
-+ case SPA_TYPE_Array:
-+ {
-+ if (SPA_POD_BODY_SIZE(pod1) != SPA_POD_BODY_SIZE(pod2))
-+ return -EINVAL;
-+ res = memcmp(SPA_POD_BODY(pod1), SPA_POD_BODY(pod2), SPA_POD_BODY_SIZE(pod2));
-+ break;
-+ }
-+ default:
-+ if (SPA_POD_BODY_SIZE(pod1) != SPA_POD_BODY_SIZE(pod2))
-+ return -EINVAL;
-+ res = spa_pod_compare_value(SPA_POD_TYPE(pod1),
-+ SPA_POD_BODY(pod1), SPA_POD_BODY(pod2),
-+ SPA_POD_BODY_SIZE(pod1));
-+ break;
-+ }
-+ return res;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
-diff --git a/third_party/pipewire/spa/pod/event.h b/third_party/pipewire/spa/pod/event.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/event.h
-@@ -0,0 +1,59 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_EVENT_H
-+#define SPA_EVENT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/pod/pod.h>
-+
-+struct spa_event_body {
-+ struct spa_pod_object_body body;
-+};
-+
-+struct spa_event {
-+ struct spa_pod pod;
-+ struct spa_event_body body;
-+};
-+
-+#define SPA_EVENT_TYPE(ev) ((ev)->body.body.type)
-+#define SPA_EVENT_ID(ev,type) (SPA_EVENT_TYPE(ev) == type ? \
-+ (ev)->body.body.id : SPA_ID_INVALID)
-+
-+#define SPA_EVENT_INIT_FULL(t,size,type,id,...) (t) \
-+ { { size, SPA_TYPE_OBJECT }, \
-+ { { type, id }, ##__VA_ARGS__ } } \
-+
-+#define SPA_EVENT_INIT(type,id) \
-+ SPA_EVENT_INIT_FULL(struct spa_event, \
-+ sizeof(struct spa_event_body), type, id)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_EVENT_H */
-diff --git a/third_party/pipewire/spa/pod/filter.h b/third_party/pipewire/spa/pod/filter.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/filter.h
-@@ -0,0 +1,395 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#include <errno.h>
-+#include <stdint.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+#include <string.h>
-+
-+#include <spa/param/props.h>
-+#include <spa/pod/iter.h>
-+#include <spa/pod/builder.h>
-+#include <spa/pod/compare.h>
-+
-+static inline int spa_pod_choice_fix_default(struct spa_pod_choice *choice)
-+{
-+ void *val, *alt;
-+ int i, nvals;
-+ uint32_t type, size;
-+
-+ nvals = SPA_POD_CHOICE_N_VALUES(choice);
-+ type = SPA_POD_CHOICE_VALUE_TYPE(choice);
-+ size = SPA_POD_CHOICE_VALUE_SIZE(choice);
-+ alt = val = SPA_POD_CHOICE_VALUES(choice);
-+
-+ switch (choice->body.type) {
-+ case SPA_CHOICE_None:
-+ break;
-+ case SPA_CHOICE_Range:
-+ case SPA_CHOICE_Step:
-+ if (nvals > 1) {
-+ alt = SPA_MEMBER(alt, size, void);
-+ if (spa_pod_compare_value(type, val, alt, size) < 0)
-+ memcpy(val, alt, size);
-+ }
-+ if (nvals > 2) {
-+ alt = SPA_MEMBER(alt, size, void);
-+ if (spa_pod_compare_value(type, val, alt, size) > 0)
-+ memcpy(val, alt, size);
-+ }
-+ break;
-+ case SPA_CHOICE_Flags:
-+ case SPA_CHOICE_Enum:
-+ {
-+ void *best = NULL;
-+
-+ for (i = 1; i < nvals; i++) {
-+ alt = SPA_MEMBER(alt, size, void);
-+ if (spa_pod_compare_value(type, val, alt, size) == 0) {
-+ best = alt;
-+ break;
-+ }
-+ if (best == NULL)
-+ best = alt;
-+ }
-+ if (best)
-+ memcpy(val, best, size);
-+
-+ if (nvals <= 1)
-+ choice->body.type = SPA_CHOICE_None;
-+ break;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static inline int spa_pod_filter_flags_value(struct spa_pod_builder *b,
-+ uint32_t type, const void *r1, const void *r2, uint32_t size)
-+{
-+ switch (type) {
-+ case SPA_TYPE_Int:
-+ {
-+ int32_t val = (*(int32_t *) r1) & (*(int32_t *) r2);
-+ if (val == 0)
-+ return 0;
-+ spa_pod_builder_int(b, val);
-+ break;
-+ }
-+ case SPA_TYPE_Long:
-+ {
-+ int64_t val = (*(int64_t *) r1) & (*(int64_t *) r2);
-+ if (val == 0)
-+ return 0;
-+ spa_pod_builder_long(b, val);
-+ break;
-+ }
-+ default:
-+ return -ENOTSUP;
-+ }
-+ return 1;
-+}
-+
-+
-+static inline int
-+spa_pod_filter_prop(struct spa_pod_builder *b,
-+ const struct spa_pod_prop *p1,
-+ const struct spa_pod_prop *p2)
-+{
-+ const struct spa_pod *v1, *v2;
-+ struct spa_pod_choice *nc;
-+ uint32_t j, k, nalt1, nalt2;
-+ void *alt1, *alt2, *a1, *a2;
-+ uint32_t type, size, p1c, p2c;
-+ struct spa_pod_frame f;
-+
-+ v1 = spa_pod_get_values(&p1->value, &nalt1, &p1c);
-+ alt1 = SPA_POD_BODY(v1);
-+ v2 = spa_pod_get_values(&p2->value, &nalt2, &p2c);
-+ alt2 = SPA_POD_BODY(v2);
-+
-+ type = v1->type;
-+ size = v1->size;
-+
-+ /* incompatible property types */
-+ if (type != v2->type || size != v2->size || p1->key != p2->key)
-+ return -EINVAL;
-+
-+ if (p1c == SPA_CHOICE_None || p1c == SPA_CHOICE_Flags) {
-+ nalt1 = 1;
-+ } else {
-+ alt1 = SPA_MEMBER(alt1, size, void);
-+ nalt1--;
-+ }
-+
-+ if (p2c == SPA_CHOICE_None || p2c == SPA_CHOICE_Flags) {
-+ nalt2 = 1;
-+ } else {
-+ alt2 = SPA_MEMBER(alt2, size, void);
-+ nalt2--;
-+ }
-+
-+ /* start with copying the property */
-+ spa_pod_builder_prop(b, p1->key, 0);
-+ spa_pod_builder_push_choice(b, &f, 0, 0);
-+ nc = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f);
-+
-+ /* default value */
-+ spa_pod_builder_primitive(b, v1);
-+
-+ if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_None) ||
-+ (p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Enum) ||
-+ (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_None) ||
-+ (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Enum)) {
-+ int n_copied = 0;
-+ /* copy all equal values but don't copy the default value again */
-+ for (j = 0, a1 = alt1; j < nalt1; j++, a1 = SPA_MEMBER(a1, size, void)) {
-+ for (k = 0, a2 = alt2; k < nalt2; k++, a2 = SPA_MEMBER(a2,size,void)) {
-+ if (spa_pod_compare_value(type, a1, a2, size) == 0) {
-+ if (p1c == SPA_CHOICE_Enum || j > 0)
-+ spa_pod_builder_raw(b, a1, size);
-+ n_copied++;
-+ }
-+ }
-+ }
-+ if (n_copied == 0)
-+ return -EINVAL;
-+ nc->body.type = SPA_CHOICE_Enum;
-+ }
-+
-+ if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Range) ||
-+ (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Range)) {
-+ int n_copied = 0;
-+ /* copy all values inside the range */
-+ for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 = SPA_MEMBER(a1,size,void)) {
-+ if (spa_pod_compare_value(type, a1, a2, size) < 0)
-+ continue;
-+ if (spa_pod_compare_value(type, a1, SPA_MEMBER(a2,size,void), size) > 0)
-+ continue;
-+ spa_pod_builder_raw(b, a1, size);
-+ n_copied++;
-+ }
-+ if (n_copied == 0)
-+ return -EINVAL;
-+ nc->body.type = SPA_CHOICE_Enum;
-+ }
-+
-+ if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Step) ||
-+ (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Step)) {
-+ return -ENOTSUP;
-+ }
-+
-+ if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_None) ||
-+ (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Enum)) {
-+ int n_copied = 0;
-+ /* copy all values inside the range */
-+ for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 = SPA_MEMBER(a2,size,void)) {
-+ if (spa_pod_compare_value(type, a2, a1, size) < 0)
-+ continue;
-+ if (spa_pod_compare_value(type, a2, SPA_MEMBER(a1,size,void), size) > 0)
-+ continue;
-+ spa_pod_builder_raw(b, a2, size);
-+ n_copied++;
-+ }
-+ if (n_copied == 0)
-+ return -EINVAL;
-+ nc->body.type = SPA_CHOICE_Enum;
-+ }
-+
-+ if ((p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Range) ||
-+ (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Step) ||
-+ (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Range) ||
-+ (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Step)) {
-+ if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
-+ spa_pod_builder_raw(b, alt2, size);
-+ else
-+ spa_pod_builder_raw(b, alt1, size);
-+
-+ alt1 = SPA_MEMBER(alt1,size,void);
-+ alt2 = SPA_MEMBER(alt2,size,void);
-+
-+ if (spa_pod_compare_value(type, alt1, alt2, size) < 0)
-+ spa_pod_builder_raw(b, alt1, size);
-+ else
-+ spa_pod_builder_raw(b, alt2, size);
-+
-+ nc->body.type = SPA_CHOICE_Range;
-+ }
-+
-+ if ((p1c == SPA_CHOICE_None && p2c == SPA_CHOICE_Flags) ||
-+ (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_None) ||
-+ (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Flags)) {
-+ if (spa_pod_filter_flags_value(b, type, alt1, alt2, size) != 1)
-+ return -EINVAL;
-+ nc->body.type = SPA_CHOICE_Flags;
-+ }
-+
-+ if (p1c == SPA_CHOICE_Range && p2c == SPA_CHOICE_Flags)
-+ return -ENOTSUP;
-+
-+ if (p1c == SPA_CHOICE_Enum && p2c == SPA_CHOICE_Flags)
-+ return -ENOTSUP;
-+
-+ if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_None)
-+ return -ENOTSUP;
-+ if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Enum)
-+ return -ENOTSUP;
-+ if (p1c == SPA_CHOICE_Step && p2c == SPA_CHOICE_Flags)
-+ return -ENOTSUP;
-+
-+ if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Range)
-+ return -ENOTSUP;
-+ if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Step)
-+ return -ENOTSUP;
-+ if (p1c == SPA_CHOICE_Flags && p2c == SPA_CHOICE_Enum)
-+ return -ENOTSUP;
-+
-+ spa_pod_builder_pop(b, &f);
-+ spa_pod_choice_fix_default(nc);
-+
-+ return 0;
-+}
-+
-+static inline int spa_pod_filter_part(struct spa_pod_builder *b,
-+ const struct spa_pod *pod, uint32_t pod_size,
-+ const struct spa_pod *filter, uint32_t filter_size)
-+{
-+ const struct spa_pod *pp, *pf;
-+ int res = 0;
-+
-+ pf = filter;
-+
-+ SPA_POD_FOREACH(pod, pod_size, pp) {
-+ bool do_copy = false, do_advance = false;
-+ uint32_t filter_offset = 0;
-+ struct spa_pod_frame f;
-+
-+ switch (SPA_POD_TYPE(pp)) {
-+ case SPA_TYPE_Object:
-+ if (pf != NULL) {
-+ struct spa_pod_object *op = (struct spa_pod_object *) pp;
-+ struct spa_pod_object *of = (struct spa_pod_object *) pf;
-+ const struct spa_pod_prop *p1, *p2;
-+
-+ if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
-+ return -EINVAL;
-+
-+ spa_pod_builder_push_object(b, &f, op->body.type, op->body.id);
-+ p2 = NULL;
-+ SPA_POD_OBJECT_FOREACH(op, p1) {
-+ p2 = spa_pod_object_find_prop(of, p2, p1->key);
-+ if (p2 != NULL)
-+ res = spa_pod_filter_prop(b, p1, p2);
-+ else
-+ spa_pod_builder_raw_padded(b, p1, SPA_POD_PROP_SIZE(p1));
-+ if (res < 0)
-+ break;
-+ }
-+ if (res >= 0) {
-+ p1 = NULL;
-+ SPA_POD_OBJECT_FOREACH(of, p2) {
-+ p1 = spa_pod_object_find_prop(op, p1, p2->key);
-+ if (p1 != NULL)
-+ continue;
-+
-+ spa_pod_builder_raw_padded(b, p2, SPA_POD_PROP_SIZE(p2));
-+ }
-+ }
-+ spa_pod_builder_pop(b, &f);
-+ do_advance = true;
-+ }
-+ else
-+ do_copy = true;
-+ break;
-+
-+ case SPA_TYPE_Struct:
-+ if (pf != NULL) {
-+ if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp))
-+ return -EINVAL;
-+
-+ filter_offset = sizeof(struct spa_pod_struct);
-+ spa_pod_builder_push_struct(b, &f);
-+ res = spa_pod_filter_part(b,
-+ SPA_MEMBER(pp,filter_offset,const struct spa_pod),
-+ SPA_POD_SIZE(pp) - filter_offset,
-+ SPA_MEMBER(pf,filter_offset,const struct spa_pod),
-+ SPA_POD_SIZE(pf) - filter_offset);
-+ spa_pod_builder_pop(b, &f);
-+ do_advance = true;
-+ }
-+ else
-+ do_copy = true;
-+ break;
-+
-+ default:
-+ if (pf != NULL) {
-+ if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf))
-+ return -EINVAL;
-+ if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0)
-+ return -EINVAL;
-+ do_advance = true;
-+ }
-+ do_copy = true;
-+ break;
-+ }
-+ if (do_copy)
-+ spa_pod_builder_raw_padded(b, pp, SPA_POD_SIZE(pp));
-+ if (do_advance) {
-+ pf = (const struct spa_pod*)spa_pod_next(pf);
-+ if (!spa_pod_is_inside(filter, filter_size, pf))
-+ pf = NULL;
-+ }
-+ if (res < 0)
-+ break;
-+ }
-+ return res;
-+}
-+
-+static inline int
-+spa_pod_filter(struct spa_pod_builder *b,
-+ struct spa_pod **result,
-+ const struct spa_pod *pod,
-+ const struct spa_pod *filter)
-+{
-+ int res;
-+ struct spa_pod_builder_state state;
-+
-+ spa_return_val_if_fail(pod != NULL, -EINVAL);
-+ spa_return_val_if_fail(b != NULL, -EINVAL);
-+
-+ spa_pod_builder_get_state(b, &state);
-+ if (filter == NULL)
-+ res = spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod));
-+ else
-+ res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter));
-+
-+ if (res < 0) {
-+ spa_pod_builder_reset(b, &state);
-+ } else if (result) {
-+ *result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
-+ if (*result == NULL)
-+ res = -ENOSPC;
-+ }
-+ return res;
-+}
-diff --git a/third_party/pipewire/spa/pod/iter.h b/third_party/pipewire/spa/pod/iter.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/iter.h
-@@ -0,0 +1,446 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_POD_ITER_H
-+#define SPA_POD_ITER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <errno.h>
-+#include <sys/types.h>
-+
-+#include <spa/pod/pod.h>
-+
-+struct spa_pod_frame {
-+ struct spa_pod pod;
-+ struct spa_pod_frame *parent;
-+ uint32_t offset;
-+ uint32_t flags;
-+};
-+
-+static inline bool spa_pod_is_inside(const void *pod, uint32_t size, const void *iter)
-+{
-+ return SPA_POD_BODY(iter) <= SPA_MEMBER(pod, size, void) &&
-+ SPA_MEMBER(iter, SPA_POD_SIZE(iter), void) <= SPA_MEMBER(pod, size, void);
-+}
-+
-+static inline void *spa_pod_next(const void *iter)
-+{
-+ return SPA_MEMBER(iter, SPA_ROUND_UP_N(SPA_POD_SIZE(iter), 8), void);
-+}
-+
-+static inline struct spa_pod_prop *spa_pod_prop_first(const struct spa_pod_object_body *body)
-+{
-+ return SPA_MEMBER(body, sizeof(struct spa_pod_object_body), struct spa_pod_prop);
-+}
-+
-+static inline bool spa_pod_prop_is_inside(const struct spa_pod_object_body *body,
-+ uint32_t size, const struct spa_pod_prop *iter)
-+{
-+ return SPA_POD_CONTENTS(struct spa_pod_prop, iter) <= SPA_MEMBER(body, size, void) &&
-+ SPA_MEMBER(iter, SPA_POD_PROP_SIZE(iter), void) <= SPA_MEMBER(body, size, void);
-+}
-+
-+static inline struct spa_pod_prop *spa_pod_prop_next(const struct spa_pod_prop *iter)
-+{
-+ return SPA_MEMBER(iter, SPA_ROUND_UP_N(SPA_POD_PROP_SIZE(iter), 8), struct spa_pod_prop);
-+}
-+
-+static inline struct spa_pod_control *spa_pod_control_first(const struct spa_pod_sequence_body *body)
-+{
-+ return SPA_MEMBER(body, sizeof(struct spa_pod_sequence_body), struct spa_pod_control);
-+}
-+
-+static inline bool spa_pod_control_is_inside(const struct spa_pod_sequence_body *body,
-+ uint32_t size, const struct spa_pod_control *iter)
-+{
-+ return SPA_POD_CONTENTS(struct spa_pod_control, iter) <= SPA_MEMBER(body, size, void) &&
-+ SPA_MEMBER(iter, SPA_POD_CONTROL_SIZE(iter), void) <= SPA_MEMBER(body, size, void);
-+}
-+
-+static inline struct spa_pod_control *spa_pod_control_next(const struct spa_pod_control *iter)
-+{
-+ return SPA_MEMBER(iter, SPA_ROUND_UP_N(SPA_POD_CONTROL_SIZE(iter), 8), struct spa_pod_control);
-+}
-+
-+#define SPA_POD_ARRAY_BODY_FOREACH(body, _size, iter) \
-+ for ((iter) = (__typeof__(iter))SPA_MEMBER((body), sizeof(struct spa_pod_array_body), void); \
-+ (iter) < (__typeof__(iter))SPA_MEMBER((body), (_size), void); \
-+ (iter) = (__typeof__(iter))SPA_MEMBER((iter), (body)->child.size, void))
-+
-+#define SPA_POD_ARRAY_FOREACH(obj, iter) \
-+ SPA_POD_ARRAY_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
-+
-+#define SPA_POD_CHOICE_BODY_FOREACH(body, _size, iter) \
-+ for ((iter) = (__typeof__(iter))SPA_MEMBER((body), sizeof(struct spa_pod_choice_body), void); \
-+ (iter) < (__typeof__(iter))SPA_MEMBER((body), (_size), void); \
-+ (iter) = (__typeof__(iter))SPA_MEMBER((iter), (body)->child.size, void))
-+
-+#define SPA_POD_CHOICE_FOREACH(obj, iter) \
-+ SPA_POD_CHOICE_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
-+
-+#define SPA_POD_FOREACH(pod, size, iter) \
-+ for ((iter) = (pod); \
-+ spa_pod_is_inside(pod, size, iter); \
-+ (iter) = (__typeof__(iter))spa_pod_next(iter))
-+
-+#define SPA_POD_STRUCT_FOREACH(obj, iter) \
-+ SPA_POD_FOREACH(SPA_POD_BODY(obj), SPA_POD_BODY_SIZE(obj), iter)
-+
-+#define SPA_POD_OBJECT_BODY_FOREACH(body, size, iter) \
-+ for ((iter) = spa_pod_prop_first(body); \
-+ spa_pod_prop_is_inside(body, size, iter); \
-+ (iter) = spa_pod_prop_next(iter))
-+
-+#define SPA_POD_OBJECT_FOREACH(obj, iter) \
-+ SPA_POD_OBJECT_BODY_FOREACH(&(obj)->body, SPA_POD_BODY_SIZE(obj), iter)
-+
-+#define SPA_POD_SEQUENCE_BODY_FOREACH(body, size, iter) \
-+ for ((iter) = spa_pod_control_first(body); \
-+ spa_pod_control_is_inside(body, size, iter); \
-+ (iter) = spa_pod_control_next(iter))
-+
-+#define SPA_POD_SEQUENCE_FOREACH(seq, iter) \
-+ SPA_POD_SEQUENCE_BODY_FOREACH(&(seq)->body, SPA_POD_BODY_SIZE(seq), iter)
-+
-+
-+static inline void *spa_pod_from_data(void *data, size_t maxsize, off_t offset, size_t size)
-+{
-+ void *pod;
-+ if (size < sizeof(struct spa_pod) || offset + size > maxsize)
-+ return NULL;
-+ pod = SPA_MEMBER(data, offset, void);
-+ if (SPA_POD_SIZE(pod) > size)
-+ return NULL;
-+ return pod;
-+}
-+
-+static inline int spa_pod_is_none(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_None);
-+}
-+
-+static inline int spa_pod_is_bool(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Bool && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
-+}
-+
-+static inline int spa_pod_get_bool(const struct spa_pod *pod, bool *value)
-+{
-+ if (!spa_pod_is_bool(pod))
-+ return -EINVAL;
-+ *value = !!SPA_POD_VALUE(struct spa_pod_bool, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_id(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Id && SPA_POD_BODY_SIZE(pod) >= sizeof(uint32_t));
-+}
-+
-+static inline int spa_pod_get_id(const struct spa_pod *pod, uint32_t *value)
-+{
-+ if (!spa_pod_is_id(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_id, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_int(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Int && SPA_POD_BODY_SIZE(pod) >= sizeof(int32_t));
-+}
-+
-+static inline int spa_pod_get_int(const struct spa_pod *pod, int32_t *value)
-+{
-+ if (!spa_pod_is_int(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_int, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_long(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Long && SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
-+}
-+
-+static inline int spa_pod_get_long(const struct spa_pod *pod, int64_t *value)
-+{
-+ if (!spa_pod_is_long(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_long, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_float(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Float && SPA_POD_BODY_SIZE(pod) >= sizeof(float));
-+}
-+
-+static inline int spa_pod_get_float(const struct spa_pod *pod, float *value)
-+{
-+ if (!spa_pod_is_float(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_float, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_double(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Double && SPA_POD_BODY_SIZE(pod) >= sizeof(double));
-+}
-+
-+static inline int spa_pod_get_double(const struct spa_pod *pod, double *value)
-+{
-+ if (!spa_pod_is_double(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_double, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_string(const struct spa_pod *pod)
-+{
-+ const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_String &&
-+ SPA_POD_BODY_SIZE(pod) > 0 &&
-+ s[SPA_POD_BODY_SIZE(pod)-1] == '\0');
-+}
-+
-+static inline int spa_pod_get_string(const struct spa_pod *pod, const char **value)
-+{
-+ if (!spa_pod_is_string(pod))
-+ return -EINVAL;
-+ *value = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_copy_string(const struct spa_pod *pod, size_t maxlen, char *dest)
-+{
-+ const char *s = (const char *)SPA_POD_CONTENTS(struct spa_pod_string, pod);
-+ if (!spa_pod_is_string(pod) || maxlen < 1)
-+ return -EINVAL;
-+ strncpy(dest, s, maxlen-1);
-+ dest[maxlen-1]= '\0';
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_bytes(const struct spa_pod *pod)
-+{
-+ return SPA_POD_TYPE(pod) == SPA_TYPE_Bytes;
-+}
-+
-+static inline int spa_pod_get_bytes(const struct spa_pod *pod, const void **value, uint32_t *len)
-+{
-+ if (!spa_pod_is_bytes(pod))
-+ return -EINVAL;
-+ *value = (const void *)SPA_POD_CONTENTS(struct spa_pod_bytes, pod);
-+ *len = SPA_POD_BODY_SIZE(pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_pointer(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Pointer &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_pointer_body));
-+}
-+
-+static inline int spa_pod_get_pointer(const struct spa_pod *pod, uint32_t *type, const void **value)
-+{
-+ if (!spa_pod_is_pointer(pod))
-+ return -EINVAL;
-+ *type = ((struct spa_pod_pointer*)pod)->body.type;
-+ *value = ((struct spa_pod_pointer*)pod)->body.value;
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_fd(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Fd &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(int64_t));
-+}
-+
-+static inline int spa_pod_get_fd(const struct spa_pod *pod, int64_t *value)
-+{
-+ if (!spa_pod_is_fd(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_fd, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_rectangle(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Rectangle &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_rectangle));
-+}
-+
-+static inline int spa_pod_get_rectangle(const struct spa_pod *pod, struct spa_rectangle *value)
-+{
-+ if (!spa_pod_is_rectangle(pod))
-+ return -EINVAL;
-+ *value = SPA_POD_VALUE(struct spa_pod_rectangle, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_fraction(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Fraction &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_fraction));
-+}
-+
-+static inline int spa_pod_get_fraction(const struct spa_pod *pod, struct spa_fraction *value)
-+{
-+ spa_return_val_if_fail(spa_pod_is_fraction(pod), -EINVAL);
-+ *value = SPA_POD_VALUE(struct spa_pod_fraction, pod);
-+ return 0;
-+}
-+
-+static inline int spa_pod_is_bitmap(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Bitmap &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(uint8_t));
-+}
-+
-+static inline int spa_pod_is_array(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Array &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_array_body));
-+}
-+
-+static inline void *spa_pod_get_array(const struct spa_pod *pod, uint32_t *n_values)
-+{
-+ spa_return_val_if_fail(spa_pod_is_array(pod), NULL);
-+ *n_values = SPA_POD_ARRAY_N_VALUES(pod);
-+ return SPA_POD_ARRAY_VALUES(pod);
-+}
-+
-+static inline uint32_t spa_pod_copy_array(const struct spa_pod *pod, uint32_t type,
-+ void *values, uint32_t max_values)
-+{
-+ uint32_t n_values;
-+ void *v = spa_pod_get_array(pod, &n_values);
-+ if (v == NULL || max_values == 0 || SPA_POD_ARRAY_VALUE_TYPE(pod) != type)
-+ return 0;
-+ n_values = SPA_MIN(n_values, max_values);
-+ memcpy(values, v, SPA_POD_ARRAY_VALUE_SIZE(pod) * n_values);
-+ return n_values;
-+}
-+
-+static inline int spa_pod_is_choice(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Choice &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_choice_body));
-+}
-+
-+static inline struct spa_pod *spa_pod_get_values(const struct spa_pod *pod, uint32_t *n_vals, uint32_t *choice)
-+{
-+ if (pod->type == SPA_TYPE_Choice) {
-+ *choice = SPA_POD_CHOICE_TYPE(pod);
-+ *n_vals = *choice == SPA_CHOICE_None ? 1 : SPA_POD_CHOICE_N_VALUES(pod);
-+ return (struct spa_pod*)SPA_POD_CHOICE_CHILD(pod);
-+ } else {
-+ *n_vals = 1;
-+ *choice = SPA_CHOICE_None;
-+ return (struct spa_pod*)pod;
-+ }
-+}
-+
-+static inline int spa_pod_is_struct(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Struct);
-+}
-+
-+static inline int spa_pod_is_object(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Object &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_object_body));
-+}
-+
-+static inline bool spa_pod_is_object_type(const struct spa_pod *pod, uint32_t type)
-+{
-+ return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_TYPE(pod) == type);
-+}
-+
-+static inline bool spa_pod_is_object_id(const struct spa_pod *pod, uint32_t id)
-+{
-+ return (pod && spa_pod_is_object(pod) && SPA_POD_OBJECT_ID(pod) == id);
-+}
-+
-+static inline int spa_pod_is_sequence(const struct spa_pod *pod)
-+{
-+ return (SPA_POD_TYPE(pod) == SPA_TYPE_Sequence &&
-+ SPA_POD_BODY_SIZE(pod) >= sizeof(struct spa_pod_sequence_body));
-+}
-+
-+static inline const struct spa_pod_prop *spa_pod_object_find_prop(const struct spa_pod_object *pod,
-+ const struct spa_pod_prop *start, uint32_t key)
-+{
-+ const struct spa_pod_prop *first, *res;
-+
-+ first = spa_pod_prop_first(&pod->body);
-+ start = start ? spa_pod_prop_next(start) : first;
-+
-+ for (res = start; spa_pod_prop_is_inside(&pod->body, pod->pod.size, res);
-+ res = spa_pod_prop_next(res)) {
-+ if (res->key == key)
-+ return res;
-+ }
-+ for (res = first; res != start; res = spa_pod_prop_next(res)) {
-+ if (res->key == key)
-+ return res;
-+ }
-+ return NULL;
-+}
-+
-+static inline const struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod,
-+ const struct spa_pod_prop *start, uint32_t key)
-+{
-+ if (!spa_pod_is_object(pod))
-+ return NULL;
-+ return spa_pod_object_find_prop((const struct spa_pod_object *)pod, start, key);
-+}
-+
-+static inline int spa_pod_object_fixate(struct spa_pod_object *pod)
-+{
-+ struct spa_pod_prop *res;
-+ SPA_POD_OBJECT_FOREACH(pod, res) {
-+ if (res->value.type == SPA_TYPE_Choice)
-+ ((struct spa_pod_choice*)&res->value)->body.type = SPA_CHOICE_None;
-+ }
-+ return 0;
-+}
-+
-+static inline int spa_pod_fixate(struct spa_pod *pod)
-+{
-+ if (!spa_pod_is_object(pod))
-+ return -EINVAL;
-+ return spa_pod_object_fixate((struct spa_pod_object *)pod);
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_POD_H */
-diff --git a/third_party/pipewire/spa/pod/parser.h b/third_party/pipewire/spa/pod/parser.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/parser.h
-@@ -0,0 +1,573 @@
-+/* Spa
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_POD_PARSER_H
-+#define SPA_POD_PARSER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <errno.h>
-+#include <stdarg.h>
-+
-+#include <spa/pod/iter.h>
-+#include <spa/pod/vararg.h>
-+
-+struct spa_pod_parser_state {
-+ uint32_t offset;
-+ uint32_t flags;
-+ struct spa_pod_frame *frame;
-+};
-+
-+struct spa_pod_parser {
-+ const void *data;
-+ uint32_t size;
-+ uint32_t _padding;
-+ struct spa_pod_parser_state state;
-+};
-+
-+#define SPA_POD_PARSER_INIT(buffer,size) (struct spa_pod_parser){ buffer, size, }
-+
-+static inline void spa_pod_parser_init(struct spa_pod_parser *parser,
-+ const void *data, uint32_t size)
-+{
-+ *parser = SPA_POD_PARSER_INIT(data, size);
-+}
-+
-+static inline void spa_pod_parser_pod(struct spa_pod_parser *parser,
-+ const struct spa_pod *pod)
-+{
-+ spa_pod_parser_init(parser, pod, SPA_POD_SIZE(pod));
-+}
-+
-+static inline void
-+spa_pod_parser_get_state(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
-+{
-+ *state = parser->state;
-+}
-+
-+static inline void
-+spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state *state)
-+{
-+ parser->state = *state;
-+}
-+
-+static inline struct spa_pod *
-+spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
-+{
-+ if (offset + 8 <= size) {
-+ struct spa_pod *pod = SPA_MEMBER(parser->data, offset, struct spa_pod);
-+ if (offset + SPA_POD_SIZE(pod) <= size)
-+ return pod;
-+ }
-+ return NULL;
-+}
-+
-+static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
-+{
-+ return SPA_MEMBER(parser->data, frame->offset, struct spa_pod);
-+}
-+
-+static inline void spa_pod_parser_push(struct spa_pod_parser *parser,
-+ struct spa_pod_frame *frame, const struct spa_pod *pod, uint32_t offset)
-+{
-+ frame->pod = *pod;
-+ frame->offset = offset;
-+ frame->parent = parser->state.frame;
-+ frame->flags = parser->state.flags;
-+ parser->state.frame = frame;
-+}
-+
-+static inline struct spa_pod *spa_pod_parser_current(struct spa_pod_parser *parser)
-+{
-+ struct spa_pod_frame *f = parser->state.frame;
-+ uint32_t size = f ? f->offset + SPA_POD_SIZE(&f->pod) : parser->size;
-+ return spa_pod_parser_deref(parser, parser->state.offset, size);
-+}
-+
-+static inline void spa_pod_parser_advance(struct spa_pod_parser *parser, const struct spa_pod *pod)
-+{
-+ parser->state.offset += SPA_ROUND_UP_N(SPA_POD_SIZE(pod), 8);
-+}
-+
-+static inline struct spa_pod *spa_pod_parser_next(struct spa_pod_parser *parser)
-+{
-+ struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod)
-+ spa_pod_parser_advance(parser, pod);
-+ return pod;
-+}
-+
-+static inline int spa_pod_parser_pop(struct spa_pod_parser *parser,
-+ struct spa_pod_frame *frame)
-+{
-+ parser->state.frame = frame->parent;
-+ parser->state.offset = frame->offset + SPA_ROUND_UP_N(SPA_POD_SIZE(&frame->pod), 8);
-+ return 0;
-+}
-+
-+static inline int spa_pod_parser_get_bool(struct spa_pod_parser *parser, bool *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_bool(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_id(struct spa_pod_parser *parser, uint32_t *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_id(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_int(struct spa_pod_parser *parser, int32_t *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_int(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_long(struct spa_pod_parser *parser, int64_t *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_long(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_float(struct spa_pod_parser *parser, float *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_float(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_double(struct spa_pod_parser *parser, double *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_double(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_string(struct spa_pod_parser *parser, const char **value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_string(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_bytes(struct spa_pod_parser *parser, const void **value, uint32_t *len)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_bytes(pod, value, len)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_pointer(struct spa_pod_parser *parser, uint32_t *type, const void **value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_pointer(pod, type, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_fd(struct spa_pod_parser *parser, int64_t *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_fd(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_rectangle(struct spa_pod_parser *parser, struct spa_rectangle *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_rectangle(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_fraction(struct spa_pod_parser *parser, struct spa_fraction *value)
-+{
-+ int res = -EPIPE;
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod != NULL && (res = spa_pod_get_fraction(pod, value)) >= 0)
-+ spa_pod_parser_advance(parser, pod);
-+ return res;
-+}
-+
-+static inline int spa_pod_parser_get_pod(struct spa_pod_parser *parser, struct spa_pod **value)
-+{
-+ struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod == NULL)
-+ return -EPIPE;
-+ *value = pod;
-+ spa_pod_parser_advance(parser, pod);
-+ return 0;
-+}
-+static inline int spa_pod_parser_push_struct(struct spa_pod_parser *parser,
-+ struct spa_pod_frame *frame)
-+{
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod == NULL)
-+ return -EPIPE;
-+ if (!spa_pod_is_struct(pod))
-+ return -EINVAL;
-+ spa_pod_parser_push(parser, frame, pod, parser->state.offset);
-+ parser->state.offset += sizeof(struct spa_pod_struct);
-+ return 0;
-+}
-+
-+static inline int spa_pod_parser_push_object(struct spa_pod_parser *parser,
-+ struct spa_pod_frame *frame, uint32_t type, uint32_t *id)
-+{
-+ const struct spa_pod *pod = spa_pod_parser_current(parser);
-+ if (pod == NULL)
-+ return -EPIPE;
-+ if (!spa_pod_is_object(pod))
-+ return -EINVAL;
-+ if (type != SPA_POD_OBJECT_TYPE(pod))
-+ return -EPROTO;
-+ if (id != NULL)
-+ *id = SPA_POD_OBJECT_ID(pod);
-+ spa_pod_parser_push(parser, frame, pod, parser->state.offset);
-+ parser->state.offset = parser->size;
-+ return 0;
-+}
-+
-+static inline bool spa_pod_parser_can_collect(const struct spa_pod *pod, char type)
-+{
-+ if (pod == NULL)
-+ return false;
-+
-+ if (spa_pod_is_choice(pod) &&
-+ SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None &&
-+ spa_pod_parser_can_collect(SPA_POD_CHOICE_CHILD(pod), type))
-+ return true;
-+
-+ switch (type) {
-+ case 'P':
-+ return true;
-+ case 'b':
-+ return spa_pod_is_bool(pod);
-+ case 'I':
-+ return spa_pod_is_id(pod);
-+ case 'i':
-+ return spa_pod_is_int(pod);
-+ case 'l':
-+ return spa_pod_is_long(pod);
-+ case 'f':
-+ return spa_pod_is_float(pod);
-+ case 'd':
-+ return spa_pod_is_double(pod);
-+ case 's':
-+ return spa_pod_is_string(pod) || spa_pod_is_none(pod);
-+ case 'S':
-+ return spa_pod_is_string(pod);
-+ case 'y':
-+ return spa_pod_is_bytes(pod);
-+ case 'R':
-+ return spa_pod_is_rectangle(pod);
-+ case 'F':
-+ return spa_pod_is_fraction(pod);
-+ case 'B':
-+ return spa_pod_is_bitmap(pod);
-+ case 'a':
-+ return spa_pod_is_array(pod);
-+ case 'p':
-+ return spa_pod_is_pointer(pod);
-+ case 'h':
-+ return spa_pod_is_fd(pod);
-+ case 'T':
-+ return spa_pod_is_struct(pod) || spa_pod_is_none(pod);
-+ case 'O':
-+ return spa_pod_is_object(pod) || spa_pod_is_none(pod);
-+ case 'V':
-+ return spa_pod_is_choice(pod);
-+ default:
-+ return false;
-+ }
-+}
-+
-+#define SPA_POD_PARSER_COLLECT(pod,_type,args) \
-+do { \
-+ switch (_type) { \
-+ case 'b': \
-+ *va_arg(args, bool*) = SPA_POD_VALUE(struct spa_pod_bool, pod); \
-+ break; \
-+ case 'I': \
-+ case 'i': \
-+ *va_arg(args, int32_t*) = SPA_POD_VALUE(struct spa_pod_int, pod); \
-+ break; \
-+ case 'l': \
-+ *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_long, pod); \
-+ break; \
-+ case 'f': \
-+ *va_arg(args, float*) = SPA_POD_VALUE(struct spa_pod_float, pod); \
-+ break; \
-+ case 'd': \
-+ *va_arg(args, double*) = SPA_POD_VALUE(struct spa_pod_double, pod); \
-+ break; \
-+ case 's': \
-+ *va_arg(args, char**) = \
-+ (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
-+ ? NULL \
-+ : (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod)); \
-+ break; \
-+ case 'S': \
-+ { \
-+ char *dest = va_arg(args, char*); \
-+ uint32_t maxlen = va_arg(args, uint32_t); \
-+ strncpy(dest, (char *)SPA_POD_CONTENTS(struct spa_pod_string, pod), maxlen-1); \
-+ break; \
-+ } \
-+ case 'y': \
-+ *(va_arg(args, void **)) = SPA_POD_CONTENTS(struct spa_pod_bytes, pod); \
-+ *(va_arg(args, uint32_t *)) = SPA_POD_BODY_SIZE(pod); \
-+ break; \
-+ case 'R': \
-+ *va_arg(args, struct spa_rectangle*) = \
-+ SPA_POD_VALUE(struct spa_pod_rectangle, pod); \
-+ break; \
-+ case 'F': \
-+ *va_arg(args, struct spa_fraction*) = \
-+ SPA_POD_VALUE(struct spa_pod_fraction, pod); \
-+ break; \
-+ case 'B': \
-+ *va_arg(args, uint32_t **) = \
-+ (uint32_t *) SPA_POD_CONTENTS(struct spa_pod_bitmap, pod); \
-+ break; \
-+ case 'a': \
-+ *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_SIZE(pod); \
-+ *va_arg(args, uint32_t*) = SPA_POD_ARRAY_VALUE_TYPE(pod); \
-+ *va_arg(args, uint32_t*) = SPA_POD_ARRAY_N_VALUES(pod); \
-+ *va_arg(args, void**) = SPA_POD_ARRAY_VALUES(pod); \
-+ break; \
-+ case 'p': \
-+ { \
-+ struct spa_pod_pointer_body *b = \
-+ (struct spa_pod_pointer_body *) SPA_POD_BODY(pod); \
-+ *(va_arg(args, uint32_t *)) = b->type; \
-+ *(va_arg(args, const void **)) = b->value; \
-+ break; \
-+ } \
-+ case 'h': \
-+ *va_arg(args, int64_t*) = SPA_POD_VALUE(struct spa_pod_fd, pod); \
-+ break; \
-+ case 'P': \
-+ case 'T': \
-+ case 'O': \
-+ case 'V': \
-+ { \
-+ const struct spa_pod **d = va_arg(args, const struct spa_pod**); \
-+ if (d) \
-+ *d = (pod == NULL || (SPA_POD_TYPE(pod) == SPA_TYPE_None) \
-+ ? NULL : pod); \
-+ break; \
-+ } \
-+ default: \
-+ break; \
-+ } \
-+} while(false)
-+
-+#define SPA_POD_PARSER_SKIP(_type,args) \
-+do { \
-+ switch (_type) { \
-+ case 'S': \
-+ va_arg(args, char*); \
-+ va_arg(args, uint32_t); \
-+ break; \
-+ case 'a': \
-+ va_arg(args, void*); \
-+ va_arg(args, void*); \
-+ /* fallthrough */ \
-+ case 'p': \
-+ case 'y': \
-+ va_arg(args, void*); \
-+ /* fallthrough */ \
-+ case 'b': \
-+ case 'I': \
-+ case 'i': \
-+ case 'l': \
-+ case 'f': \
-+ case 'd': \
-+ case 's': \
-+ case 'R': \
-+ case 'F': \
-+ case 'B': \
-+ case 'h': \
-+ case 'V': \
-+ case 'P': \
-+ case 'T': \
-+ case 'O': \
-+ va_arg(args, void*); \
-+ break; \
-+ } \
-+} while(false)
-+
-+static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, va_list args)
-+{
-+ struct spa_pod_frame *f = parser->state.frame;
-+ uint32_t ftype = f ? f->pod.type : (uint32_t)SPA_TYPE_Struct;
-+ const struct spa_pod_prop *prop = NULL;
-+ int count = 0;
-+
-+ do {
-+ bool optional;
-+ const struct spa_pod *pod = NULL;
-+ const char *format;
-+
-+ if (ftype == SPA_TYPE_Object) {
-+ uint32_t key = va_arg(args, uint32_t);
-+ const struct spa_pod_object *object;
-+
-+ if (key == 0)
-+ break;
-+
-+ object = (const struct spa_pod_object *)spa_pod_parser_frame(parser, f);
-+ prop = spa_pod_object_find_prop(object, prop, key);
-+ pod = prop ? &prop->value : NULL;
-+ }
-+
-+ if ((format = va_arg(args, char *)) == NULL)
-+ break;
-+
-+ if (ftype == SPA_TYPE_Struct)
-+ pod = spa_pod_parser_next(parser);
-+
-+ if ((optional = (*format == '?')))
-+ format++;
-+
-+ if (!spa_pod_parser_can_collect(pod, *format)) {
-+ if (!optional) {
-+ if (pod == NULL)
-+ return -ESRCH;
-+ else
-+ return -EPROTO;
-+ }
-+ SPA_POD_PARSER_SKIP(*format, args);
-+ } else {
-+ if (pod->type == SPA_TYPE_Choice && *format != 'V' &&
-+ SPA_POD_CHOICE_TYPE(pod) == SPA_CHOICE_None)
-+ pod = SPA_POD_CHOICE_CHILD(pod);
-+
-+ SPA_POD_PARSER_COLLECT(pod, *format, args);
-+ count++;
-+ }
-+ } while (true);
-+
-+ return count;
-+}
-+
-+static inline int spa_pod_parser_get(struct spa_pod_parser *parser, ...)
-+{
-+ int res;
-+ va_list args;
-+
-+ va_start(args, parser);
-+ res = spa_pod_parser_getv(parser, args);
-+ va_end(args);
-+
-+ return res;
-+}
-+
-+#define SPA_POD_OPT_Bool(val) "?" SPA_POD_Bool(val)
-+#define SPA_POD_OPT_Id(val) "?" SPA_POD_Id(val)
-+#define SPA_POD_OPT_Int(val) "?" SPA_POD_Int(val)
-+#define SPA_POD_OPT_Long(val) "?" SPA_POD_Long(val)
-+#define SPA_POD_OPT_Float(val) "?" SPA_POD_Float(val)
-+#define SPA_POD_OPT_Double(val) "?" SPA_POD_Double(val)
-+#define SPA_POD_OPT_String(val) "?" SPA_POD_String(val)
-+#define SPA_POD_OPT_Stringn(val,len) "?" SPA_POD_Stringn(val,len)
-+#define SPA_POD_OPT_Bytes(val,len) "?" SPA_POD_Bytes(val,len)
-+#define SPA_POD_OPT_Rectangle(val) "?" SPA_POD_Rectangle(val)
-+#define SPA_POD_OPT_Fraction(val) "?" SPA_POD_Fraction(val)
-+#define SPA_POD_OPT_Array(csize,ctype,n_vals,vals) "?" SPA_POD_Array(csize,ctype,n_vals,vals)
-+#define SPA_POD_OPT_Pointer(type,val) "?" SPA_POD_Pointer(type,val)
-+#define SPA_POD_OPT_Fd(val) "?" SPA_POD_Fd(val)
-+#define SPA_POD_OPT_Pod(val) "?" SPA_POD_Pod(val)
-+#define SPA_POD_OPT_PodObject(val) "?" SPA_POD_PodObject(val)
-+#define SPA_POD_OPT_PodStruct(val) "?" SPA_POD_PodStruct(val)
-+#define SPA_POD_OPT_PodChoice(val) "?" SPA_POD_PodChoice(val)
-+
-+#define spa_pod_parser_get_object(p,type,id,...) \
-+({ \
-+ struct spa_pod_frame _f; \
-+ int _res; \
-+ if ((_res = spa_pod_parser_push_object(p, &_f, type, id)) == 0) { \
-+ _res = spa_pod_parser_get(p,##__VA_ARGS__, 0); \
-+ spa_pod_parser_pop(p, &_f); \
-+ } \
-+ _res; \
-+})
-+
-+#define spa_pod_parser_get_struct(p,...) \
-+({ \
-+ struct spa_pod_frame _f; \
-+ int _res; \
-+ if ((_res = spa_pod_parser_push_struct(p, &_f)) == 0) { \
-+ _res = spa_pod_parser_get(p,##__VA_ARGS__, NULL); \
-+ spa_pod_parser_pop(p, &_f); \
-+ } \
-+ _res; \
-+})
-+
-+#define spa_pod_parse_object(pod,type,id,...) \
-+({ \
-+ struct spa_pod_parser _p; \
-+ spa_pod_parser_pod(&_p, pod); \
-+ spa_pod_parser_get_object(&_p,type,id,##__VA_ARGS__); \
-+})
-+
-+#define spa_pod_parse_struct(pod,...) \
-+({ \
-+ struct spa_pod_parser _p; \
-+ spa_pod_parser_pod(&_p, pod); \
-+ spa_pod_parser_get_struct(&_p,##__VA_ARGS__); \
-+})
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_POD_PARSER_H */
-diff --git a/third_party/pipewire/spa/pod/pod.h b/third_party/pipewire/spa/pod/pod.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/pod.h
-@@ -0,0 +1,231 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_POD_H
-+#define SPA_POD_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/type.h>
-+
-+#define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size)
-+#define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type)
-+#define SPA_POD_SIZE(pod) (sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod))
-+#define SPA_POD_CONTENTS_SIZE(type,pod) (SPA_POD_SIZE(pod)-sizeof(type))
-+
-+#define SPA_POD_CONTENTS(type,pod) SPA_MEMBER((pod),sizeof(type),void)
-+#define SPA_POD_CONTENTS_CONST(type,pod) SPA_MEMBER((pod),sizeof(type),const void)
-+#define SPA_POD_BODY(pod) SPA_MEMBER((pod),sizeof(struct spa_pod),void)
-+#define SPA_POD_BODY_CONST(pod) SPA_MEMBER((pod),sizeof(struct spa_pod),const void)
-+
-+struct spa_pod {
-+ uint32_t size; /* size of the body */
-+ uint32_t type; /* a basic id of enum spa_type */
-+};
-+
-+#define SPA_POD_VALUE(type,pod) (((type*)pod)->value)
-+
-+struct spa_pod_bool {
-+ struct spa_pod pod;
-+ int32_t value;
-+ int32_t _padding;
-+};
-+
-+struct spa_pod_id {
-+ struct spa_pod pod;
-+ uint32_t value;
-+ int32_t _padding;
-+};
-+
-+struct spa_pod_int {
-+ struct spa_pod pod;
-+ int32_t value;
-+ int32_t _padding;
-+};
-+
-+struct spa_pod_long {
-+ struct spa_pod pod;
-+ int64_t value;
-+};
-+
-+struct spa_pod_float {
-+ struct spa_pod pod;
-+ float value;
-+ int32_t _padding;
-+};
-+
-+struct spa_pod_double {
-+ struct spa_pod pod;
-+ double value;
-+};
-+
-+struct spa_pod_string {
-+ struct spa_pod pod;
-+ /* value here */
-+};
-+
-+struct spa_pod_bytes {
-+ struct spa_pod pod;
-+ /* value here */
-+};
-+
-+struct spa_pod_rectangle {
-+ struct spa_pod pod;
-+ struct spa_rectangle value;
-+};
-+
-+struct spa_pod_fraction {
-+ struct spa_pod pod;
-+ struct spa_fraction value;
-+};
-+
-+struct spa_pod_bitmap {
-+ struct spa_pod pod;
-+ /* array of uint8_t follows with the bitmap */
-+};
-+
-+#define SPA_POD_ARRAY_CHILD(arr) (&((struct spa_pod_array*)(arr))->body.child)
-+#define SPA_POD_ARRAY_VALUE_TYPE(arr) (SPA_POD_TYPE(SPA_POD_ARRAY_CHILD(arr)))
-+#define SPA_POD_ARRAY_VALUE_SIZE(arr) (SPA_POD_BODY_SIZE(SPA_POD_ARRAY_CHILD(arr)))
-+#define SPA_POD_ARRAY_N_VALUES(arr) ((SPA_POD_BODY_SIZE(arr) - sizeof(struct spa_pod_array_body)) / SPA_POD_ARRAY_VALUE_SIZE(arr))
-+#define SPA_POD_ARRAY_VALUES(arr) SPA_POD_CONTENTS(struct spa_pod_array, arr)
-+
-+struct spa_pod_array_body {
-+ struct spa_pod child;
-+ /* array with elements of child.size follows */
-+};
-+
-+struct spa_pod_array {
-+ struct spa_pod pod;
-+ struct spa_pod_array_body body;
-+};
-+
-+#define SPA_POD_CHOICE_CHILD(choice) (&((struct spa_pod_choice*)(choice))->body.child)
-+#define SPA_POD_CHOICE_TYPE(choice) (((struct spa_pod_choice*)(choice))->body.type)
-+#define SPA_POD_CHOICE_FLAGS(choice) (((struct spa_pod_choice*)(choice))->body.flags)
-+#define SPA_POD_CHOICE_VALUE_TYPE(choice) (SPA_POD_TYPE(SPA_POD_CHOICE_CHILD(choice)))
-+#define SPA_POD_CHOICE_VALUE_SIZE(choice) (SPA_POD_BODY_SIZE(SPA_POD_CHOICE_CHILD(choice)))
-+#define SPA_POD_CHOICE_N_VALUES(choice) ((SPA_POD_BODY_SIZE(choice) - sizeof(struct spa_pod_choice_body)) / SPA_POD_CHOICE_VALUE_SIZE(choice))
-+#define SPA_POD_CHOICE_VALUES(choice) (SPA_POD_CONTENTS(struct spa_pod_choice, choice))
-+
-+enum spa_choice_type {
-+ SPA_CHOICE_None, /**< no choice, first value is current */
-+ SPA_CHOICE_Range, /**< range: default, min, max */
-+ SPA_CHOICE_Step, /**< range with step: default, min, max, step */
-+ SPA_CHOICE_Enum, /**< list: default, alternative,... */
-+ SPA_CHOICE_Flags, /**< flags: default, possible flags,... */
-+};
-+
-+struct spa_pod_choice_body {
-+ uint32_t type; /**< type of choice, one of enum spa_choice_type */
-+ uint32_t flags; /**< extra flags */
-+ struct spa_pod child;
-+ /* array with elements of child.size follows. Note that there might be more
-+ * elements than required by \a type, which should be ignored. */
-+};
-+
-+struct spa_pod_choice {
-+ struct spa_pod pod;
-+ struct spa_pod_choice_body body;
-+};
-+
-+struct spa_pod_struct {
-+ struct spa_pod pod;
-+ /* one or more spa_pod follow */
-+};
-+
-+#define SPA_POD_OBJECT_TYPE(obj) (((struct spa_pod_object*)(obj))->body.type)
-+#define SPA_POD_OBJECT_ID(obj) (((struct spa_pod_object*)(obj))->body.id)
-+
-+struct spa_pod_object_body {
-+ uint32_t type; /**< one of enum spa_type */
-+ uint32_t id; /**< id of the object, depends on the object type */
-+ /* contents follow, series of spa_pod_prop */
-+};
-+
-+struct spa_pod_object {
-+ struct spa_pod pod;
-+ struct spa_pod_object_body body;
-+};
-+
-+struct spa_pod_pointer_body {
-+ uint32_t type; /**< pointer id, one of enum spa_type */
-+ uint32_t _padding;
-+ const void *value;
-+};
-+
-+struct spa_pod_pointer {
-+ struct spa_pod pod;
-+ struct spa_pod_pointer_body body;
-+};
-+
-+struct spa_pod_fd {
-+ struct spa_pod pod;
-+ int64_t value;
-+};
-+
-+#define SPA_POD_PROP_SIZE(prop) (sizeof(struct spa_pod_prop) + (prop)->value.size)
-+
-+/* props can be inside an object */
-+struct spa_pod_prop {
-+ uint32_t key; /**< key of property, list of valid keys depends on the
-+ * object type */
-+#define SPA_POD_PROP_FLAG_READONLY (1u<<0) /**< is read-only */
-+#define SPA_POD_PROP_FLAG_HARDWARE (1u<<1) /**< some sort of hardware parameter */
-+ uint32_t flags; /**< flags for property */
-+ struct spa_pod value;
-+ /* value follows */
-+};
-+
-+#define SPA_POD_CONTROL_SIZE(ev) (sizeof(struct spa_pod_control) + (ev)->value.size)
-+
-+/* controls can be inside a sequence and mark timed values */
-+struct spa_pod_control {
-+ uint32_t offset; /**< media offset */
-+ uint32_t type; /**< type of control, enum spa_control_type */
-+ struct spa_pod value; /**< control value, depends on type */
-+ /* value contents follow */
-+};
-+
-+struct spa_pod_sequence_body {
-+ uint32_t unit;
-+ uint32_t pad;
-+ /* series of struct spa_pod_control follows */
-+};
-+
-+/** a sequence of timed controls */
-+struct spa_pod_sequence {
-+ struct spa_pod pod;
-+ struct spa_pod_sequence_body body;
-+};
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_POD_H */
-diff --git a/third_party/pipewire/spa/pod/vararg.h b/third_party/pipewire/spa/pod/vararg.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/pod/vararg.h
-@@ -0,0 +1,104 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_POD_VARARG_H
-+#define SPA_POD_VARARG_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+
-+#include <spa/pod/pod.h>
-+
-+#define SPA_POD_Prop(key,...) \
-+ key, ##__VA_ARGS__
-+
-+#define SPA_POD_Control(offset,type,...) \
-+ offset, type, ##__VA_ARGS__
-+
-+#define SPA_CHOICE_RANGE(def,min,max) 3,(def),(min),(max)
-+#define SPA_CHOICE_STEP(def,min,max,step) 4,(def),(min),(max),(step)
-+#define SPA_CHOICE_ENUM(n_vals,...) (n_vals),##__VA_ARGS__
-+#define SPA_CHOICE_FLAGS(flags) 1, (flags)
-+#define SPA_CHOICE_BOOL(def) 3,(def),(def),!(def)
-+
-+#define SPA_POD_Bool(val) "b", val
-+#define SPA_POD_CHOICE_Bool(def) "?eb", SPA_CHOICE_BOOL(def)
-+
-+#define SPA_POD_Id(val) "I", val
-+#define SPA_POD_CHOICE_ENUM_Id(n_vals,...) "?eI", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+
-+#define SPA_POD_Int(val) "i", val
-+#define SPA_POD_CHOICE_ENUM_Int(n_vals,...) "?ei", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+#define SPA_POD_CHOICE_RANGE_Int(def,min,max) "?ri", SPA_CHOICE_RANGE(def, min, max)
-+#define SPA_POD_CHOICE_STEP_Int(def,min,max,step) "?si", SPA_CHOICE_STEP(def, min, max, step)
-+#define SPA_POD_CHOICE_FLAGS_Int(flags) "?fi", SPA_CHOICE_FLAGS(flags)
-+
-+#define SPA_POD_Long(val) "l", val
-+#define SPA_POD_CHOICE_ENUM_Long(n_vals,...) "?el", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+#define SPA_POD_CHOICE_RANGE_Long(def,min,max) "?rl", SPA_CHOICE_RANGE(def, min, max)
-+#define SPA_POD_CHOICE_STEP_Long(def,min,max,step) "?sl", SPA_CHOICE_STEP(def, min, max, step)
-+#define SPA_POD_CHOICE_FLAGS_Long(flags) "?fl", SPA_CHOICE_FLAGS(flags)
-+
-+#define SPA_POD_Float(val) "f", val
-+#define SPA_POD_CHOICE_ENUM_Float(n_vals,...) "?ef", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+#define SPA_POD_CHOICE_RANGE_Float(def,min,max) "?rf", SPA_CHOICE_RANGE(def, min, max)
-+#define SPA_POD_CHOICE_STEP_Float(def,min,max,step) "?sf", SPA_CHOICE_STEP(def, min, max, step)
-+
-+#define SPA_POD_Double(val) "d", val
-+#define SPA_POD_CHOICE_ENUM_Double(n_vals,...) "?ed", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+#define SPA_POD_CHOICE_RANGE_Double(def,min,max) "?rd", SPA_CHOICE_RANGE(def, min, max)
-+#define SPA_POD_CHOICE_STEP_Double(def,min,max,step) "?sd", SPA_CHOICE_STEP(def, min, max, step)
-+
-+#define SPA_POD_String(val) "s",val
-+#define SPA_POD_Stringn(val,len) "S",val,len
-+
-+#define SPA_POD_Bytes(val,len) "y",val,len
-+
-+#define SPA_POD_Rectangle(val) "R",val
-+#define SPA_POD_CHOICE_ENUM_Rectangle(n_vals,...) "?eR", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+#define SPA_POD_CHOICE_RANGE_Rectangle(def,min,max) "?rR", SPA_CHOICE_RANGE((def),(min),(max))
-+#define SPA_POD_CHOICE_STEP_Rectangle(def,min,max,step) "?sR", SPA_CHOICE_STEP((def),(min),(max),(step))
-+
-+#define SPA_POD_Fraction(val) "F",val
-+#define SPA_POD_CHOICE_ENUM_Fraction(n_vals,...) "?eF", SPA_CHOICE_ENUM(n_vals, __VA_ARGS__)
-+#define SPA_POD_CHOICE_RANGE_Fraction(def,min,max) "?rF", SPA_CHOICE_RANGE((def),(min),(max))
-+#define SPA_POD_CHOICE_STEP_Fraction(def,min,max,step) "?sF", SPA_CHOICE_STEP(def, min, max, step)
-+
-+#define SPA_POD_Array(csize,ctype,n_vals,vals) "a", csize,ctype,n_vals,vals
-+#define SPA_POD_Pointer(type,val) "p", type,val
-+#define SPA_POD_Fd(val) "h", val
-+#define SPA_POD_None() "P", NULL
-+#define SPA_POD_Pod(val) "P", val
-+#define SPA_POD_PodObject(val) "O", val
-+#define SPA_POD_PodStruct(val) "T", val
-+#define SPA_POD_PodChoice(val) "V", val
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_POD_VARARG_H */
-diff --git a/third_party/pipewire/spa/support/cpu.h b/third_party/pipewire/spa/support/cpu.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/cpu.h
-@@ -0,0 +1,126 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_CPU_H
-+#define SPA_CPU_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+/**
-+ * The CPU features interface
-+ */
-+#define SPA_TYPE_INTERFACE_CPU SPA_TYPE_INFO_INTERFACE_BASE "CPU"
-+
-+#define SPA_VERSION_CPU 0
-+struct spa_cpu { struct spa_interface iface; };
-+
-+/* x86 specific */
-+#define SPA_CPU_FLAG_MMX (1<<0) /**< standard MMX */
-+#define SPA_CPU_FLAG_MMXEXT (1<<1) /**< SSE integer or AMD MMX ext */
-+#define SPA_CPU_FLAG_3DNOW (1<<2) /**< AMD 3DNOW */
-+#define SPA_CPU_FLAG_SSE (1<<3) /**< SSE */
-+#define SPA_CPU_FLAG_SSE2 (1<<4) /**< SSE2 */
-+#define SPA_CPU_FLAG_3DNOWEXT (1<<5) /**< AMD 3DNowExt */
-+#define SPA_CPU_FLAG_SSE3 (1<<6) /**< Prescott SSE3 */
-+#define SPA_CPU_FLAG_SSSE3 (1<<7) /**< Conroe SSSE3 */
-+#define SPA_CPU_FLAG_SSE41 (1<<8) /**< Penryn SSE4.1 */
-+#define SPA_CPU_FLAG_SSE42 (1<<9) /**< Nehalem SSE4.2 */
-+#define SPA_CPU_FLAG_AESNI (1<<10) /**< Advanced Encryption Standard */
-+#define SPA_CPU_FLAG_AVX (1<<11) /**< AVX */
-+#define SPA_CPU_FLAG_XOP (1<<12) /**< Bulldozer XOP */
-+#define SPA_CPU_FLAG_FMA4 (1<<13) /**< Bulldozer FMA4 */
-+#define SPA_CPU_FLAG_CMOV (1<<14) /**< supports cmov */
-+#define SPA_CPU_FLAG_AVX2 (1<<15) /**< AVX2 */
-+#define SPA_CPU_FLAG_FMA3 (1<<16) /**< Haswell FMA3 */
-+#define SPA_CPU_FLAG_BMI1 (1<<17) /**< Bit Manipulation Instruction Set 1 */
-+#define SPA_CPU_FLAG_BMI2 (1<<18) /**< Bit Manipulation Instruction Set 2 */
-+#define SPA_CPU_FLAG_AVX512 (1<<19) /**< AVX-512 */
-+#define SPA_CPU_FLAG_SLOW_UNALIGNED (1<<20) /**< unaligned loads/stores are slow */
-+
-+/* PPC specific */
-+#define SPA_CPU_FLAG_ALTIVEC (1<<0) /**< standard */
-+#define SPA_CPU_FLAG_VSX (1<<1) /**< ISA 2.06 */
-+#define SPA_CPU_FLAG_POWER8 (1<<2) /**< ISA 2.07 */
-+
-+/* ARM specific */
-+#define SPA_CPU_FLAG_ARMV5TE (1 << 0)
-+#define SPA_CPU_FLAG_ARMV6 (1 << 1)
-+#define SPA_CPU_FLAG_ARMV6T2 (1 << 2)
-+#define SPA_CPU_FLAG_VFP (1 << 3)
-+#define SPA_CPU_FLAG_VFPV3 (1 << 4)
-+#define SPA_CPU_FLAG_NEON (1 << 5)
-+#define SPA_CPU_FLAG_ARMV8 (1 << 6)
-+
-+#define SPA_CPU_FORCE_AUTODETECT ((uint32_t)-1)
-+/**
-+ * methods
-+ */
-+struct spa_cpu_methods {
-+ /** the version of the methods. This can be used to expand this
-+ structure in the future */
-+#define SPA_VERSION_CPU_METHODS 0
-+ uint32_t version;
-+
-+ /** get CPU flags */
-+ uint32_t (*get_flags) (void *object);
-+
-+ /** force CPU flags, use SPA_CPU_FORCE_AUTODETECT to autodetect CPU flags */
-+ int (*force_flags) (void *object, uint32_t flags);
-+
-+ /** get number of CPU cores */
-+ uint32_t (*get_count) (void *object);
-+
-+ /** get maximum required alignment of data */
-+ uint32_t (*get_max_align) (void *object);
-+};
-+
-+#define spa_cpu_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_cpu *_c = o; \
-+ spa_interface_call_res(&_c->iface, \
-+ struct spa_cpu_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+#define spa_cpu_get_flags(c) spa_cpu_method(c, get_flags, 0)
-+#define spa_cpu_force_flags(c,f) spa_cpu_method(c, force_flags, 0, f)
-+#define spa_cpu_get_count(c) spa_cpu_method(c, get_count, 0)
-+#define spa_cpu_get_max_align(c) spa_cpu_method(c, get_max_align, 0)
-+
-+/** keys can be given when initializing the cpu handle */
-+#define SPA_KEY_CPU_FORCE "cpu.force" /**< force cpu flags */
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_CPU_H */
-diff --git a/third_party/pipewire/spa/support/dbus.h b/third_party/pipewire/spa/support/dbus.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/dbus.h
-@@ -0,0 +1,100 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DBUS_H
-+#define SPA_DBUS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/support/loop.h>
-+
-+#define SPA_TYPE_INTERFACE_DBus SPA_TYPE_INFO_INTERFACE_BASE "DBus"
-+
-+#define SPA_VERSION_DBUS 0
-+struct spa_dbus { struct spa_interface iface; };
-+
-+enum spa_dbus_type {
-+ SPA_DBUS_TYPE_SESSION, /**< The login session bus */
-+ SPA_DBUS_TYPE_SYSTEM, /**< The systemwide bus */
-+ SPA_DBUS_TYPE_STARTER /**< The bus that started us, if any */
-+};
-+
-+struct spa_dbus_connection {
-+#define SPA_VERSION_DBUS_CONNECTION 0
-+ uint32_t version;
-+ /**
-+ * Get the DBusConnection from a wrapper
-+ *
-+ * \param conn the spa_dbus_connection wrapper
-+ * \return a pointer of type DBusConnection
-+ */
-+ void *(*get) (struct spa_dbus_connection *conn);
-+ /**
-+ * Destroy a dbus connection wrapper
-+ *
-+ * \param conn the wrapper to destroy
-+ */
-+ void (*destroy) (struct spa_dbus_connection *conn);
-+};
-+
-+#define spa_dbus_connection_get(c) (c)->get((c))
-+#define spa_dbus_connection_destroy(c) (c)->destroy((c))
-+
-+struct spa_dbus_methods {
-+#define SPA_VERSION_DBUS_METHODS 0
-+ uint32_t version;
-+
-+ /**
-+ * Get a new connection wrapper for the given bus type.
-+ *
-+ * The connection wrapper is completely configured to operate
-+ * in the main context of the handle that manages the spa_dbus
-+ * interface.
-+ *
-+ * \param dbus the dbus manager
-+ * \param type the bus type to wrap
-+ * \param error location for the DBusError
-+ * \return a new dbus connection wrapper or NULL on error
-+ */
-+ struct spa_dbus_connection * (*get_connection) (void *object,
-+ enum spa_dbus_type type);
-+};
-+
-+static inline struct spa_dbus_connection *
-+spa_dbus_get_connection(struct spa_dbus *dbus, enum spa_dbus_type type)
-+{
-+ struct spa_dbus_connection *res = NULL;
-+ spa_interface_call_res(&dbus->iface,
-+ struct spa_dbus_methods, res,
-+ get_connection, 0, type);
-+ return res;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DBUS_H */
-diff --git a/third_party/pipewire/spa/support/log-impl.h b/third_party/pipewire/spa/support/log-impl.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/log-impl.h
-@@ -0,0 +1,86 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_LOG_IMPL_H
-+#define SPA_LOG_IMPL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdio.h>
-+
-+#include <spa/utils/type.h>
-+#include <spa/support/log.h>
-+
-+static inline SPA_PRINTF_FUNC(6, 0) void spa_log_impl_logv(void *object,
-+ enum spa_log_level level,
-+ const char *file,
-+ int line,
-+ const char *func,
-+ const char *fmt,
-+ va_list args)
-+{
-+ char text[512], location[1024];
-+ static const char *levels[] = { "-", "E", "W", "I", "D", "T" };
-+
-+ vsnprintf(text, sizeof(text), fmt, args);
-+ snprintf(location, sizeof(location), "[%s][%s:%i %s()] %s\n",
-+ levels[level], strrchr(file, '/') + 1, line, func, text);
-+ fputs(location, stderr);
-+}
-+static inline SPA_PRINTF_FUNC(6,7) void spa_log_impl_log(void *object,
-+ enum spa_log_level level,
-+ const char *file,
-+ int line,
-+ const char *func,
-+ const char *fmt, ...)
-+{
-+ va_list args;
-+ va_start(args, fmt);
-+ spa_log_impl_logv(object, level, file, line, func, fmt, args);
-+ va_end(args);
-+}
-+
-+#define SPA_LOG_IMPL_DEFINE(name) \
-+struct { \
-+ struct spa_log log; \
-+ struct spa_log_methods methods; \
-+} name
-+
-+#define SPA_LOG_IMPL_INIT(name) \
-+ { { { SPA_TYPE_INTERFACE_Log, SPA_VERSION_LOG, \
-+ SPA_CALLBACKS_INIT(&name.methods, &name) }, \
-+ SPA_LOG_LEVEL_INFO, }, \
-+ { SPA_VERSION_LOG_METHODS, \
-+ spa_log_impl_log, \
-+ spa_log_impl_logv,} }
-+
-+#define SPA_LOG_IMPL(name) \
-+ SPA_LOG_IMPL_DEFINE(name) = SPA_LOG_IMPL_INIT(name)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+#endif /* SPA_LOG_IMPL_H */
-diff --git a/third_party/pipewire/spa/support/log.h b/third_party/pipewire/spa/support/log.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/log.h
-@@ -0,0 +1,179 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_LOG_H
-+#define SPA_LOG_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <stdarg.h>
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+enum spa_log_level {
-+ SPA_LOG_LEVEL_NONE = 0,
-+ SPA_LOG_LEVEL_ERROR,
-+ SPA_LOG_LEVEL_WARN,
-+ SPA_LOG_LEVEL_INFO,
-+ SPA_LOG_LEVEL_DEBUG,
-+ SPA_LOG_LEVEL_TRACE,
-+};
-+
-+/**
-+ * The Log interface
-+ */
-+#define SPA_TYPE_INTERFACE_Log SPA_TYPE_INFO_INTERFACE_BASE "Log"
-+
-+#define SPA_VERSION_LOG 0
-+
-+struct spa_log {
-+ /** the version of this log. This can be used to expand this
-+ * structure in the future */
-+ struct spa_interface iface;
-+ /**
-+ * Logging level, everything above this level is not logged
-+ */
-+ enum spa_log_level level;
-+};
-+
-+struct spa_log_methods {
-+#define SPA_VERSION_LOG_METHODS 0
-+ uint32_t version;
-+ /**
-+ * Log a message with the given log level.
-+ *
-+ * \param log a spa_log
-+ * \param level a spa_log_level
-+ * \param file the file name
-+ * \param line the line number
-+ * \param func the function name
-+ * \param fmt printf style format
-+ * \param ... format arguments
-+ */
-+ void (*log) (void *object,
-+ enum spa_log_level level,
-+ const char *file,
-+ int line,
-+ const char *func,
-+ const char *fmt, ...) SPA_PRINTF_FUNC(6, 7);
-+
-+ /**
-+ * Log a message with the given log level.
-+ *
-+ * \param log a spa_log
-+ * \param level a spa_log_level
-+ * \param file the file name
-+ * \param line the line number
-+ * \param func the function name
-+ * \param fmt printf style format
-+ * \param args format arguments
-+ */
-+ void (*logv) (void *object,
-+ enum spa_log_level level,
-+ const char *file,
-+ int line,
-+ const char *func,
-+ const char *fmt,
-+ va_list args) SPA_PRINTF_FUNC(6, 0);
-+};
-+
-+#define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev))
-+
-+#if defined(__USE_ISOC11) || defined(__USE_ISOC99) || \
-+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
-+
-+#define spa_log_log(l,lev,...) \
-+({ \
-+ struct spa_log *_l = l; \
-+ if (SPA_UNLIKELY(spa_log_level_enabled(_l, lev))) \
-+ spa_interface_call(&_l->iface, \
-+ struct spa_log_methods, log, 0, lev, \
-+ __VA_ARGS__); \
-+})
-+
-+#define spa_log_logv(l,lev,...) \
-+({ \
-+ struct spa_log *_l = l; \
-+ if (SPA_UNLIKELY(spa_log_level_enabled(_l, lev))) \
-+ spa_interface_call(&_l->iface, \
-+ struct spa_log_methods, logv, 0, lev, \
-+ __VA_ARGS__); \
-+})
-+
-+#define spa_log_error(l,...) spa_log_log(l,SPA_LOG_LEVEL_ERROR,__FILE__,__LINE__,__func__,__VA_ARGS__)
-+#define spa_log_warn(l,...) spa_log_log(l,SPA_LOG_LEVEL_WARN,__FILE__,__LINE__,__func__,__VA_ARGS__)
-+#define spa_log_info(l,...) spa_log_log(l,SPA_LOG_LEVEL_INFO,__FILE__,__LINE__,__func__,__VA_ARGS__)
-+#define spa_log_debug(l,...) spa_log_log(l,SPA_LOG_LEVEL_DEBUG,__FILE__,__LINE__,__func__,__VA_ARGS__)
-+#define spa_log_trace(l,...) spa_log_log(l,SPA_LOG_LEVEL_TRACE,__FILE__,__LINE__,__func__,__VA_ARGS__)
-+
-+#ifndef FASTPATH
-+#define spa_log_trace_fp(l,...) spa_log_log(l,SPA_LOG_LEVEL_TRACE,__FILE__,__LINE__,__func__,__VA_ARGS__)
-+#else
-+#define spa_log_trace_fp(l,...)
-+#endif
-+
-+#else
-+
-+#define SPA_LOG_FUNC(name,lev) \
-+static inline SPA_PRINTF_FUNC(2,3) void spa_log_##name (struct spa_log *l, const char *format, ...) \
-+{ \
-+ if (SPA_UNLIKELY(spa_log_level_enabled(l, lev))) { \
-+ va_list varargs; \
-+ va_start (varargs, format); \
-+ spa_interface_call(&l->iface, \
-+ struct spa_log_methods, logv, 0, lev, \
-+ __FILE__,__LINE__,__func__,format,varargs); \
-+ va_end (varargs); \
-+ } \
-+}
-+
-+SPA_LOG_FUNC(error, SPA_LOG_LEVEL_ERROR)
-+SPA_LOG_FUNC(warn, SPA_LOG_LEVEL_WARN)
-+SPA_LOG_FUNC(info, SPA_LOG_LEVEL_INFO)
-+SPA_LOG_FUNC(debug, SPA_LOG_LEVEL_DEBUG)
-+SPA_LOG_FUNC(trace, SPA_LOG_LEVEL_TRACE)
-+
-+#ifndef FASTPATH
-+SPA_LOG_FUNC(trace_fp, SPA_LOG_LEVEL_TRACE)
-+#else
-+static inline void spa_log_trace_fp (struct spa_log *l, const char *format, ...) { }
-+#endif
-+
-+#endif
-+
-+/** keys can be given when initializing the logger handle */
-+#define SPA_KEY_LOG_LEVEL "log.level" /**< the default log level */
-+#define SPA_KEY_LOG_COLORS "log.colors" /**< enable colors in the logger */
-+#define SPA_KEY_LOG_FILE "log.file" /**< log to the specified file instead of
-+ * stderr. */
-+#define SPA_KEY_LOG_TIMESTAMP "log.timestamp" /**< log timestamps */
-+#define SPA_KEY_LOG_LINE "log.line" /**< log file and line numbers */
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+#endif /* SPA_LOG_H */
-diff --git a/third_party/pipewire/spa/support/loop.h b/third_party/pipewire/spa/support/loop.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/loop.h
-@@ -0,0 +1,312 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_LOOP_H
-+#define SPA_LOOP_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+#include <spa/support/system.h>
-+
-+#define SPA_TYPE_INTERFACE_Loop SPA_TYPE_INFO_INTERFACE_BASE "Loop"
-+#define SPA_TYPE_INTERFACE_DataLoop SPA_TYPE_INFO_INTERFACE_BASE "DataLoop"
-+#define SPA_VERSION_LOOP 0
-+struct spa_loop { struct spa_interface iface; };
-+
-+#define SPA_TYPE_INTERFACE_LoopControl SPA_TYPE_INFO_INTERFACE_BASE "LoopControl"
-+#define SPA_VERSION_LOOP_CONTROL 0
-+struct spa_loop_control { struct spa_interface iface; };
-+
-+#define SPA_TYPE_INTERFACE_LoopUtils SPA_TYPE_INFO_INTERFACE_BASE "LoopUtils"
-+#define SPA_VERSION_LOOP_UTILS 0
-+struct spa_loop_utils { struct spa_interface iface; };
-+
-+struct spa_source;
-+
-+typedef void (*spa_source_func_t) (struct spa_source *source);
-+
-+struct spa_source {
-+ struct spa_loop *loop;
-+ spa_source_func_t func;
-+ void *data;
-+ int fd;
-+ uint32_t mask;
-+ uint32_t rmask;
-+};
-+
-+typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
-+ bool async,
-+ uint32_t seq,
-+ const void *data,
-+ size_t size,
-+ void *user_data);
-+
-+/**
-+ * Register sources and work items to an event loop
-+ */
-+struct spa_loop_methods {
-+ /* the version of this structure. This can be used to expand this
-+ * structure in the future */
-+#define SPA_VERSION_LOOP_METHODS 0
-+ uint32_t version;
-+
-+ /** add a source to the loop */
-+ int (*add_source) (void *object,
-+ struct spa_source *source);
-+
-+ /** update the source io mask */
-+ int (*update_source) (void *object,
-+ struct spa_source *source);
-+
-+ /** remove a source from the loop */
-+ int (*remove_source) (void *object,
-+ struct spa_source *source);
-+
-+ /** invoke a function in the context of this loop */
-+ int (*invoke) (void *object,
-+ spa_invoke_func_t func,
-+ uint32_t seq,
-+ const void *data,
-+ size_t size,
-+ bool block,
-+ void *user_data);
-+};
-+
-+#define spa_loop_method(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_loop *_o = o; \
-+ spa_interface_call_res(&_o->iface, \
-+ struct spa_loop_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define spa_loop_add_source(l,...) spa_loop_method(l,add_source,0,##__VA_ARGS__)
-+#define spa_loop_update_source(l,...) spa_loop_method(l,update_source,0,##__VA_ARGS__)
-+#define spa_loop_remove_source(l,...) spa_loop_method(l,remove_source,0,##__VA_ARGS__)
-+#define spa_loop_invoke(l,...) spa_loop_method(l,invoke,0,##__VA_ARGS__)
-+
-+
-+/** Control hooks. These hooks can't be removed from their
-+ * callbacks and must be removed from a safe place (when the loop
-+ * is not running or when it is locked). */
-+struct spa_loop_control_hooks {
-+#define SPA_VERSION_LOOP_CONTROL_HOOKS 0
-+ uint32_t version;
-+ /** Executed right before waiting for events. It is typically used to
-+ * release locks. */
-+ void (*before) (void *data);
-+ /** Executed right after waiting for events. It is typically used to
-+ * reacquire locks. */
-+ void (*after) (void *data);
-+};
-+
-+#define spa_loop_control_hook_before(l) \
-+({ \
-+ struct spa_hook_list *_l = l; \
-+ struct spa_hook *_h; \
-+ spa_list_for_each_reverse(_h, &_l->list, link) \
-+ spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, before, 0); \
-+})
-+
-+#define spa_loop_control_hook_after(l) \
-+({ \
-+ struct spa_hook_list *_l = l; \
-+ struct spa_hook *_h; \
-+ spa_list_for_each(_h, &_l->list, link) \
-+ spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, after, 0); \
-+})
-+
-+/**
-+ * Control an event loop
-+ */
-+struct spa_loop_control_methods {
-+ /* the version of this structure. This can be used to expand this
-+ * structure in the future */
-+#define SPA_VERSION_LOOP_CONTROL_METHODS 0
-+ uint32_t version;
-+
-+ int (*get_fd) (void *object);
-+
-+ /** Add a hook
-+ * \param ctrl the control to change
-+ * \param hooks the hooks to add
-+ *
-+ * Adds hooks to the loop controlled by \a ctrl.
-+ */
-+ void (*add_hook) (void *object,
-+ struct spa_hook *hook,
-+ const struct spa_loop_control_hooks *hooks,
-+ void *data);
-+
-+ /** Enter a loop
-+ * \param ctrl the control
-+ *
-+ * Start an iteration of the loop. This function should be called
-+ * before calling iterate and is typically used to capture the thread
-+ * that this loop will run in.
-+ */
-+ void (*enter) (void *object);
-+ /** Leave a loop
-+ * \param ctrl the control
-+ *
-+ * Ends the iteration of a loop. This should be called after calling
-+ * iterate.
-+ */
-+ void (*leave) (void *object);
-+
-+ /** Perform one iteration of the loop.
-+ * \param ctrl the control
-+ * \param timeout an optional timeout in milliseconds.
-+ * 0 for no timeout, -1 for infinite timeout.
-+ *
-+ * This function will block
-+ * up to \a timeout milliseconds and then dispatch the fds with activity.
-+ * The number of dispatched fds is returned.
-+ */
-+ int (*iterate) (void *object, int timeout);
-+};
-+
-+#define spa_loop_control_method_v(o,method,version,...) \
-+({ \
-+ struct spa_loop_control *_o = o; \
-+ spa_interface_call(&_o->iface, \
-+ struct spa_loop_control_methods, \
-+ method, version, ##__VA_ARGS__); \
-+})
-+
-+#define spa_loop_control_method_r(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_loop_control *_o = o; \
-+ spa_interface_call_res(&_o->iface, \
-+ struct spa_loop_control_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+#define spa_loop_control_get_fd(l) spa_loop_control_method_r(l,get_fd,0)
-+#define spa_loop_control_add_hook(l,...) spa_loop_control_method_v(l,add_hook,0,__VA_ARGS__)
-+#define spa_loop_control_enter(l) spa_loop_control_method_v(l,enter,0)
-+#define spa_loop_control_leave(l) spa_loop_control_method_v(l,leave,0)
-+#define spa_loop_control_iterate(l,...) spa_loop_control_method_r(l,iterate,0,__VA_ARGS__)
-+
-+typedef void (*spa_source_io_func_t) (void *data, int fd, uint32_t mask);
-+typedef void (*spa_source_idle_func_t) (void *data);
-+typedef void (*spa_source_event_func_t) (void *data, uint64_t count);
-+typedef void (*spa_source_timer_func_t) (void *data, uint64_t expirations);
-+typedef void (*spa_source_signal_func_t) (void *data, int signal_number);
-+
-+/**
-+ * Create sources for an event loop
-+ */
-+struct spa_loop_utils_methods {
-+ /* the version of this structure. This can be used to expand this
-+ * structure in the future */
-+#define SPA_VERSION_LOOP_UTILS_METHODS 0
-+ uint32_t version;
-+
-+ struct spa_source *(*add_io) (void *object,
-+ int fd,
-+ uint32_t mask,
-+ bool close,
-+ spa_source_io_func_t func, void *data);
-+
-+ int (*update_io) (void *object, struct spa_source *source, uint32_t mask);
-+
-+ struct spa_source *(*add_idle) (void *object,
-+ bool enabled,
-+ spa_source_idle_func_t func, void *data);
-+ int (*enable_idle) (void *object, struct spa_source *source, bool enabled);
-+
-+ struct spa_source *(*add_event) (void *object,
-+ spa_source_event_func_t func, void *data);
-+ int (*signal_event) (void *object, struct spa_source *source);
-+
-+ struct spa_source *(*add_timer) (void *object,
-+ spa_source_timer_func_t func, void *data);
-+ int (*update_timer) (void *object,
-+ struct spa_source *source,
-+ struct timespec *value,
-+ struct timespec *interval,
-+ bool absolute);
-+ struct spa_source *(*add_signal) (void *object,
-+ int signal_number,
-+ spa_source_signal_func_t func, void *data);
-+
-+ /** destroy a source allocated with this interface. This function
-+ * should only be called when the loop is not running or from the
-+ * context of the running loop */
-+ void (*destroy_source) (void *object, struct spa_source *source);
-+};
-+
-+#define spa_loop_utils_method_v(o,method,version,...) \
-+({ \
-+ struct spa_loop_utils *_o = o; \
-+ spa_interface_call(&_o->iface, \
-+ struct spa_loop_utils_methods, \
-+ method, version, ##__VA_ARGS__); \
-+})
-+
-+#define spa_loop_utils_method_r(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_loop_utils *_o = o; \
-+ spa_interface_call_res(&_o->iface, \
-+ struct spa_loop_utils_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+#define spa_loop_utils_method_s(o,method,version,...) \
-+({ \
-+ struct spa_source *_res = NULL; \
-+ struct spa_loop_utils *_o = o; \
-+ spa_interface_call_res(&_o->iface, \
-+ struct spa_loop_utils_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+
-+#define spa_loop_utils_add_io(l,...) spa_loop_utils_method_s(l,add_io,0,__VA_ARGS__)
-+#define spa_loop_utils_update_io(l,...) spa_loop_utils_method_r(l,update_io,0,__VA_ARGS__)
-+#define spa_loop_utils_add_idle(l,...) spa_loop_utils_method_s(l,add_idle,0,__VA_ARGS__)
-+#define spa_loop_utils_enable_idle(l,...) spa_loop_utils_method_r(l,enable_idle,0,__VA_ARGS__)
-+#define spa_loop_utils_add_event(l,...) spa_loop_utils_method_s(l,add_event,0,__VA_ARGS__)
-+#define spa_loop_utils_signal_event(l,...) spa_loop_utils_method_r(l,signal_event,0,__VA_ARGS__)
-+#define spa_loop_utils_add_timer(l,...) spa_loop_utils_method_s(l,add_timer,0,__VA_ARGS__)
-+#define spa_loop_utils_update_timer(l,...) spa_loop_utils_method_r(l,update_timer,0,__VA_ARGS__)
-+#define spa_loop_utils_add_signal(l,...) spa_loop_utils_method_s(l,add_signal,0,__VA_ARGS__)
-+#define spa_loop_utils_destroy_source(l,...) spa_loop_utils_method_v(l,destroy_source,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_LOOP_H */
-diff --git a/third_party/pipewire/spa/support/plugin.h b/third_party/pipewire/spa/support/plugin.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/plugin.h
-@@ -0,0 +1,215 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_PLUGIN_H
-+#define SPA_PLUGIN_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/dict.h>
-+
-+struct spa_handle {
-+ /** Version of this struct */
-+#define SPA_VERSION_HANDLE 0
-+ uint32_t version;
-+
-+ /**
-+ * Get the interface provided by \a handle with \a type.
-+ *
-+ * \a interface is always a struct spa_interface but depending on
-+ * \a type, the struct might contain other information.
-+ *
-+ * \param handle a spa_handle
-+ * \param type the interface type
-+ * \param interface result to hold the interface.
-+ * \return 0 on success
-+ * -ENOTSUP when there are no interfaces
-+ * -EINVAL when handle or info is NULL
-+ */
-+ int (*get_interface) (struct spa_handle *handle, const char *type, void **interface);
-+ /**
-+ * Clean up the memory of \a handle. After this, \a handle should not be used
-+ * anymore.
-+ *
-+ * \param handle a pointer to memory
-+ * \return 0 on success
-+ */
-+ int (*clear) (struct spa_handle *handle);
-+};
-+
-+#define spa_handle_get_interface(h,...) (h)->get_interface((h),__VA_ARGS__)
-+#define spa_handle_clear(h) (h)->clear((h))
-+
-+/**
-+ * This structure lists the information about available interfaces on
-+ * handles.
-+ */
-+struct spa_interface_info {
-+ const char *type; /*< the type of the interface, can be
-+ * used to get the interface */
-+};
-+
-+/**
-+ * Extra supporting infrastructure passed to the init() function of
-+ * a factory. It can be extra information or interfaces such as logging.
-+ */
-+struct spa_support {
-+ const char *type; /*< the type of the support item */
-+ void *data; /*< specific data for the item */
-+};
-+
-+/** Find a support item of the given type */
-+static inline void *spa_support_find(const struct spa_support *support,
-+ uint32_t n_support,
-+ const char *type)
-+{
-+ uint32_t i;
-+ for (i = 0; i < n_support; i++) {
-+ if (strcmp(support[i].type, type) == 0)
-+ return support[i].data;
-+ }
-+ return NULL;
-+}
-+
-+#define SPA_SUPPORT_INIT(type,data) (struct spa_support) { (type), (data) }
-+
-+struct spa_handle_factory {
-+ /** The version of this structure */
-+#define SPA_VERSION_HANDLE_FACTORY 1
-+ uint32_t version;
-+ /**
-+ * The name of the factory contains a logical name that describes
-+ * the function of the handle. Other plugins might contain an alternative
-+ * implementation with the same name.
-+ *
-+ * See utils/names.h for the list of standard names.
-+ *
-+ * Examples include:
-+ *
-+ * api.alsa.pcm.sink: an object to write PCM samples to an alsa PLAYBACK
-+ * device
-+ * api.v4l2.source: an object to read from a v4l2 source.
-+ */
-+ const char *name;
-+ /**
-+ * Extra information about the handles of this factory.
-+ */
-+ const struct spa_dict *info;
-+ /**
-+ * Get the size of handles from this factory.
-+ *
-+ * \param factory a spa_handle_factory
-+ * \param params extra parameters that determine the size of the
-+ * handle.
-+ */
-+ size_t (*get_size) (const struct spa_handle_factory *factory,
-+ const struct spa_dict *params);
-+
-+ /**
-+ * Initialize an instance of this factory. The caller should allocate
-+ * memory at least size bytes and pass this as \a handle.
-+ *
-+ * \a support can optionally contain extra interfaces or data items that the
-+ * plugin can use such as a logger.
-+ *
-+ * \param factory a spa_handle_factory
-+ * \param handle a pointer to memory
-+ * \param info extra handle specific information, usually obtained
-+ * from a spa_device. This can be used to configure the handle.
-+ * \param support support items
-+ * \param n_support number of elements in \a support
-+ * \return 0 on success
-+ * < 0 errno type error
-+ */
-+ int (*init) (const struct spa_handle_factory *factory,
-+ struct spa_handle *handle,
-+ const struct spa_dict *info,
-+ const struct spa_support *support,
-+ uint32_t n_support);
-+
-+ /**
-+ * spa_handle_factory::enum_interface_info:
-+ * \param factory: a #spa_handle_factory
-+ * \param info: result to hold spa_interface_info.
-+ * \param index: index to keep track of the enumeration, 0 for first item
-+ *
-+ * Enumerate the interface information for \a factory.
-+ *
-+ * \return 1 when an item is available
-+ * 0 when no more items are available
-+ * < 0 errno type error
-+ */
-+ int (*enum_interface_info) (const struct spa_handle_factory *factory,
-+ const struct spa_interface_info **info,
-+ uint32_t *index);
-+};
-+
-+#define spa_handle_factory_get_size(h,...) (h)->get_size((h),__VA_ARGS__)
-+#define spa_handle_factory_init(h,...) (h)->init((h),__VA_ARGS__)
-+#define spa_handle_factory_enum_interface_info(h,...) (h)->enum_interface_info((h),__VA_ARGS__)
-+
-+/**
-+ * The function signature of the entry point in a plugin.
-+ *
-+ * \param factory a location to hold the factory result
-+ * \param index index to keep track of the enumeration
-+ * \return 1 on success
-+ * 0 when there are no more factories
-+ * -EINVAL when factory is NULL
-+ */
-+typedef int (*spa_handle_factory_enum_func_t) (const struct spa_handle_factory **factory,
-+ uint32_t *index);
-+
-+#define SPA_HANDLE_FACTORY_ENUM_FUNC_NAME "spa_handle_factory_enum"
-+
-+/**
-+ * The entry point in a plugin.
-+ *
-+ * \param factory a location to hold the factory result
-+ * \param index index to keep track of the enumeration
-+ * \return 1 on success
-+ * 0 when no more items are available
-+ * < 0 errno type error
-+ */
-+int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index);
-+
-+
-+
-+#define SPA_KEY_FACTORY_NAME "factory.name" /**< the name of a factory */
-+#define SPA_KEY_FACTORY_AUTHOR "factory.author" /**< a comma separated list of factory authors */
-+#define SPA_KEY_FACTORY_DESCRIPTION "factory.description" /**< description of a factory */
-+#define SPA_KEY_FACTORY_USAGE "factory.usage" /**< usage of a factory */
-+
-+#define SPA_KEY_LIBRARY_NAME "library.name" /**< the name of a library. This is usually
-+ * the filename of the plugin without the
-+ * path or the plugin extension. */
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_PLUGIN_H */
-diff --git a/third_party/pipewire/spa/support/system.h b/third_party/pipewire/spa/support/system.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/support/system.h
-@@ -0,0 +1,152 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_SYSTEM_H
-+#define SPA_SYSTEM_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+struct itimerspec;
-+
-+#include <time.h>
-+#include <sys/types.h>
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/hook.h>
-+
-+/**
-+ * a collection of core system functions
-+ */
-+#define SPA_TYPE_INTERFACE_System SPA_TYPE_INFO_INTERFACE_BASE "System"
-+#define SPA_TYPE_INTERFACE_DataSystem SPA_TYPE_INFO_INTERFACE_BASE "DataSystem"
-+
-+#define SPA_VERSION_SYSTEM 0
-+struct spa_system { struct spa_interface iface; };
-+
-+/* IO events */
-+#define SPA_IO_IN (1 << 0)
-+#define SPA_IO_OUT (1 << 2)
-+#define SPA_IO_ERR (1 << 3)
-+#define SPA_IO_HUP (1 << 4)
-+
-+/* flags */
-+#define SPA_FD_CLOEXEC (1<<0)
-+#define SPA_FD_NONBLOCK (1<<1)
-+#define SPA_FD_EVENT_SEMAPHORE (1<<2)
-+#define SPA_FD_TIMER_ABSTIME (1<<3)
-+#define SPA_FD_TIMER_CANCEL_ON_SET (1<<4)
-+
-+struct spa_poll_event {
-+ uint32_t events;
-+ void *data;
-+};
-+
-+struct spa_system_methods {
-+#define SPA_VERSION_SYSTEM_METHODS 0
-+ uint32_t version;
-+
-+ /* read/write/ioctl */
-+ ssize_t (*read) (void *object, int fd, void *buf, size_t count);
-+ ssize_t (*write) (void *object, int fd, const void *buf, size_t count);
-+ int (*ioctl) (void *object, int fd, unsigned long request, ...);
-+ int (*close) (void *object, int fd);
-+
-+ /* clock */
-+ int (*clock_gettime) (void *object,
-+ int clockid, struct timespec *value);
-+ int (*clock_getres) (void *object,
-+ int clockid, struct timespec *res);
-+
-+ /* poll */
-+ int (*pollfd_create) (void *object, int flags);
-+ int (*pollfd_add) (void *object, int pfd, int fd, uint32_t events, void *data);
-+ int (*pollfd_mod) (void *object, int pfd, int fd, uint32_t events, void *data);
-+ int (*pollfd_del) (void *object, int pfd, int fd);
-+ int (*pollfd_wait) (void *object, int pfd,
-+ struct spa_poll_event *ev, int n_ev, int timeout);
-+
-+ /* timers */
-+ int (*timerfd_create) (void *object, int clockid, int flags);
-+ int (*timerfd_settime) (void *object,
-+ int fd, int flags,
-+ const struct itimerspec *new_value,
-+ struct itimerspec *old_value);
-+ int (*timerfd_gettime) (void *object,
-+ int fd, struct itimerspec *curr_value);
-+ int (*timerfd_read) (void *object, int fd, uint64_t *expirations);
-+
-+ /* events */
-+ int (*eventfd_create) (void *object, int flags);
-+ int (*eventfd_write) (void *object, int fd, uint64_t count);
-+ int (*eventfd_read) (void *object, int fd, uint64_t *count);
-+
-+ /* signals */
-+ int (*signalfd_create) (void *object, int signal, int flags);
-+ int (*signalfd_read) (void *object, int fd, int *signal);
-+};
-+
-+#define spa_system_method_r(o,method,version,...) \
-+({ \
-+ int _res = -ENOTSUP; \
-+ struct spa_system *_o = o; \
-+ spa_interface_call_res(&_o->iface, \
-+ struct spa_system_methods, _res, \
-+ method, version, ##__VA_ARGS__); \
-+ _res; \
-+})
-+
-+
-+#define spa_system_read(s,...) spa_system_method_r(s,read,0,__VA_ARGS__)
-+#define spa_system_write(s,...) spa_system_method_r(s,write,0,__VA_ARGS__)
-+#define spa_system_ioctl(s,...) spa_system_method_r(s,ioctl,0,__VA_ARGS__)
-+#define spa_system_close(s,...) spa_system_method_r(s,close,0,__VA_ARGS__)
-+
-+#define spa_system_clock_gettime(s,...) spa_system_method_r(s,clock_gettime,0,__VA_ARGS__)
-+#define spa_system_clock_getres(s,...) spa_system_method_r(s,clock_getres,0,__VA_ARGS__)
-+
-+#define spa_system_pollfd_create(s,...) spa_system_method_r(s,pollfd_create,0,__VA_ARGS__)
-+#define spa_system_pollfd_add(s,...) spa_system_method_r(s,pollfd_add,0,__VA_ARGS__)
-+#define spa_system_pollfd_mod(s,...) spa_system_method_r(s,pollfd_mod,0,__VA_ARGS__)
-+#define spa_system_pollfd_del(s,...) spa_system_method_r(s,pollfd_del,0,__VA_ARGS__)
-+#define spa_system_pollfd_wait(s,...) spa_system_method_r(s,pollfd_wait,0,__VA_ARGS__)
-+
-+#define spa_system_timerfd_create(s,...) spa_system_method_r(s,timerfd_create,0,__VA_ARGS__)
-+#define spa_system_timerfd_settime(s,...) spa_system_method_r(s,timerfd_settime,0,__VA_ARGS__)
-+#define spa_system_timerfd_gettime(s,...) spa_system_method_r(s,timerfd_gettime,0,__VA_ARGS__)
-+#define spa_system_timerfd_read(s,...) spa_system_method_r(s,timerfd_read,0,__VA_ARGS__)
-+
-+#define spa_system_eventfd_create(s,...) spa_system_method_r(s,eventfd_create,0,__VA_ARGS__)
-+#define spa_system_eventfd_write(s,...) spa_system_method_r(s,eventfd_write,0,__VA_ARGS__)
-+#define spa_system_eventfd_read(s,...) spa_system_method_r(s,eventfd_read,0,__VA_ARGS__)
-+
-+#define spa_system_signalfd_create(s,...) spa_system_method_r(s,signalfd_create,0,__VA_ARGS__)
-+#define spa_system_signalfd_read(s,...) spa_system_method_r(s,signalfd_read,0,__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_SYSTEM_H */
-diff --git a/third_party/pipewire/spa/utils/defs.h b/third_party/pipewire/spa/utils/defs.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/defs.h
-@@ -0,0 +1,265 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_UTILS_DEFS_H
-+#define SPA_UTILS_DEFS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#else
-+#include <stdbool.h>
-+#endif
-+#include <inttypes.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <stddef.h>
-+#include <stdio.h>
-+
-+#define SPA_FLAG_MASK(field,mask,flag) (((field) & (mask)) == (flag))
-+#define SPA_FLAG_IS_SET(field,flag) SPA_FLAG_MASK(field,flag,flag)
-+#define SPA_FLAG_SET(field,flag) ((field) |= (flag))
-+#define SPA_FLAG_CLEAR(field,flag) ((field) &= ~(flag))
-+#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET(field,flag) : SPA_FLAG_CLEAR(field,flag))
-+
-+enum spa_direction {
-+ SPA_DIRECTION_INPUT = 0,
-+ SPA_DIRECTION_OUTPUT = 1,
-+};
-+
-+#define SPA_DIRECTION_REVERSE(d) ((d) ^ 1)
-+
-+#define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height }
-+struct spa_rectangle {
-+ uint32_t width;
-+ uint32_t height;
-+};
-+
-+#define SPA_POINT(x,y) (struct spa_point){ x, y }
-+struct spa_point {
-+ int32_t x;
-+ int32_t y;
-+};
-+
-+#define SPA_REGION(x,y,width,height) (struct spa_region){ SPA_POINT(x,y), SPA_RECTANGLE(width,height) }
-+struct spa_region {
-+ struct spa_point position;
-+ struct spa_rectangle size;
-+};
-+
-+#define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom }
-+struct spa_fraction {
-+ uint32_t num;
-+ uint32_t denom;
-+};
-+
-+#define SPA_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
-+
-+#define SPA_MIN(a,b) \
-+({ \
-+ __typeof__(a) _a = (a); \
-+ __typeof__(b) _b = (b); \
-+ SPA_LIKELY(_a < _b) ? _a : _b; \
-+})
-+#define SPA_MAX(a,b) \
-+({ \
-+ __typeof__(a) _a = (a); \
-+ __typeof__(b) _b = (b); \
-+ SPA_LIKELY(_a > _b) ? _a : _b; \
-+})
-+#define SPA_CLAMP(v,low,high) \
-+({ \
-+ __typeof__(v) _v = (v); \
-+ __typeof__(low) _low = (low); \
-+ __typeof__(high) _high = (high); \
-+ SPA_MIN(SPA_MAX(_v, _low), _high); \
-+})
-+
-+#define SPA_SWAP(a,b) \
-+({ \
-+ __typeof__(a) _t = (a); \
-+ a = b; b = _t; \
-+})
-+
-+#define SPA_TYPECHECK(type,x) \
-+({ type _dummy; \
-+ typeof(x) _dummy2; \
-+ (void)(&_dummy == &_dummy2); \
-+ x; \
-+})
-+
-+#define SPA_MEMBER(b,o,t) ((t*)((uint8_t*)(b) + (int)(o)))
-+#define SPA_MEMBER_ALIGN(b,o,a,t) SPA_PTR_ALIGN(SPA_MEMBER(b,o,t),a,t)
-+
-+#define SPA_CONTAINER_OF(p,t,m) (t*)((uint8_t*)p - offsetof (t,m))
-+
-+#define SPA_PTRDIFF(p1,p2) ((uint8_t*)(p1) - (uint8_t*)(p2))
-+
-+#define SPA_PTR_TO_INT(p) ((int) ((intptr_t) (p)))
-+#define SPA_INT_TO_PTR(u) ((void*) ((intptr_t) (u)))
-+
-+#define SPA_PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
-+#define SPA_UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))
-+
-+#define SPA_TIME_INVALID ((int64_t)INT64_MIN)
-+#define SPA_IDX_INVALID ((unsigned int)-1)
-+#define SPA_ID_INVALID ((uint32_t)0xffffffff)
-+
-+#define SPA_NSEC_PER_SEC (1000000000ll)
-+#define SPA_NSEC_PER_MSEC (1000000ll)
-+#define SPA_NSEC_PER_USEC (1000ll)
-+#define SPA_USEC_PER_SEC (1000000ll)
-+#define SPA_USEC_PER_MSEC (1000ll)
-+#define SPA_MSEC_PER_SEC (1000ll)
-+
-+#define SPA_TIMESPEC_TO_NSEC(ts) ((ts)->tv_sec * SPA_NSEC_PER_SEC + (ts)->tv_nsec)
-+#define SPA_TIMESPEC_TO_USEC(ts) ((ts)->tv_sec * SPA_USEC_PER_SEC + (ts)->tv_nsec / SPA_NSEC_PER_USEC)
-+#define SPA_TIMEVAL_TO_NSEC(tv) ((tv)->tv_sec * SPA_NSEC_PER_SEC + (tv)->tv_usec * SPA_NSEC_PER_USEC)
-+#define SPA_TIMEVAL_TO_USEC(tv) ((tv)->tv_sec * SPA_USEC_PER_SEC + (tv)->tv_usec)
-+
-+#ifdef __GNUC__
-+#define SPA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
-+#define SPA_ALIGNED(align) __attribute__((aligned(align)))
-+#define SPA_DEPRECATED __attribute__ ((deprecated))
-+#define SPA_EXPORT __attribute__((visibility("default")))
-+#define SPA_SENTINEL __attribute__((__sentinel__))
-+#define SPA_UNUSED __attribute__ ((unused))
-+#else
-+#define SPA_PRINTF_FUNC(fmt, arg1)
-+#define SPA_ALIGNED(align)
-+#define SPA_DEPRECATED
-+#define SPA_EXPORT
-+#define SPA_SENTINEL
-+#define SPA_UNUSED
-+#endif
-+
-+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-+#define SPA_RESTRICT restrict
-+#elif defined(__GNUC__) && __GNUC__ >= 4
-+#define SPA_RESTRICT __restrict__
-+#else
-+#define SPA_RESTRICT
-+#endif
-+
-+#define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1))
-+#define SPA_ROUND_UP_N(num,align) SPA_ROUND_DOWN_N((num) + ((align) - 1),align)
-+
-+#define SPA_PTR_ALIGNMENT(p,align) ((intptr_t)(p) & ((align)-1))
-+#define SPA_IS_ALIGNED(p,align) (SPA_PTR_ALIGNMENT(p,align) == 0)
-+#define SPA_PTR_ALIGN(p,align,type) (type*)SPA_ROUND_UP_N((intptr_t)(p), (intptr_t)(align))
-+
-+#ifndef SPA_LIKELY
-+#ifdef __GNUC__
-+#define SPA_LIKELY(x) (__builtin_expect(!!(x),1))
-+#define SPA_UNLIKELY(x) (__builtin_expect(!!(x),0))
-+#else
-+#define SPA_LIKELY(x) (x)
-+#define SPA_UNLIKELY(x) (x)
-+#endif
-+#endif
-+
-+#define SPA_STRINGIFY_1(...) #__VA_ARGS__
-+#define SPA_STRINGIFY(...) SPA_STRINGIFY_1(__VA_ARGS__)
-+
-+#define spa_return_if_fail(expr) \
-+ do { \
-+ if (SPA_UNLIKELY(!(expr))) { \
-+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
-+ #expr , __FILE__, __LINE__, __func__); \
-+ return; \
-+ } \
-+ } while(false)
-+
-+#define spa_return_val_if_fail(expr, val) \
-+ do { \
-+ if (SPA_UNLIKELY(!(expr))) { \
-+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
-+ #expr , __FILE__, __LINE__, __func__); \
-+ return (val); \
-+ } \
-+ } while(false)
-+
-+/* spa_assert_se() is an assert which guarantees side effects of x,
-+ * i.e. is never optimized away, regardless of NDEBUG or FASTPATH. */
-+#define spa_assert_se(expr) \
-+ do { \
-+ if (SPA_UNLIKELY(!(expr))) { \
-+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
-+ #expr , __FILE__, __LINE__, __func__); \
-+ abort(); \
-+ } \
-+ } while (false)
-+
-+#define spa_assert(expr) \
-+ do { \
-+ if (SPA_UNLIKELY(!(expr))) { \
-+ fprintf(stderr, "'%s' failed at %s:%u %s()\n", \
-+ #expr , __FILE__, __LINE__, __func__); \
-+ abort(); \
-+ } \
-+ } while (false)
-+
-+#define spa_assert_not_reached() \
-+ do { \
-+ fprintf(stderr, "Code should not be reached at %s:%u %s()\n", \
-+ __FILE__, __LINE__, __func__); \
-+ abort(); \
-+ } while (false)
-+
-+/* Does exactly nothing */
-+#define spa_nop() do {} while (false)
-+
-+#define spa_memzero(x,l) (memset((x), 0, (l)))
-+#define spa_zero(x) (spa_memzero(&(x), sizeof(x)))
-+
-+#ifdef SPA_DEBUG_MEMCPY
-+#define spa_memcpy(d,s,n) \
-+({ \
-+ fprintf(stderr, "%s:%u %s() memcpy(%p, %p, %zd)\n", \
-+ __FILE__, __LINE__, __func__, (d), (s), (size_t)(n)); \
-+ memcpy(d,s,n); \
-+})
-+#define spa_memmove(d,s,n) \
-+({ \
-+ fprintf(stderr, "%s:%u %s() memmove(%p, %p, %zd)\n", \
-+ __FILE__, __LINE__, __func__, (d), (s), (size_t)(n)); \
-+ memmove(d,s,n); \
-+})
-+#else
-+#define spa_memcpy(d,s,n) memcpy(d,s,n)
-+#define spa_memmove(d,s,n) memmove(d,s,n)
-+#endif
-+
-+#define spa_aprintf(_fmt, ...) \
-+({ \
-+ char *_strp; \
-+ if (asprintf(&(_strp), (_fmt), ## __VA_ARGS__ ) == -1) \
-+ _strp = NULL; \
-+ _strp; \
-+})
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_UTILS_DEFS_H */
-diff --git a/third_party/pipewire/spa/utils/dict.h b/third_party/pipewire/spa/utils/dict.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/dict.h
-@@ -0,0 +1,104 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_DICT_H
-+#define SPA_DICT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <string.h>
-+
-+#include <spa/utils/defs.h>
-+
-+struct spa_dict_item {
-+ const char *key;
-+ const char *value;
-+};
-+
-+#define SPA_DICT_ITEM_INIT(key,value) (struct spa_dict_item) { key, value }
-+
-+struct spa_dict {
-+#define SPA_DICT_FLAG_SORTED (1<<0) /**< items are sorted */
-+ uint32_t flags;
-+ uint32_t n_items;
-+ const struct spa_dict_item *items;
-+};
-+
-+#define SPA_DICT_INIT(items,n_items) (struct spa_dict) { 0, n_items, items }
-+#define SPA_DICT_INIT_ARRAY(items) (struct spa_dict) { 0, SPA_N_ELEMENTS(items), items }
-+
-+#define spa_dict_for_each(item, dict) \
-+ for ((item) = (dict)->items; \
-+ (item) < &(dict)->items[(dict)->n_items]; \
-+ (item)++)
-+
-+static inline int spa_dict_item_compare(const void *i1, const void *i2)
-+{
-+ const struct spa_dict_item *it1 = (const struct spa_dict_item *)i1,
-+ *it2 = (const struct spa_dict_item *)i2;
-+ return strcmp(it1->key, it2->key);
-+}
-+
-+static inline void spa_dict_qsort(struct spa_dict *dict)
-+{
-+ qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item),
-+ spa_dict_item_compare);
-+ SPA_FLAG_SET(dict->flags, SPA_DICT_FLAG_SORTED);
-+}
-+
-+static inline const struct spa_dict_item *spa_dict_lookup_item(const struct spa_dict *dict,
-+ const char *key)
-+{
-+ const struct spa_dict_item *item;
-+
-+ if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED)) {
-+ struct spa_dict_item k = SPA_DICT_ITEM_INIT(key, NULL);
-+ item = (const struct spa_dict_item *)bsearch(&k,
-+ (const void *) dict->items, dict->n_items,
-+ sizeof(struct spa_dict_item),
-+ spa_dict_item_compare);
-+ if (item != NULL)
-+ return item;
-+ } else {
-+ spa_dict_for_each(item, dict) {
-+ if (!strcmp(item->key, key))
-+ return item;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static inline const char *spa_dict_lookup(const struct spa_dict *dict, const char *key)
-+{
-+ const struct spa_dict_item *item = spa_dict_lookup_item(dict, key);
-+ return item ? item->value : NULL;
-+}
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_DICT_H */
-diff --git a/third_party/pipewire/spa/utils/hook.h b/third_party/pipewire/spa/utils/hook.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/hook.h
-@@ -0,0 +1,198 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_HOOK_H
-+#define SPA_HOOK_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/list.h>
-+
-+/** \class spa_hook
-+ *
-+ * \brief a list of hooks
-+ *
-+ * The hook list provides a way to keep track of hooks.
-+ */
-+/** A list of hooks */
-+struct spa_hook_list {
-+ struct spa_list list;
-+};
-+
-+/** Callbacks, contains the structure with functions and the data passed
-+ * to the functions. The structure should also contain a version field that
-+ * is checked. */
-+struct spa_callbacks {
-+ const void *funcs;
-+ void *data;
-+};
-+
-+/** Check if a callback \c has method \m of version \v */
-+#define SPA_CALLBACK_CHECK(c,m,v) ((c) && ((v) == 0 || (c)->version > (v)-1) && (c)->m)
-+
-+#define SPA_CALLBACKS_INIT(_funcs,_data) (struct spa_callbacks){ _funcs, _data, }
-+
-+struct spa_interface {
-+ const char *type;
-+ uint32_t version;
-+ struct spa_callbacks cb;
-+};
-+
-+#define SPA_INTERFACE_INIT(_type,_version,_funcs,_data) \
-+ (struct spa_interface){ _type, _version, SPA_CALLBACKS_INIT(_funcs,_data), }
-+
-+/** A hook, contains the structure with functions and the data passed
-+ * to the functions. */
-+struct spa_hook {
-+ struct spa_list link;
-+ struct spa_callbacks cb;
-+ /** callback and data for the hook list */
-+ void (*removed) (struct spa_hook *hook);
-+ void *priv;
-+};
-+
-+/** Initialize a hook list */
-+static inline void spa_hook_list_init(struct spa_hook_list *list)
-+{
-+ spa_list_init(&list->list);
-+}
-+
-+static inline bool spa_hook_list_is_empty(struct spa_hook_list *list)
-+{
-+ return spa_list_is_empty(&list->list);
-+}
-+
-+/** Append a hook \memberof spa_hook */
-+static inline void spa_hook_list_append(struct spa_hook_list *list,
-+ struct spa_hook *hook,
-+ const void *funcs, void *data)
-+{
-+ hook->cb = SPA_CALLBACKS_INIT(funcs, data);
-+ spa_list_append(&list->list, &hook->link);
-+}
-+
-+/** Prepend a hook \memberof spa_hook */
-+static inline void spa_hook_list_prepend(struct spa_hook_list *list,
-+ struct spa_hook *hook,
-+ const void *funcs, void *data)
-+{
-+ hook->cb = SPA_CALLBACKS_INIT(funcs, data);
-+ spa_list_prepend(&list->list, &hook->link);
-+}
-+
-+/** Remove a hook \memberof spa_hook */
-+static inline void spa_hook_remove(struct spa_hook *hook)
-+{
-+ spa_list_remove(&hook->link);
-+ if (hook->removed)
-+ hook->removed(hook);
-+}
-+
-+static inline void
-+spa_hook_list_isolate(struct spa_hook_list *list,
-+ struct spa_hook_list *save,
-+ struct spa_hook *hook,
-+ const void *funcs, void *data)
-+{
-+ /* init save list and move hooks to it */
-+ spa_hook_list_init(save);
-+ spa_list_insert_list(&save->list, &list->list);
-+ /* init hooks and add single hook */
-+ spa_hook_list_init(list);
-+ spa_hook_list_append(list, hook, funcs, data);
-+}
-+
-+static inline void
-+spa_hook_list_join(struct spa_hook_list *list,
-+ struct spa_hook_list *save)
-+{
-+ spa_list_insert_list(&list->list, &save->list);
-+}
-+
-+#define spa_callbacks_call(callbacks,type,method,vers,...) \
-+({ \
-+ const type *_f = (const type *) (callbacks)->funcs; \
-+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
-+ _f->method((callbacks)->data, ## __VA_ARGS__); \
-+})
-+
-+#define spa_callbacks_call_res(callbacks,type,res,method,vers,...) \
-+({ \
-+ const type *_f = (const type *) (callbacks)->funcs; \
-+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) \
-+ res = _f->method((callbacks)->data, ## __VA_ARGS__); \
-+ res; \
-+})
-+
-+#define spa_interface_call(iface,type,method,vers,...) \
-+ spa_callbacks_call(&(iface)->cb,type,method,vers,##__VA_ARGS__)
-+
-+#define spa_interface_call_res(iface,type,res,method,vers,...) \
-+ spa_callbacks_call_res(&(iface)->cb,type,res,method,vers,##__VA_ARGS__)
-+
-+#define spa_hook_list_call_simple(l,type,method,vers,...) \
-+({ \
-+ struct spa_hook_list *_l = l; \
-+ struct spa_hook *_h, *_t; \
-+ spa_list_for_each_safe(_h, _t, &_l->list, link) \
-+ spa_callbacks_call(&_h->cb,type,method,vers, ## __VA_ARGS__); \
-+})
-+
-+/** Call all hooks in a list, starting from the given one and optionally stopping
-+ * after calling the first non-NULL function, returns the number of methods
-+ * called */
-+#define spa_hook_list_do_call(l,start,type,method,vers,once,...) \
-+({ \
-+ struct spa_hook_list *list = l; \
-+ struct spa_list *s = start ? (struct spa_list *)start : &list->list; \
-+ struct spa_hook cursor = { 0 }, *ci; \
-+ int count = 0; \
-+ spa_list_cursor_start(cursor, s, link); \
-+ spa_list_for_each_cursor(ci, cursor, &list->list, link) { \
-+ const type *_f = (const type *)ci->cb.funcs; \
-+ if (SPA_LIKELY(SPA_CALLBACK_CHECK(_f,method,vers))) { \
-+ _f->method(ci->cb.data, ## __VA_ARGS__); \
-+ count++; \
-+ if (once) \
-+ break; \
-+ } \
-+ } \
-+ spa_list_cursor_end(cursor, link); \
-+ count; \
-+})
-+
-+#define spa_hook_list_call(l,t,m,v,...) spa_hook_list_do_call(l,NULL,t,m,v,false,##__VA_ARGS__)
-+#define spa_hook_list_call_once(l,t,m,v,...) spa_hook_list_do_call(l,NULL,t,m,v,true,##__VA_ARGS__)
-+
-+#define spa_hook_list_call_start(l,s,t,m,v,...) spa_hook_list_do_call(l,s,t,m,v,false,##__VA_ARGS__)
-+#define spa_hook_list_call_once_start(l,s,t,m,v,...) spa_hook_list_do_call(l,s,t,m,v,true,##__VA_ARGS__)
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* SPA_HOOK_H */
-diff --git a/third_party/pipewire/spa/utils/keys.h b/third_party/pipewire/spa/utils/keys.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/keys.h
-@@ -0,0 +1,124 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_UTILS_KEYS_H
-+#define SPA_UTILS_KEYS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** for objects */
-+#define SPA_KEY_OBJECT_PATH "object.path" /**< a unique path to
-+ * identity the object */
-+
-+#define SPA_KEY_MEDIA_CLASS "media.class" /**< Media class
-+ * Ex. "Audio/Device",
-+ * "Video/Source",... */
-+#define SPA_KEY_MEDIA_ROLE "media.role" /**< Role: Movie, Music, Camera,
-+ * Screen, Communication, Game,
-+ * Notification, DSP, Production,
-+ * Accessibility, Test */
-+/** keys for udev api */
-+#define SPA_KEY_API_UDEV "api.udev" /**< key for the udev api */
-+#define SPA_KEY_API_UDEV_MATCH "api.udev.match" /**< udev subsystem match */
-+
-+/** keys for alsa api */
-+#define SPA_KEY_API_ALSA "api.alsa" /**< key for the alsa api */
-+#define SPA_KEY_API_ALSA_PATH "api.alsa.path" /**< alsa device path as can be
-+ * used in snd_pcm_open() and
-+ * snd_ctl_open(). */
-+#define SPA_KEY_API_ALSA_CARD "api.alsa.card" /**< alsa card number */
-+#define SPA_KEY_API_ALSA_USE_UCM "api.alsa.use-ucm" /**< if UCM should be used */
-+#define SPA_KEY_API_ALSA_IGNORE_DB "api.alsa.ignore-dB" /**< if decibel info should be ignored */
-+
-+/** info from alsa card_info */
-+#define SPA_KEY_API_ALSA_CARD_ID "api.alsa.card.id" /**< id from card_info */
-+#define SPA_KEY_API_ALSA_CARD_COMPONENTS \
-+ "api.alsa.card.components" /**< components from card_info */
-+#define SPA_KEY_API_ALSA_CARD_DRIVER "api.alsa.card.driver" /**< driver from card_info */
-+#define SPA_KEY_API_ALSA_CARD_NAME "api.alsa.card.name" /**< name from card_info */
-+#define SPA_KEY_API_ALSA_CARD_LONGNAME "api.alsa.card.longname" /**< longname from card_info */
-+#define SPA_KEY_API_ALSA_CARD_MIXERNAME "api.alsa.card.mixername" /**< mixername from card_info */
-+
-+/** info from alsa pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_ID "api.alsa.pcm.id" /**< id from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_CARD "api.alsa.pcm.card" /**< card from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_NAME "api.alsa.pcm.name" /**< name from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_SUBNAME "api.alsa.pcm.subname" /**< subdevice_name from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_STREAM "api.alsa.pcm.stream" /**< stream type from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_CLASS "api.alsa.pcm.class" /**< class from pcm_info as string */
-+#define SPA_KEY_API_ALSA_PCM_DEVICE "api.alsa.pcm.device" /**< device from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_SUBDEVICE "api.alsa.pcm.subdevice" /**< subdevice from pcm_info */
-+#define SPA_KEY_API_ALSA_PCM_SUBCLASS "api.alsa.pcm.subclass" /**< subclass from pcm_info as string */
-+#define SPA_KEY_API_ALSA_PCM_SYNC_ID "api.alsa.pcm.sync-id" /**< sync id */
-+
-+/** keys for v4l2 api */
-+#define SPA_KEY_API_V4L2 "api.v4l2" /**< key for the v4l2 api */
-+#define SPA_KEY_API_V4L2_PATH "api.v4l2.path" /**< v4l2 device path as can be
-+ * used in open() */
-+
-+/** keys for libcamera api */
-+#define SPA_KEY_API_LIBCAMERA "api.libcamera" /**< key for the libcamera api */
-+#define SPA_KEY_API_LIBCAMERA_PATH "api.libcamera.path" /**< libcamera device path as can be
-+ * used in open() */
-+
-+/** info from libcamera_capability */
-+#define SPA_KEY_API_LIBCAMERA_CAP_DRIVER "api.libcamera.cap.driver" /**< driver from capbility */
-+#define SPA_KEY_API_LIBCAMERA_CAP_CARD "api.libcamera.cap.card" /**< caps from capability */
-+#define SPA_KEY_API_LIBCAMERA_CAP_BUS_INFO "api.libcamera.cap.bus_info"/**< bus_info from capability */
-+#define SPA_KEY_API_LIBCAMERA_CAP_VERSION "api.libcamera.cap.version" /**< version from capability as %u.%u.%u */
-+#define SPA_KEY_API_LIBCAMERA_CAP_CAPABILITIES \
-+ "api.libcamera.cap.capabilities" /**< capabilities from capability */
-+#define SPA_KEY_API_LIBCAMERA_CAP_DEVICE_CAPS \
-+ "api.libcamera.cap.device-caps" /**< device_caps from capability */
-+/** info from v4l2_capability */
-+#define SPA_KEY_API_V4L2_CAP_DRIVER "api.v4l2.cap.driver" /**< driver from capbility */
-+#define SPA_KEY_API_V4L2_CAP_CARD "api.v4l2.cap.card" /**< caps from capability */
-+#define SPA_KEY_API_V4L2_CAP_BUS_INFO "api.v4l2.cap.bus_info" /**< bus_info from capability */
-+#define SPA_KEY_API_V4L2_CAP_VERSION "api.v4l2.cap.version" /**< version from capability as %u.%u.%u */
-+#define SPA_KEY_API_V4L2_CAP_CAPABILITIES \
-+ "api.v4l2.cap.capabilities" /**< capabilities from capability */
-+#define SPA_KEY_API_V4L2_CAP_DEVICE_CAPS \
-+ "api.v4l2.cap.device-caps" /**< device_caps from capability */
-+
-+
-+/** keys for bluez5 api */
-+#define SPA_KEY_API_BLUEZ5 "api.bluez5" /**< key for the bluez5 api */
-+#define SPA_KEY_API_BLUEZ5_PATH "api.bluez5.path" /**< a bluez5 path */
-+#define SPA_KEY_API_BLUEZ5_DEVICE "api.bluez5.device" /**< an internal bluez5 device */
-+#define SPA_KEY_API_BLUEZ5_TRANSPORT "api.bluez5.transport" /**< an internal bluez5 transport */
-+#define SPA_KEY_API_BLUEZ5_PROFILE "api.bluez5.profile" /**< a bluetooth profile */
-+#define SPA_KEY_API_BLUEZ5_ADDRESS "api.bluez5.address" /**< a bluetooth address */
-+
-+/** keys for jack api */
-+#define SPA_KEY_API_JACK "api.jack" /**< key for the JACK api */
-+#define SPA_KEY_API_JACK_SERVER "api.jack.server" /**< a jack server name */
-+#define SPA_KEY_API_JACK_CLIENT "api.jack.client" /**< an internal jack client */
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_UTILS_KEYS_H */
-diff --git a/third_party/pipewire/spa/utils/list.h b/third_party/pipewire/spa/utils/list.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/list.h
-@@ -0,0 +1,138 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_LIST_H
-+#define SPA_LIST_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+struct spa_list {
-+ struct spa_list *next;
-+ struct spa_list *prev;
-+};
-+
-+#define SPA_LIST_INIT(list) (struct spa_list){ list, list };
-+
-+static inline void spa_list_init(struct spa_list *list)
-+{
-+ *list = SPA_LIST_INIT(list);
-+}
-+
-+#define spa_list_is_empty(l) ((l)->next == (l))
-+
-+static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
-+{
-+ elem->prev = list;
-+ elem->next = list->next;
-+ list->next = elem;
-+ elem->next->prev = elem;
-+}
-+
-+static inline void spa_list_insert_list(struct spa_list *list, struct spa_list *other)
-+{
-+ if (spa_list_is_empty(other))
-+ return;
-+ other->next->prev = list;
-+ other->prev->next = list->next;
-+ list->next->prev = other->prev;
-+ list->next = other->next;
-+}
-+
-+static inline void spa_list_remove(struct spa_list *elem)
-+{
-+ elem->prev->next = elem->next;
-+ elem->next->prev = elem->prev;
-+}
-+
-+#define spa_list_first(head, type, member) \
-+ SPA_CONTAINER_OF((head)->next, type, member)
-+
-+#define spa_list_last(head, type, member) \
-+ SPA_CONTAINER_OF((head)->prev, type, member)
-+
-+#define spa_list_append(list, item) \
-+ spa_list_insert((list)->prev, item)
-+
-+#define spa_list_prepend(list, item) \
-+ spa_list_insert(list, item)
-+
-+#define spa_list_is_end(pos, head, member) \
-+ (&(pos)->member == (head))
-+
-+#define spa_list_next(pos, member) \
-+ SPA_CONTAINER_OF((pos)->member.next, __typeof__(*pos), member)
-+
-+#define spa_list_prev(pos, member) \
-+ SPA_CONTAINER_OF((pos)->member.prev, __typeof__(*pos), member)
-+
-+#define spa_list_consume(pos, head, member) \
-+ for (pos = spa_list_first(head, __typeof__(*pos), member); \
-+ !spa_list_is_empty(head); \
-+ pos = spa_list_first(head, __typeof__(*pos), member))
-+
-+#define spa_list_for_each_next(pos, head, curr, member) \
-+ for (pos = spa_list_first(curr, __typeof__(*pos), member); \
-+ !spa_list_is_end(pos, head, member); \
-+ pos = spa_list_next(pos, member))
-+
-+#define spa_list_for_each_prev(pos, head, curr, member) \
-+ for (pos = spa_list_last(curr, __typeof__(*pos), member); \
-+ !spa_list_is_end(pos, head, member); \
-+ pos = spa_list_prev(pos, member))
-+
-+#define spa_list_for_each(pos, head, member) \
-+ spa_list_for_each_next(pos, head, head, member)
-+
-+#define spa_list_for_each_reverse(pos, head, member) \
-+ spa_list_for_each_prev(pos, head, head, member)
-+
-+#define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \
-+ for (pos = spa_list_first(curr, __typeof__(*pos), member); \
-+ tmp = spa_list_next(pos, member), \
-+ !spa_list_is_end(pos, head, member); \
-+ pos = tmp)
-+
-+#define spa_list_for_each_safe(pos, tmp, head, member) \
-+ spa_list_for_each_safe_next(pos, tmp, head, head, member)
-+
-+#define spa_list_cursor_start(cursor, head, member) \
-+ spa_list_prepend(head, &(cursor).member)
-+
-+#define spa_list_for_each_cursor(pos, cursor, head, member) \
-+ for(pos = spa_list_first(&(cursor).member, __typeof__(*(pos)), member); \
-+ spa_list_remove(&(pos)->member), \
-+ spa_list_append(&(cursor).member, &(pos)->member), \
-+ !spa_list_is_end(pos, head, member); \
-+ pos = spa_list_next(&cursor, member))
-+
-+#define spa_list_cursor_end(cursor, member) \
-+ spa_list_remove(&(cursor).member)
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_LIST_H */
-diff --git a/third_party/pipewire/spa/utils/names.h b/third_party/pipewire/spa/utils/names.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/names.h
-@@ -0,0 +1,137 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2019 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_UTILS_NAMES_H
-+#define SPA_UTILS_NAMES_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/** for factory names */
-+#define SPA_NAME_SUPPORT_CPU "support.cpu" /**< A CPU interface */
-+#define SPA_NAME_SUPPORT_DBUS "support.dbus" /**< A DBUS interface */
-+#define SPA_NAME_SUPPORT_LOG "support.log" /**< A Log interface */
-+#define SPA_NAME_SUPPORT_LOOP "support.loop" /**< A Loop/LoopControl/LoopUtils
-+ * interface */
-+#define SPA_NAME_SUPPORT_SYSTEM "support.system" /**< A System interface */
-+
-+#define SPA_NAME_SUPPORT_NODE_DRIVER "support.node.driver" /**< A dummy driver node */
-+
-+/* control mixer */
-+#define SPA_NAME_CONTROL_MIXER "control.mixer" /**< mixes control streams */
-+
-+/* audio mixer */
-+#define SPA_NAME_AUDIO_MIXER "audio.mixer" /**< mixes the raw audio on N input
-+ * ports together on the output
-+ * port */
-+#define SPA_NAME_AUDIO_MIXER_DSP "audio.mixer.dsp" /**< mixes mono audio with fixed input
-+ * and output buffer sizes. supported
-+ * formats must include f32 and
-+ * optionally f64 and s24_32 */
-+
-+/** audio processing */
-+#define SPA_NAME_AUDIO_PROCESS_FORMAT "audio.process.format" /**< processes raw audio from one format
-+ * to another */
-+#define SPA_NAME_AUDIO_PROCESS_CHANNELMIX \
-+ "audio.process.channelmix" /**< mixes raw audio channels and applies
-+ * volume change. */
-+#define SPA_NAME_AUDIO_PROCESS_RESAMPLE \
-+ "audio.process.resample" /**< resamples raw audio */
-+#define SPA_NAME_AUDIO_PROCESS_DEINTERLEAVE \
-+ "audio.process.deinterleave" /**< deinterleave raw audio channels */
-+#define SPA_NAME_AUDIO_PROCESS_INTERLEAVE \
-+ "audio.process.interleave" /**< interleave raw audio channels */
-+
-+
-+/** audio convert combines some of the audio processing */
-+#define SPA_NAME_AUDIO_CONVERT "audio.convert" /**< converts raw audio from one format
-+ * to another. Must include at least
-+ * format, channelmix and resample
-+ * processing */
-+#define SPA_NAME_AUDIO_ADAPT "audio.adapt" /**< combination of a node and an
-+ * audio.convert. Does clock slaving */
-+
-+/** video processing */
-+#define SPA_NAME_VIDEO_PROCESS_FORMAT "video.process.format" /**< processes raw video from one format
-+ * to another */
-+#define SPA_NAME_VIDEO_PROCESS_SCALE "video.process.scale" /**< scales raw video */
-+
-+/** video convert combines some of the video processing */
-+#define SPA_NAME_VIDEO_CONVERT "video.convert" /**< converts raw video from one format
-+ * to another. Must include at least
-+ * format and scaling */
-+#define SPA_NAME_VIDEO_ADAPT "video.adapt" /**< combination of a node and a
-+ * video.convert. */
-+/** keys for alsa factory names */
-+#define SPA_NAME_API_ALSA_ENUM_UDEV "api.alsa.enum.udev" /**< an alsa udev Device interface */
-+#define SPA_NAME_API_ALSA_PCM_DEVICE "api.alsa.pcm.device" /**< an alsa Device interface */
-+#define SPA_NAME_API_ALSA_PCM_SOURCE "api.alsa.pcm.source" /**< an alsa Node interface for
-+ * capturing PCM */
-+#define SPA_NAME_API_ALSA_PCM_SINK "api.alsa.pcm.sink" /**< an alsa Node interface for
-+ * playback PCM */
-+#define SPA_NAME_API_ALSA_SEQ_DEVICE "api.alsa.seq.device" /**< an alsa Midi device */
-+#define SPA_NAME_API_ALSA_SEQ_SOURCE "api.alsa.seq.source" /**< an alsa Node interface for
-+ * capture of midi */
-+#define SPA_NAME_API_ALSA_SEQ_SINK "api.alsa.seq.sink" /**< an alsa Node interface for
-+ * playback of midi */
-+#define SPA_NAME_API_ALSA_SEQ_BRIDGE "api.alsa.seq.bridge" /**< an alsa Node interface for
-+ * bridging midi ports */
-+#define SPA_NAME_API_ALSA_ACP_DEVICE "api.alsa.acp.device" /**< an alsa ACP Device interface */
-+
-+/** keys for bluez5 factory names */
-+#define SPA_NAME_API_BLUEZ5_ENUM_DBUS "api.bluez5.enum.dbus" /**< a dbus Device interface */
-+#define SPA_NAME_API_BLUEZ5_DEVICE "api.bluez5.device" /**< a Device interface */
-+#define SPA_NAME_API_BLUEZ5_A2DP_SINK "api.bluez5.a2dp.sink" /**< a playback Node interface for A2DP profiles */
-+#define SPA_NAME_API_BLUEZ5_A2DP_SOURCE "api.bluez5.a2dp.source" /**< a capture Node interface for A2DP profiles */
-+#define SPA_NAME_API_BLUEZ5_SCO_SINK "api.bluez5.sco.sink" /**< a playback Node interface for HSP/HFP profiles */
-+#define SPA_NAME_API_BLUEZ5_SCO_SOURCE "api.bluez5.sco.source" /**< a capture Node interface for HSP/HFP profiles */
-+
-+/** keys for v4l2 factory names */
-+#define SPA_NAME_API_V4L2_ENUM_UDEV "api.v4l2.enum.udev" /**< a v4l2 udev Device interface */
-+#define SPA_NAME_API_V4L2_DEVICE "api.v4l2.device" /**< a v4l2 Device interface */
-+#define SPA_NAME_API_V4L2_SOURCE "api.v4l2.source" /**< a v4l2 Node interface for
-+ * capturing */
-+
-+/** keys for libcamera factory names */
-+#define SPA_NAME_API_LIBCAMERA_ENUM_CLIENT "api.libcamera.enum.client" /**< a libcamera client Device interface */
-+#define SPA_NAME_API_LIBCAMERA_DEVICE "api.libcamera.device" /**< a libcamera Device interface */
-+#define SPA_NAME_API_LIBCAMERA_SOURCE "api.libcamera.source" /**< a libcamera Node interface for
-+ * capturing */
-+
-+/** keys for jack factory names */
-+#define SPA_NAME_API_JACK_DEVICE "api.jack.device" /**< a jack device. This is a
-+ * client connected to a server */
-+#define SPA_NAME_API_JACK_SOURCE "api.jack.source" /**< a jack source */
-+#define SPA_NAME_API_JACK_SINK "api.jack.sink" /**< a jack sink */
-+
-+/** keys for vulkan factory names */
-+#define SPA_NAME_API_VULKAN_COMPUTE_SOURCE \
-+ "api.vulkan.compute.source" /**< a vulkan compute source. */
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_UTILS_NAMES_H */
-diff --git a/third_party/pipewire/spa/utils/result.h b/third_party/pipewire/spa/utils/result.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/result.h
-@@ -0,0 +1,58 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_UTILS_RESULT_H
-+#define SPA_UTILS_RESULT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+#include <spa/utils/list.h>
-+
-+#define SPA_ASYNC_BIT (1 << 30)
-+#define SPA_ASYNC_MASK (3 << 30)
-+#define SPA_ASYNC_SEQ_MASK (SPA_ASYNC_BIT - 1)
-+
-+#define SPA_RESULT_IS_OK(res) ((res) >= 0)
-+#define SPA_RESULT_IS_ERROR(res) ((res) < 0)
-+#define SPA_RESULT_IS_ASYNC(res) (((res) & SPA_ASYNC_MASK) == SPA_ASYNC_BIT)
-+
-+#define SPA_RESULT_ASYNC_SEQ(res) ((res) & SPA_ASYNC_SEQ_MASK)
-+#define SPA_RESULT_RETURN_ASYNC(seq) (SPA_ASYNC_BIT | SPA_RESULT_ASYNC_SEQ(seq))
-+
-+#define spa_strerror(err) \
-+({ \
-+ int _err = -err; \
-+ if (SPA_RESULT_IS_ASYNC(err)) \
-+ _err = EINPROGRESS; \
-+ strerror(_err); \
-+})
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_UTILS_RESULT_H */
-diff --git a/third_party/pipewire/spa/utils/ringbuffer.h b/third_party/pipewire/spa/utils/ringbuffer.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/ringbuffer.h
-@@ -0,0 +1,174 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_RINGBUFFER_H
-+#define SPA_RINGBUFFER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+struct spa_ringbuffer;
-+
-+#include <string.h>
-+
-+#include <spa/utils/defs.h>
-+
-+/**
-+ * A ringbuffer type.
-+ */
-+struct spa_ringbuffer {
-+ uint32_t readindex; /*< the current read index */
-+ uint32_t writeindex; /*< the current write index */
-+};
-+
-+#define SPA_RINGBUFFER_INIT() (struct spa_ringbuffer) { 0, 0 }
-+
-+/**
-+ * Initialize a spa_ringbuffer with \a size.
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ * \param size the number of elements in the ringbuffer
-+ */
-+static inline void spa_ringbuffer_init(struct spa_ringbuffer *rbuf)
-+{
-+ *rbuf = SPA_RINGBUFFER_INIT();
-+}
-+
-+/**
-+ * Sets the pointers so that the ringbuffer contains \a size bytes.
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ */
-+static inline void spa_ringbuffer_set_avail(struct spa_ringbuffer *rbuf, uint32_t size)
-+{
-+ rbuf->readindex = 0;
-+ rbuf->writeindex = size;
-+}
-+
-+/**
-+ * Get the read index and available bytes for reading.
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ * \param index the value of readindex, should be taken modulo the size of the
-+ * ringbuffer memory to get the offset in the ringbuffer memory
-+ * \return number of available bytes to read. values < 0 mean
-+ * there was an underrun. values > rbuf->size means there
-+ * was an overrun.
-+ */
-+static inline int32_t spa_ringbuffer_get_read_index(struct spa_ringbuffer *rbuf, uint32_t *index)
-+{
-+ *index = __atomic_load_n(&rbuf->readindex, __ATOMIC_RELAXED);
-+ return (int32_t) (__atomic_load_n(&rbuf->writeindex, __ATOMIC_ACQUIRE) - *index);
-+}
-+
-+/**
-+ * Read \a len bytes from \a rbuf starting \a offset. \a offset must be taken
-+ * modulo \a size and len should be smaller than \a size.
-+ *
-+ * \param rbuf a #struct spa_ringbuffer
-+ * \param buffer memory to read from
-+ * \param size the size of \a buffer
-+ * \param offset offset in \a buffer to read from
-+ * \param data destination memory
-+ * \param len number of bytes to read
-+ */
-+static inline void
-+spa_ringbuffer_read_data(struct spa_ringbuffer *rbuf,
-+ const void *buffer, uint32_t size,
-+ uint32_t offset, void *data, uint32_t len)
-+{
-+ uint32_t l0 = SPA_MIN(len, size - offset), l1 = len - l0;
-+ spa_memcpy(data, SPA_MEMBER(buffer, offset, void), l0);
-+ if (SPA_UNLIKELY(l1 > 0))
-+ spa_memcpy(SPA_MEMBER(data, l0, void), buffer, l1);
-+}
-+
-+/**
-+ * Update the read pointer to \a index.
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ * \param index new index
-+ */
-+static inline void spa_ringbuffer_read_update(struct spa_ringbuffer *rbuf, int32_t index)
-+{
-+ __atomic_store_n(&rbuf->readindex, index, __ATOMIC_RELEASE);
-+}
-+
-+/**
-+ * Get the write index and the number of bytes inside the ringbuffer.
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ * \param index the value of writeindex, should be taken modulo the size of the
-+ * ringbuffer memory to get the offset in the ringbuffer memory
-+ * \return the fill level of \a rbuf. values < 0 mean
-+ * there was an underrun. values > rbuf->size means there
-+ * was an overrun. Subtract from the buffer size to get
-+ * the number of bytes available for writing.
-+ */
-+static inline int32_t spa_ringbuffer_get_write_index(struct spa_ringbuffer *rbuf, uint32_t *index)
-+{
-+ *index = __atomic_load_n(&rbuf->writeindex, __ATOMIC_RELAXED);
-+ return (int32_t) (*index - __atomic_load_n(&rbuf->readindex, __ATOMIC_ACQUIRE));
-+}
-+
-+/**
-+ * Write \a len bytes to \a buffer starting \a offset. \a offset must be taken
-+ * modulo \a size and len should be smaller than \a size.
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ * \param buffer memory to write to
-+ * \param size the size of \a buffer
-+ * \param offset offset in \a buffer to write to
-+ * \param data source memory
-+ * \param len number of bytes to write
-+ */
-+static inline void
-+spa_ringbuffer_write_data(struct spa_ringbuffer *rbuf,
-+ void *buffer, uint32_t size,
-+ uint32_t offset, const void *data, uint32_t len)
-+{
-+ uint32_t l0 = SPA_MIN(len, size - offset), l1 = len - l0;
-+ spa_memcpy(SPA_MEMBER(buffer, offset, void), data, l0);
-+ if (SPA_UNLIKELY(l1 > 0))
-+ spa_memcpy(buffer, SPA_MEMBER(data, l0, void), l1);
-+}
-+
-+/**
-+ * Update the write pointer to \a index
-+ *
-+ * \param rbuf a spa_ringbuffer
-+ * \param index new index
-+ */
-+static inline void spa_ringbuffer_write_update(struct spa_ringbuffer *rbuf, int32_t index)
-+{
-+ __atomic_store_n(&rbuf->writeindex, index, __ATOMIC_RELEASE);
-+}
-+
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_RINGBUFFER_H */
-diff --git a/third_party/pipewire/spa/utils/type-info.h b/third_party/pipewire/spa/utils/type-info.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/type-info.h
-@@ -0,0 +1,128 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_TYPE_INFO_H
-+#define SPA_TYPE_INFO_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+
-+#ifndef SPA_TYPE_ROOT
-+#define SPA_TYPE_ROOT spa_types
-+#endif
-+
-+static inline bool spa_type_is_a(const char *type, const char *parent)
-+{
-+ return type != NULL && parent != NULL && strncmp(type, parent, strlen(parent)) == 0;
-+}
-+
-+#include <spa/utils/type.h>
-+
-+/* base for parameter object enumerations */
-+#define SPA_TYPE_INFO_Direction SPA_TYPE_INFO_ENUM_BASE "Direction"
-+#define SPA_TYPE_INFO_DIRECTION_BASE SPA_TYPE_INFO_Direction ":"
-+
-+static const struct spa_type_info spa_type_direction[] = {
-+ { SPA_DIRECTION_INPUT, SPA_TYPE_Int, SPA_TYPE_INFO_DIRECTION_BASE "Input", NULL },
-+ { SPA_DIRECTION_OUTPUT, SPA_TYPE_Int, SPA_TYPE_INFO_DIRECTION_BASE "Output", NULL },
-+ { 0, 0, NULL, NULL }
-+};
-+
-+#include <spa/node/type-info.h>
-+#include <spa/param/type-info.h>
-+#include <spa/control/type-info.h>
-+
-+/* base for parameter object enumerations */
-+#define SPA_TYPE_INFO_Choice SPA_TYPE_INFO_ENUM_BASE "Choice"
-+#define SPA_TYPE_INFO_CHOICE_BASE SPA_TYPE_INFO_Choice ":"
-+
-+static const struct spa_type_info spa_type_choice[] = {
-+ { SPA_CHOICE_None, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "None", NULL },
-+ { SPA_CHOICE_Range, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Range", NULL },
-+ { SPA_CHOICE_Step, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Step", NULL },
-+ { SPA_CHOICE_Enum, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Enum", NULL },
-+ { SPA_CHOICE_Flags, SPA_TYPE_Int, SPA_TYPE_INFO_CHOICE_BASE "Flags", NULL },
-+ { 0, 0, NULL, NULL }
-+};
-+
-+static const struct spa_type_info spa_types[] = {
-+ /* Basic types */
-+ { SPA_TYPE_START, SPA_TYPE_START, SPA_TYPE_INFO_BASE, NULL },
-+ { SPA_TYPE_None, SPA_TYPE_None, SPA_TYPE_INFO_BASE "None", NULL },
-+ { SPA_TYPE_Bool, SPA_TYPE_Bool, SPA_TYPE_INFO_BASE "Bool", NULL },
-+ { SPA_TYPE_Id, SPA_TYPE_Int, SPA_TYPE_INFO_BASE "Id", NULL },
-+ { SPA_TYPE_Int, SPA_TYPE_Int, SPA_TYPE_INFO_BASE "Int", NULL },
-+ { SPA_TYPE_Long, SPA_TYPE_Long, SPA_TYPE_INFO_BASE "Long", NULL },
-+ { SPA_TYPE_Float, SPA_TYPE_Float, SPA_TYPE_INFO_BASE "Float", NULL },
-+ { SPA_TYPE_Double, SPA_TYPE_Double, SPA_TYPE_INFO_BASE "Double", NULL },
-+ { SPA_TYPE_String, SPA_TYPE_String, SPA_TYPE_INFO_BASE "String", NULL },
-+ { SPA_TYPE_Bytes, SPA_TYPE_Bytes, SPA_TYPE_INFO_BASE "Bytes", NULL },
-+ { SPA_TYPE_Rectangle, SPA_TYPE_Rectangle, SPA_TYPE_INFO_BASE "Rectangle", NULL },
-+ { SPA_TYPE_Fraction, SPA_TYPE_Fraction, SPA_TYPE_INFO_BASE "Fraction", NULL },
-+ { SPA_TYPE_Bitmap, SPA_TYPE_Bitmap, SPA_TYPE_INFO_BASE "Bitmap", NULL },
-+ { SPA_TYPE_Array, SPA_TYPE_Array, SPA_TYPE_INFO_BASE "Array", NULL },
-+ { SPA_TYPE_Pod, SPA_TYPE_Pod, SPA_TYPE_INFO_Pod, NULL },
-+ { SPA_TYPE_Struct, SPA_TYPE_Pod, SPA_TYPE_INFO_Struct, NULL },
-+ { SPA_TYPE_Object, SPA_TYPE_Pod, SPA_TYPE_INFO_Object, NULL },
-+ { SPA_TYPE_Sequence, SPA_TYPE_Pod, SPA_TYPE_INFO_POD_BASE "Sequence", NULL },
-+ { SPA_TYPE_Pointer, SPA_TYPE_Pointer, SPA_TYPE_INFO_Pointer, NULL },
-+ { SPA_TYPE_Fd, SPA_TYPE_Fd, SPA_TYPE_INFO_BASE "Fd", NULL },
-+ { SPA_TYPE_Choice, SPA_TYPE_Pod, SPA_TYPE_INFO_POD_BASE "Choice", NULL },
-+
-+ { SPA_TYPE_POINTER_START, SPA_TYPE_Pointer, SPA_TYPE_INFO_Pointer, NULL },
-+ { SPA_TYPE_POINTER_Buffer, SPA_TYPE_Pointer, SPA_TYPE_INFO_POINTER_BASE "Buffer", NULL },
-+ { SPA_TYPE_POINTER_Meta, SPA_TYPE_Pointer, SPA_TYPE_INFO_POINTER_BASE "Meta", NULL },
-+ { SPA_TYPE_POINTER_Dict, SPA_TYPE_Pointer, SPA_TYPE_INFO_POINTER_BASE "Dict", NULL },
-+
-+ { SPA_TYPE_EVENT_START, SPA_TYPE_Object, SPA_TYPE_INFO_Event, NULL },
-+ { SPA_TYPE_EVENT_Device, SPA_TYPE_Object, SPA_TYPE_INFO_EVENT_BASE "Device", NULL },
-+ { SPA_TYPE_EVENT_Node, SPA_TYPE_Object, SPA_TYPE_INFO_EVENT_BASE "Node", spa_type_node_event },
-+
-+ { SPA_TYPE_COMMAND_START, SPA_TYPE_Object, SPA_TYPE_INFO_Command, NULL },
-+ { SPA_TYPE_COMMAND_Device, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Device", NULL },
-+ { SPA_TYPE_COMMAND_Node, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Node", spa_type_node_command },
-+
-+ { SPA_TYPE_OBJECT_START, SPA_TYPE_Object, SPA_TYPE_INFO_Object, NULL },
-+ { SPA_TYPE_OBJECT_PropInfo, SPA_TYPE_Object, SPA_TYPE_INFO_PropInfo, spa_type_prop_info, },
-+ { SPA_TYPE_OBJECT_Props, SPA_TYPE_Object, SPA_TYPE_INFO_Props, spa_type_props },
-+ { SPA_TYPE_OBJECT_Format, SPA_TYPE_Object, SPA_TYPE_INFO_Format, spa_type_format },
-+ { SPA_TYPE_OBJECT_ParamBuffers, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Buffers, spa_type_param_buffers, },
-+ { SPA_TYPE_OBJECT_ParamMeta, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Meta, spa_type_param_meta },
-+ { SPA_TYPE_OBJECT_ParamIO, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_IO, spa_type_param_io },
-+ { SPA_TYPE_OBJECT_ParamProfile, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Profile, spa_type_param_profile },
-+ { SPA_TYPE_OBJECT_ParamPortConfig, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_PortConfig, spa_type_param_port_config },
-+ { SPA_TYPE_OBJECT_ParamRoute, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Route, spa_type_param_route },
-+ { SPA_TYPE_OBJECT_Profiler, SPA_TYPE_Object, SPA_TYPE_INFO_Profiler, spa_type_profiler },
-+
-+ { 0, 0, NULL, NULL }
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_TYPE_INFO_H */
-diff --git a/third_party/pipewire/spa/utils/type.h b/third_party/pipewire/spa/utils/type.h
-new file mode 100644
---- /dev/null
-+++ b/third_party/pipewire/spa/utils/type.h
-@@ -0,0 +1,138 @@
-+/* Simple Plugin API
-+ *
-+ * Copyright © 2018 Wim Taymans
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the "Software"),
-+ * to deal in the Software without restriction, including without limitation
-+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-+ * and/or sell copies of the Software, and to permit persons to whom the
-+ * Software is furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice (including the next
-+ * paragraph) shall be included in all copies or substantial portions of the
-+ * Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ */
-+
-+#ifndef SPA_TYPE_H
-+#define SPA_TYPE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#include <spa/utils/defs.h>
-+
-+enum {
-+ /* Basic types */
-+ SPA_TYPE_START = 0x00000,
-+ SPA_TYPE_None,
-+ SPA_TYPE_Bool,
-+ SPA_TYPE_Id,
-+ SPA_TYPE_Int,
-+ SPA_TYPE_Long,
-+ SPA_TYPE_Float,
-+ SPA_TYPE_Double,
-+ SPA_TYPE_String,
-+ SPA_TYPE_Bytes,
-+ SPA_TYPE_Rectangle,
-+ SPA_TYPE_Fraction,
-+ SPA_TYPE_Bitmap,
-+ SPA_TYPE_Array,
-+ SPA_TYPE_Struct,
-+ SPA_TYPE_Object,
-+ SPA_TYPE_Sequence,
-+ SPA_TYPE_Pointer,
-+ SPA_TYPE_Fd,
-+ SPA_TYPE_Choice,
-+ SPA_TYPE_Pod,
-+ SPA_TYPE_LAST, /**< not part of ABI */
-+
-+ /* Pointers */
-+ SPA_TYPE_POINTER_START = 0x10000,
-+ SPA_TYPE_POINTER_Buffer,
-+ SPA_TYPE_POINTER_Meta,
-+ SPA_TYPE_POINTER_Dict,
-+ SPA_TYPE_POINTER_LAST, /**< not part of ABI */
-+
-+ /* Events */
-+ SPA_TYPE_EVENT_START = 0x20000,
-+ SPA_TYPE_EVENT_Device,
-+ SPA_TYPE_EVENT_Node,
-+ SPA_TYPE_EVENT_LAST, /**< not part of ABI */
-+
-+ /* Commands */
-+ SPA_TYPE_COMMAND_START = 0x30000,
-+ SPA_TYPE_COMMAND_Device,
-+ SPA_TYPE_COMMAND_Node,
-+ SPA_TYPE_COMMAND_LAST, /**< not part of ABI */
-+
-+ /* Objects */
-+ SPA_TYPE_OBJECT_START = 0x40000,
-+ SPA_TYPE_OBJECT_PropInfo,
-+ SPA_TYPE_OBJECT_Props,
-+ SPA_TYPE_OBJECT_Format,
-+ SPA_TYPE_OBJECT_ParamBuffers,
-+ SPA_TYPE_OBJECT_ParamMeta,
-+ SPA_TYPE_OBJECT_ParamIO,
-+ SPA_TYPE_OBJECT_ParamProfile,
-+ SPA_TYPE_OBJECT_ParamPortConfig,
-+ SPA_TYPE_OBJECT_ParamRoute,
-+ SPA_TYPE_OBJECT_Profiler,
-+ SPA_TYPE_OBJECT_LAST, /**< not part of ABI */
-+
-+ /* vendor extensions */
-+ SPA_TYPE_VENDOR_PipeWire = 0x02000000,
-+
-+ SPA_TYPE_VENDOR_Other = 0x7f000000,
-+};
-+
-+#define SPA_TYPE_INFO_BASE "Spa:"
-+
-+#define SPA_TYPE_INFO_Flags SPA_TYPE_INFO_BASE "Flags"
-+#define SPA_TYPE_INFO_FLAGS_BASE SPA_TYPE_INFO_Flags ":"
-+
-+#define SPA_TYPE_INFO_Enum SPA_TYPE_INFO_BASE "Enum"
-+#define SPA_TYPE_INFO_ENUM_BASE SPA_TYPE_INFO_Enum ":"
-+
-+#define SPA_TYPE_INFO_Pod SPA_TYPE_INFO_BASE "Pod"
-+#define SPA_TYPE_INFO_POD_BASE SPA_TYPE_INFO_Pod ":"
-+
-+#define SPA_TYPE_INFO_Struct SPA_TYPE_INFO_POD_BASE "Struct"
-+#define SPA_TYPE_INFO_STRUCT_BASE SPA_TYPE_INFO_Struct ":"
-+
-+#define SPA_TYPE_INFO_Object SPA_TYPE_INFO_POD_BASE "Object"
-+#define SPA_TYPE_INFO_OBJECT_BASE SPA_TYPE_INFO_Object ":"
-+
-+#define SPA_TYPE_INFO_Pointer SPA_TYPE_INFO_BASE "Pointer"
-+#define SPA_TYPE_INFO_POINTER_BASE SPA_TYPE_INFO_Pointer ":"
-+
-+#define SPA_TYPE_INFO_Interface SPA_TYPE_INFO_POINTER_BASE "Interface"
-+#define SPA_TYPE_INFO_INTERFACE_BASE SPA_TYPE_INFO_Interface ":"
-+
-+#define SPA_TYPE_INFO_Event SPA_TYPE_INFO_OBJECT_BASE "Event"
-+#define SPA_TYPE_INFO_EVENT_BASE SPA_TYPE_INFO_Event ":"
-+
-+#define SPA_TYPE_INFO_Command SPA_TYPE_INFO_OBJECT_BASE "Command"
-+#define SPA_TYPE_INFO_COMMAND_BASE SPA_TYPE_INFO_Command ":"
-+
-+struct spa_type_info {
-+ uint32_t type;
-+ uint32_t parent;
-+ const char *name;
-+ const struct spa_type_info *values;
-+};
-+
-+#ifdef __cplusplus
-+} /* extern "C" */
-+#endif
-+
-+#endif /* SPA_TYPE_H */
-
diff --git a/pw5.patch b/pw5.patch
deleted file mode 100644
index bcb004e..0000000
--- a/pw5.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-
-# HG changeset patch
-# User stransky <stransky@redhat.com>
-# Date 1605025841 0
-# Node ID e04be7688dfb4fbbe8dee73e366df8bc9a5da580
-# Parent 41d3c1292480de14d05b34aa0cf2d56015994878
-Bug 1675767 [Linux] Use PipeWire on Wayland desktop, r=dminor
-
-Differential Revision: https://phabricator.services.mozilla.com/D96587
-
-diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc
---- a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc
-+++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capturer.cc
-@@ -72,37 +72,21 @@ std::unique_ptr<DesktopCapturer> Desktop
- if (capturer && options.detect_updated_region()) {
- capturer.reset(new DesktopCapturerDifferWrapper(std::move(capturer)));
- }
-
- return capturer;
- }
-
- #if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
--// Return true if Firefox is actually running with Wayland backend.
--static bool IsWaylandDisplayUsed() {
-- const auto display = gdk_display_get_default();
-- if (display == nullptr) {
-- // We're running in headless mode.
-- return false;
-- }
-- return !GDK_IS_X11_DISPLAY(display);
--}
--
--// Return true if Firefox is actually running on Wayland enabled session.
--// It means some screensharing capabilities may be limited.
--static bool IsWaylandSessionUsed() {
-+bool DesktopCapturer::IsRunningUnderWayland() {
- const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
- if (!xdg_session_type || strncmp(xdg_session_type, "wayland", 7) != 0)
- return false;
-
- if (!(getenv("WAYLAND_DISPLAY")))
- return false;
-
- return true;
- }
--
--bool DesktopCapturer::IsRunningUnderWayland() {
-- return IsWaylandSessionUsed() ? IsWaylandDisplayUsed() : false;
--}
- #endif // defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
-
- } // namespace webrtc
-
diff --git a/pw6.patch b/pw6.patch
deleted file mode 100644
index 90f0879..0000000
--- a/pw6.patch
+++ /dev/null
@@ -1,163 +0,0 @@
-diff -up firefox-83.0/browser/actors/WebRTCParent.jsm.pw6 firefox-83.0/browser/actors/WebRTCParent.jsm
---- firefox-83.0/browser/actors/WebRTCParent.jsm.pw6 2020-11-12 19:04:30.000000000 +0100
-+++ firefox-83.0/browser/actors/WebRTCParent.jsm 2020-11-25 10:28:32.492865982 +0100
-@@ -45,6 +45,9 @@ XPCOMUtils.defineLazyServiceGetter(
- "nsIOSPermissionRequest"
- );
-
-+const PIPEWIRE_PORTAL_NAME = "####_PIPEWIRE_PORTAL_####";
-+const PIPEWIRE_ID = 0xaffffff;
-+
- class WebRTCParent extends JSWindowActorParent {
- didDestroy() {
- webrtcUI.forgetStreamsFromBrowserContext(this.browsingContext);
-@@ -753,6 +756,8 @@ function prompt(aActor, aBrowser, aReque
- );
- menupopup.appendChild(doc.createXULElement("menuseparator"));
-
-+ let isPipeWire = false;
-+
- // Build the list of 'devices'.
- let monitorIndex = 1;
- for (let i = 0; i < devices.length; ++i) {
-@@ -774,6 +779,29 @@ function prompt(aActor, aBrowser, aReque
- }
- } else {
- name = device.name;
-+ // When we share content by PipeWire add only one item to the device
-+ // list. When it's selected PipeWire portal dialog is opened and
-+ // user confirms actual window/screen sharing there.
-+ // Don't mark it as scary as there's an extra confirmation step by
-+ // PipeWire portal dialog.
-+ if (name == PIPEWIRE_PORTAL_NAME && device.id == PIPEWIRE_ID) {
-+ isPipeWire = true;
-+ let name;
-+ try {
-+ name = stringBundle.getString("getUserMedia.sharePipeWirePortal.label");
-+ } catch (err) {
-+ name = "Use operating system settings"
-+ }
-+ let item = addDeviceToList(
-+ menupopup,
-+ name,
-+ i,
-+ type
-+ );
-+ item.deviceId = device.id;
-+ item.mediaSource = type;
-+ break;
-+ }
- if (type == "application") {
- // The application names returned by the platform are of the form:
- // <window count>\x1e<application name>
-@@ -888,39 +916,41 @@ function prompt(aActor, aBrowser, aReque
- perms.EXPIRE_SESSION
- );
-
-- video.deviceId = deviceId;
-- let constraints = {
-- video: { mediaSource: type, deviceId: { exact: deviceId } },
-- };
-- chromeWin.navigator.mediaDevices.getUserMedia(constraints).then(
-- stream => {
-- if (video.deviceId != deviceId) {
-- // The user has selected a different device or closed the panel
-- // before getUserMedia finished.
-- stream.getTracks().forEach(t => t.stop());
-- return;
-- }
-- video.srcObject = stream;
-- video.stream = stream;
-- doc.getElementById("webRTC-preview").hidden = false;
-- video.onloadedmetadata = function(e) {
-- video.play();
-- };
-- },
-- err => {
-- if (
-- err.name == "OverconstrainedError" &&
-- err.constraint == "deviceId"
-- ) {
-- // Window has disappeared since enumeration, which can happen.
-- // No preview for you.
-- return;
-+ if (!isPipeWire) {
-+ video.deviceId = deviceId;
-+ let constraints = {
-+ video: { mediaSource: type, deviceId: { exact: deviceId } },
-+ };
-+ chromeWin.navigator.mediaDevices.getUserMedia(constraints).then(
-+ stream => {
-+ if (video.deviceId != deviceId) {
-+ // The user has selected a different device or closed the panel
-+ // before getUserMedia finished.
-+ stream.getTracks().forEach(t => t.stop());
-+ return;
-+ }
-+ video.srcObject = stream;
-+ video.stream = stream;
-+ doc.getElementById("webRTC-preview").hidden = false;
-+ video.onloadedmetadata = function(e) {
-+ video.play();
-+ };
-+ },
-+ err => {
-+ if (
-+ err.name == "OverconstrainedError" &&
-+ err.constraint == "deviceId"
-+ ) {
-+ // Window has disappeared since enumeration, which can happen.
-+ // No preview for you.
-+ return;
-+ }
-+ Cu.reportError(
-+ `error in preview: ${err.message} ${err.constraint}`
-+ );
- }
-- Cu.reportError(
-- `error in preview: ${err.message} ${err.constraint}`
-- );
-- }
-- );
-+ );
-+ }
- };
- menupopup.addEventListener("command", menupopup._commandEventListener);
- }
-diff -up firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties.pw6 firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties
---- firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties.pw6 2020-11-12 19:04:30.000000000 +0100
-+++ firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties 2020-11-25 09:24:26.378857626 +0100
-@@ -764,6 +764,7 @@ getUserMedia.selectWindowOrScreen.label=
- getUserMedia.selectWindowOrScreen.accesskey=W
- getUserMedia.pickWindowOrScreen.label = Select Window or Screen
- getUserMedia.shareEntireScreen.label = Entire screen
-+getUserMedia.sharePipeWirePortal.label = Use operating system settings
- # LOCALIZATION NOTE (getUserMedia.shareMonitor.label):
- # %S is screen number (digits 1, 2, etc)
- # Example: Screen 1, Screen 2,..
-diff -up firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc.pw6 firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
---- firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc.pw6 2020-11-25 09:24:26.358857788 +0100
-+++ firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc 2020-11-25 09:24:26.378857626 +0100
-@@ -879,17 +879,17 @@ void BaseCapturerPipeWire::CaptureFrame(
- callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
- }
-
-+#define PIPEWIRE_ID 0xaffffff
-+#define PIPEWIRE_NAME "####_PIPEWIRE_PORTAL_####"
-+
- bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) {
-- RTC_DCHECK(sources->size() == 0);
-- // List of available screens is already presented by the xdg-desktop-portal.
-- // But we have to add an empty source as the code expects it.
-- sources->push_back({0});
-+ sources->push_back({PIPEWIRE_ID, 0, PIPEWIRE_NAME});
- return true;
- }
-
- bool BaseCapturerPipeWire::SelectSource(SourceId id) {
- // Screen selection is handled by the xdg-desktop-portal.
-- return true;
-+ return id == PIPEWIRE_ID;
- }
-
- // static
diff --git a/sources b/sources
index 0a077ef..91c83fd 100644
--- a/sources
+++ b/sources
@@ -1,4 +1,4 @@
SHA512 (cbindgen-vendor.tar.xz) = 3c925c5523246b7dfbcb4ce563483d5b45315a06dc90f2cf07cddef0c263dd15b410afbbe4d86594de96a308e93be3b27ffec01f5f759a42ecba3cc983b1677f
SHA512 (mochitest-python.tar.gz) = 7f357cb8bd93d64be5cb75819a8a813d2f8f217ff25f0df8c3190910744132405d45797b3900775a44b554f5c70cf2682809c9e7a686ca131fddcd81e98028d9
-SHA512 (firefox-84.0.2.source.tar.xz) = 3fd4c9a5ec2409f23507b38c809e71a35aa674779dc5a7a2e3ff82841e0b65ead29d38ac4d5b17f7108479ed7338b3d2b40cbcfa9c51e01696634166d92edf99
-SHA512 (firefox-langpacks-84.0.2-20210106.tar.xz) = 49b6bae80031d70a413a1e5033e7b8d2625ad687bbbbda7ade4e523c549c6a46af5f29de7bf538e0e464ea17734fcd43ba2e015cc190f93af4e3b88d3f50ccde
+SHA512 (firefox-85.0.source.tar.xz) = a88472e66baab32d98cb9d13d7dd3c41b47a697ce2a42209612d2342bd6c1c26cd80cdd8905a4cecc72895f155df09762735e8af24bc6156663b7a14e890be4e
+SHA512 (firefox-langpacks-85.0-20210120.tar.xz) = ec4b720d74940849f90831de72c5b7bdc004075e4a9b3b966c218b87e4ff9c3c10117a193d947cd971db955f1f3be99d7af706f981b8c0195c16936b1a10881e
bgstack15