diff --git a/D145871.diff b/D145871.diff deleted file mode 100644 index 33a2e61..0000000 --- a/D145871.diff +++ /dev/null @@ -1,140 +0,0 @@ -diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h ---- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h -+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h -@@ -146,10 +146,15 @@ - RefPtr mImageContainer; - VideoInfo mInfo; - int mDecodedFrames; - #if LIBAVCODEC_VERSION_MAJOR >= 58 - int mDecodedFramesLate; -+ // Tracks when decode time of recent frame and averange decode time of -+ // previous frames is bigger than frame interval, -+ // i.e. we fail to decode in time. -+ // We switch to SW decode when we hit HW_DECODE_LATE_FRAMES treshold. -+ int mMissedDecodeInAverangeTime; - #endif - float mAverangeDecodeTime; - - class PtsCorrectionContext { - public: -diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp ---- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -@@ -14,10 +14,13 @@ - #include "VPXDecoder.h" - #include "mozilla/layers/KnowsCompositor.h" - #if LIBAVCODEC_VERSION_MAJOR >= 57 - # include "mozilla/layers/TextureClient.h" - #endif -+#if LIBAVCODEC_VERSION_MAJOR >= 58 -+# include "mozilla/ProfilerMarkers.h" -+#endif - #ifdef MOZ_WAYLAND_USE_VAAPI - # include "H264.h" - # include "mozilla/layers/DMABUFSurfaceImage.h" - # include "mozilla/widget/DMABufLibWrapper.h" - # include "FFmpegVideoFramePool.h" -@@ -56,13 +59,14 @@ - typedef int VAStatus; - # define VA_EXPORT_SURFACE_READ_ONLY 0x0001 - # define VA_EXPORT_SURFACE_SEPARATE_LAYERS 0x0004 - # define VA_STATUS_SUCCESS 0x00000000 - #endif -- - // Use some extra HW frames for potential rendering lags. - #define EXTRA_HW_FRAMES 6 -+// Defines number of delayed frames until we switch back to SW decode. -+#define HW_DECODE_LATE_FRAMES 15 - - #if LIBAVCODEC_VERSION_MAJOR >= 57 && LIBAVUTIL_VERSION_MAJOR >= 56 - # define CUSTOMIZED_BUFFER_ALLOCATION 1 - #endif - -@@ -386,10 +390,11 @@ - mImageContainer(aImageContainer), - mInfo(aConfig), - mDecodedFrames(0), - #if LIBAVCODEC_VERSION_MAJOR >= 58 - mDecodedFramesLate(0), -+ mMissedDecodeInAverangeTime(0), - #endif - mAverangeDecodeTime(0), - mLowLatency(aLowLatency) { - FFMPEG_LOG("FFmpegVideoDecoder::FFmpegVideoDecoder MIME %s Codec ID %d", - aConfig.mMimeType.get(), mCodecID); -@@ -781,22 +786,32 @@ - float decodeTime = (TimeStamp::Now() - aDecodeStart).ToMilliseconds(); - mAverangeDecodeTime = - (mAverangeDecodeTime * (mDecodedFrames - 1) + decodeTime) / - mDecodedFrames; - FFMPEG_LOG( -- " decode time %.2f ms averange decode time %.2f ms decoded frames %d\n", -+ "Frame decode finished, time %.2f ms averange decode time %.2f ms " -+ "decoded %d frames\n", - decodeTime, mAverangeDecodeTime, mDecodedFrames); - #if LIBAVCODEC_VERSION_MAJOR >= 58 -- int frameDuration = mFrame->pkt_duration; -- if (frameDuration > 0 && frameDuration / 1000.0 < decodeTime) { -- mDecodedFramesLate++; -- FFMPEG_LOG( -- " slow decode: failed to decode in time, frame duration %.2f ms, " -- "decode time %.2f\n", -- frameDuration / 1000.0, decodeTime); -- FFMPEG_LOG(" all decoded frames / late decoded frames %d/%d\n", -- mDecodedFrames, mDecodedFramesLate); -+ if (mFrame->pkt_duration > 0) { -+ // Switch frame duration to ms -+ float frameDuration = mFrame->pkt_duration / 1000.0f; -+ if (frameDuration < decodeTime) { -+ PROFILER_MARKER_TEXT("FFmpegVideoDecoder::DoDecode", MEDIA_PLAYBACK, {}, -+ "frame decode takes too long"); -+ mDecodedFramesLate++; -+ if (frameDuration < mAverangeDecodeTime) { -+ mMissedDecodeInAverangeTime++; -+ } -+ FFMPEG_LOG( -+ " slow decode: failed to decode in time, frame duration %.2f ms, " -+ "decode time %.2f\n", -+ frameDuration, decodeTime); -+ FFMPEG_LOG(" frames: all decoded %d late decoded %d over averange %d\n", -+ mDecodedFrames, mDecodedFramesLate, -+ mMissedDecodeInAverangeTime); -+ } - } - #endif - } - - MediaResult FFmpegVideoDecoder::DoDecode( -@@ -866,10 +881,18 @@ - decodeStart = TimeStamp::Now(); - - MediaResult rv; - # ifdef MOZ_WAYLAND_USE_VAAPI - if (IsHardwareAccelerated()) { -+ if (mMissedDecodeInAverangeTime > HW_DECODE_LATE_FRAMES) { -+ PROFILER_MARKER_TEXT("FFmpegVideoDecoder::DoDecode", MEDIA_PLAYBACK, {}, -+ "Fallback to SW decode"); -+ FFMPEG_LOG(" HW decoding is slow, switch back to SW decode"); -+ return MediaResult( -+ NS_ERROR_DOM_MEDIA_DECODE_ERR, -+ RESULT_DETAIL("HW decoding is slow, switch back to SW decode")); -+ } - rv = CreateImageVAAPI(mFrame->pkt_pos, GetFramePts(mFrame), - mFrame->pkt_duration, aResults); - // If VA-API playback failed, just quit. Decoder is going to be restarted - // without VA-API. - if (NS_FAILED(rv)) { -@@ -1129,11 +1152,11 @@ - } - - MediaResult FFmpegVideoDecoder::CreateImageVAAPI( - int64_t aOffset, int64_t aPts, int64_t aDuration, - MediaDataDecoder::DecodedData& aResults) { -- FFMPEG_LOG("VA-API Got one frame output with pts=%" PRId64 "dts=%" PRId64 -+ FFMPEG_LOG("VA-API Got one frame output with pts=%" PRId64 " dts=%" PRId64 - " duration=%" PRId64 " opaque=%" PRId64, - aPts, mFrame->pkt_dts, aDuration, mCodecContext->reordered_opaque); - - VADRMPRIMESurfaceDescriptor vaDesc; - if (!GetVAAPISurfaceDescriptor(&vaDesc)) { - diff --git a/D145966.diff b/D145966.diff deleted file mode 100644 index 2ecfaec..0000000 --- a/D145966.diff +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp ---- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -@@ -780,12 +780,13 @@ - mDecodedFrames++; - float decodeTime = (TimeStamp::Now() - aDecodeStart).ToMilliseconds(); - mAverangeDecodeTime = - (mAverangeDecodeTime * (mDecodedFrames - 1) + decodeTime) / - mDecodedFrames; -- FFMPEG_LOG(" averange frame decode time %.2f ms decoded frames %d\n", -- mAverangeDecodeTime, mDecodedFrames); -+ FFMPEG_LOG( -+ " decode time %.2f ms averange decode time %.2f ms decoded frames %d\n", -+ decodeTime, mAverangeDecodeTime, mDecodedFrames); - #if LIBAVCODEC_VERSION_MAJOR >= 58 - int frameDuration = mFrame->pkt_duration; - if (frameDuration > 0 && frameDuration / 1000.0 < decodeTime) { - mDecodedFramesLate++; - FFMPEG_LOG( - diff --git a/D146271.diff b/D146271.diff deleted file mode 100644 index fd2e0b0..0000000 --- a/D146271.diff +++ /dev/null @@ -1,94 +0,0 @@ -diff -up firefox-101.0/security/sandbox/linux/SandboxFilter.cpp.D146271.diff firefox-101.0/security/sandbox/linux/SandboxFilter.cpp ---- firefox-101.0/security/sandbox/linux/SandboxFilter.cpp.D146271.diff 2022-05-27 01:16:59.000000000 +0200 -+++ firefox-101.0/security/sandbox/linux/SandboxFilter.cpp 2022-06-09 09:59:35.569235176 +0200 -@@ -125,28 +125,12 @@ namespace mozilla { - // denied if no broker client is provided by the concrete class. - class SandboxPolicyCommon : public SandboxPolicyBase { - protected: -- enum class ShmemUsage : uint8_t { -- MAY_CREATE, -- ONLY_USE, -- }; -- -- enum class AllowUnsafeSocketPair : uint8_t { -- NO, -- YES, -- }; -- -+ // Subclasses can assign these in their constructors to loosen the -+ // default settings. - SandboxBrokerClient* mBroker = nullptr; - bool mMayCreateShmem = false; - bool mAllowUnsafeSocketPair = false; - -- explicit SandboxPolicyCommon(SandboxBrokerClient* aBroker, -- ShmemUsage aShmemUsage, -- AllowUnsafeSocketPair aAllowUnsafeSocketPair) -- : mBroker(aBroker), -- mMayCreateShmem(aShmemUsage == ShmemUsage::MAY_CREATE), -- mAllowUnsafeSocketPair(aAllowUnsafeSocketPair == -- AllowUnsafeSocketPair::YES) {} -- - SandboxPolicyCommon() = default; - - typedef const sandbox::arch_seccomp_data& ArgsRef; -@@ -1228,11 +1212,13 @@ class ContentSandboxPolicy : public Sand - public: - ContentSandboxPolicy(SandboxBrokerClient* aBroker, - ContentProcessSandboxParams&& aParams) -- : SandboxPolicyCommon(aBroker, ShmemUsage::MAY_CREATE, -- AllowUnsafeSocketPair::YES), -- mParams(std::move(aParams)), -+ : mParams(std::move(aParams)), - mAllowSysV(PR_GetEnv("MOZ_SANDBOX_ALLOW_SYSV") != nullptr), -- mUsingRenderDoc(PR_GetEnv("RENDERDOC_CAPTUREOPTS") != nullptr) {} -+ mUsingRenderDoc(PR_GetEnv("RENDERDOC_CAPTUREOPTS") != nullptr) { -+ mBroker = aBroker; -+ mMayCreateShmem = true; -+ mAllowUnsafeSocketPair = true; -+ } - - ~ContentSandboxPolicy() override = default; - -@@ -1762,9 +1748,10 @@ UniquePtr GetM - // segments, so it may need file brokering. - class RDDSandboxPolicy final : public SandboxPolicyCommon { - public: -- explicit RDDSandboxPolicy(SandboxBrokerClient* aBroker) -- : SandboxPolicyCommon(aBroker, ShmemUsage::MAY_CREATE, -- AllowUnsafeSocketPair::NO) {} -+ explicit RDDSandboxPolicy(SandboxBrokerClient* aBroker) { -+ mBroker = aBroker; -+ mMayCreateShmem = true; -+ } - - #ifndef ANDROID - Maybe EvaluateIpcCall(int aCall, int aArgShift) const override { -@@ -1875,9 +1862,10 @@ UniquePtr GetD - // the SocketProcess sandbox looks like. - class SocketProcessSandboxPolicy final : public SandboxPolicyCommon { - public: -- explicit SocketProcessSandboxPolicy(SandboxBrokerClient* aBroker) -- : SandboxPolicyCommon(aBroker, ShmemUsage::MAY_CREATE, -- AllowUnsafeSocketPair::NO) {} -+ explicit SocketProcessSandboxPolicy(SandboxBrokerClient* aBroker) { -+ mBroker = aBroker; -+ mMayCreateShmem = true; -+ } - - static intptr_t FcntlTrap(const sandbox::arch_seccomp_data& aArgs, - void* aux) { -@@ -2013,9 +2001,10 @@ UniquePtr GetS - - class UtilitySandboxPolicy : public SandboxPolicyCommon { - public: -- explicit UtilitySandboxPolicy(SandboxBrokerClient* aBroker) -- : SandboxPolicyCommon(aBroker, ShmemUsage::MAY_CREATE, -- AllowUnsafeSocketPair::NO) {} -+ explicit UtilitySandboxPolicy(SandboxBrokerClient* aBroker) { -+ mBroker = aBroker; -+ mMayCreateShmem = true; -+ } - - ResultExpr PrctlPolicy() const override { - Arg op(0); diff --git a/D146272.diff b/D146272.diff deleted file mode 100644 index 0a2c749..0000000 --- a/D146272.diff +++ /dev/null @@ -1,373 +0,0 @@ -diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp ---- a/security/sandbox/linux/SandboxFilter.cpp -+++ b/security/sandbox/linux/SandboxFilter.cpp -@@ -128,10 +128,11 @@ - // Subclasses can assign these in their constructors to loosen the - // default settings. - SandboxBrokerClient* mBroker = nullptr; - bool mMayCreateShmem = false; - bool mAllowUnsafeSocketPair = false; -+ bool mBrokeredConnect = false; // Can connect() be brokered? - - SandboxPolicyCommon() = default; - - typedef const sandbox::arch_seccomp_data& ArgsRef; - -@@ -533,10 +534,124 @@ - MOZ_CRASH("unreachable?"); - return -ENOSYS; - #endif - } - -+ // This just needs to return something to stand in for the -+ // unconnected socket until ConnectTrap, below, and keep track of -+ // the socket type somehow. Half a socketpair *is* a socket, so it -+ // should result in minimal confusion in the caller. -+ static intptr_t FakeSocketTrapCommon(int domain, int type, int protocol) { -+ int fds[2]; -+ // X11 client libs will still try to getaddrinfo() even for a -+ // local connection. Also, WebRTC still has vestigial network -+ // code trying to do things in the content process. Politely tell -+ // them no. -+ if (domain != AF_UNIX) { -+ return -EAFNOSUPPORT; -+ } -+ if (socketpair(domain, type, protocol, fds) != 0) { -+ return -errno; -+ } -+ close(fds[1]); -+ return fds[0]; -+ } -+ -+ static intptr_t FakeSocketTrap(ArgsRef aArgs, void* aux) { -+ return FakeSocketTrapCommon(static_cast(aArgs.args[0]), -+ static_cast(aArgs.args[1]), -+ static_cast(aArgs.args[2])); -+ } -+ -+ static intptr_t FakeSocketTrapLegacy(ArgsRef aArgs, void* aux) { -+ const auto innerArgs = reinterpret_cast(aArgs.args[1]); -+ -+ return FakeSocketTrapCommon(static_cast(innerArgs[0]), -+ static_cast(innerArgs[1]), -+ static_cast(innerArgs[2])); -+ } -+ -+ static Maybe DoGetSockOpt(int fd, int optname) { -+ int optval; -+ socklen_t optlen = sizeof(optval); -+ -+ if (getsockopt(fd, SOL_SOCKET, optname, &optval, &optlen) != 0) { -+ return Nothing(); -+ } -+ MOZ_RELEASE_ASSERT(static_cast(optlen) == sizeof(optval)); -+ return Some(optval); -+ } -+ -+ // Substitute the newly connected socket from the broker for the -+ // original socket. This is meant to be used on a fd from -+ // FakeSocketTrap, above, but it should also work to simulate -+ // re-connect()ing a real connected socket. -+ // -+ // Warning: This isn't quite right if the socket is dup()ed, because -+ // other duplicates will still be the original socket, but hopefully -+ // nothing we're dealing with does that. -+ static intptr_t ConnectTrapCommon(SandboxBrokerClient* aBroker, int aFd, -+ const struct sockaddr_un* aAddr, -+ socklen_t aLen) { -+ if (aFd < 0) { -+ return -EBADF; -+ } -+ const auto maybeDomain = DoGetSockOpt(aFd, SO_DOMAIN); -+ if (!maybeDomain) { -+ return -errno; -+ } -+ if (*maybeDomain != AF_UNIX) { -+ return -EAFNOSUPPORT; -+ } -+ const auto maybeType = DoGetSockOpt(aFd, SO_TYPE); -+ if (!maybeType) { -+ return -errno; -+ } -+ const int oldFlags = fcntl(aFd, F_GETFL); -+ if (oldFlags == -1) { -+ return -errno; -+ } -+ const int newFd = aBroker->Connect(aAddr, aLen, *maybeType); -+ if (newFd < 0) { -+ return newFd; -+ } -+ // Copy over the nonblocking flag. The connect() won't be -+ // nonblocking in that case, but that shouldn't matter for -+ // AF_UNIX. The other fcntl-settable flags are either irrelevant -+ // for sockets (e.g., O_APPEND) or would be blocked by this -+ // seccomp-bpf policy, so they're ignored. -+ if (fcntl(newFd, F_SETFL, oldFlags & O_NONBLOCK) != 0) { -+ close(newFd); -+ return -errno; -+ } -+ if (dup2(newFd, aFd) < 0) { -+ close(newFd); -+ return -errno; -+ } -+ close(newFd); -+ return 0; -+ } -+ -+ static intptr_t ConnectTrap(ArgsRef aArgs, void* aux) { -+ typedef const struct sockaddr_un* AddrPtr; -+ -+ return ConnectTrapCommon(static_cast(aux), -+ static_cast(aArgs.args[0]), -+ reinterpret_cast(aArgs.args[1]), -+ static_cast(aArgs.args[2])); -+ } -+ -+ static intptr_t ConnectTrapLegacy(ArgsRef aArgs, void* aux) { -+ const auto innerArgs = reinterpret_cast(aArgs.args[1]); -+ typedef const struct sockaddr_un* AddrPtr; -+ -+ return ConnectTrapCommon(static_cast(aux), -+ static_cast(innerArgs[0]), -+ reinterpret_cast(innerArgs[1]), -+ static_cast(innerArgs[2])); -+ } -+ - public: - ResultExpr InvalidSyscall() const override { - return Trap(BlockedSyscallTrap, nullptr); - } - -@@ -630,15 +745,37 @@ - return Some(Allow()); - } - Arg level(1), optname(2); - // SO_SNDBUF is used by IPC to avoid constructing - // unnecessarily large gather arrays for `sendmsg`. -- return Some( -- If(AllOf(level == SOL_SOCKET, optname == SO_SNDBUF), Allow()) -- .Else(InvalidSyscall())); -+ // -+ // SO_DOMAIN and SO_TYPE are needed for connect() brokering, -+ // but they're harmless even when it's not enabled. -+ return Some(If(AllOf(level == SOL_SOCKET, -+ AnyOf(optname == SO_SNDBUF, optname == SO_DOMAIN, -+ optname == SO_TYPE)), -+ Allow()) -+ .Else(InvalidSyscall())); - } - -+ // These two cases are for connect() brokering, if enabled. -+ case SYS_SOCKET: -+ if (mBrokeredConnect) { -+ const auto trapFn = aHasArgs ? FakeSocketTrap : FakeSocketTrapLegacy; -+ MOZ_ASSERT(mBroker); -+ return Some(Trap(trapFn, mBroker)); -+ } -+ return Nothing(); -+ -+ case SYS_CONNECT: -+ if (mBrokeredConnect) { -+ const auto trapFn = aHasArgs ? ConnectTrap : ConnectTrapLegacy; -+ MOZ_ASSERT(mBroker); -+ return Some(Trap(trapFn, mBroker)); -+ } -+ return Nothing(); -+ - default: - return Nothing(); - } - } - -@@ -1006,10 +1143,16 @@ - return If(AnyOf(request == TCGETS, request == TIOCGWINSZ), - Error(ENOTTY)) - .Else(SandboxPolicyBase::EvaluateSyscall(sysno)); - } - -+ CASES_FOR_dup2: // See ConnectTrapCommon -+ if (mBrokeredConnect) { -+ return Allow(); -+ } -+ return SandboxPolicyBase::EvaluateSyscall(sysno); -+ - #ifdef MOZ_ASAN - // ASAN's error reporter wants to know if stderr is a tty. - case __NR_ioctl: { - Arg fd(0); - return If(fd == STDERR_FILENO, Error(ENOTTY)).Else(InvalidSyscall()); -@@ -1093,133 +1236,20 @@ - - close(fd); - return rv; - } - -- // This just needs to return something to stand in for the -- // unconnected socket until ConnectTrap, below, and keep track of -- // the socket type somehow. Half a socketpair *is* a socket, so it -- // should result in minimal confusion in the caller. -- static intptr_t FakeSocketTrapCommon(int domain, int type, int protocol) { -- int fds[2]; -- // X11 client libs will still try to getaddrinfo() even for a -- // local connection. Also, WebRTC still has vestigial network -- // code trying to do things in the content process. Politely tell -- // them no. -- if (domain != AF_UNIX) { -- return -EAFNOSUPPORT; -- } -- if (socketpair(domain, type, protocol, fds) != 0) { -- return -errno; -- } -- close(fds[1]); -- return fds[0]; -- } -- -- static intptr_t FakeSocketTrap(ArgsRef aArgs, void* aux) { -- return FakeSocketTrapCommon(static_cast(aArgs.args[0]), -- static_cast(aArgs.args[1]), -- static_cast(aArgs.args[2])); -- } -- -- static intptr_t FakeSocketTrapLegacy(ArgsRef aArgs, void* aux) { -- const auto innerArgs = reinterpret_cast(aArgs.args[1]); -- -- return FakeSocketTrapCommon(static_cast(innerArgs[0]), -- static_cast(innerArgs[1]), -- static_cast(innerArgs[2])); -- } -- -- static Maybe DoGetSockOpt(int fd, int optname) { -- int optval; -- socklen_t optlen = sizeof(optval); -- -- if (getsockopt(fd, SOL_SOCKET, optname, &optval, &optlen) != 0) { -- return Nothing(); -- } -- MOZ_RELEASE_ASSERT(static_cast(optlen) == sizeof(optval)); -- return Some(optval); -- } -- -- // Substitute the newly connected socket from the broker for the -- // original socket. This is meant to be used on a fd from -- // FakeSocketTrap, above, but it should also work to simulate -- // re-connect()ing a real connected socket. -- // -- // Warning: This isn't quite right if the socket is dup()ed, because -- // other duplicates will still be the original socket, but hopefully -- // nothing we're dealing with does that. -- static intptr_t ConnectTrapCommon(SandboxBrokerClient* aBroker, int aFd, -- const struct sockaddr_un* aAddr, -- socklen_t aLen) { -- if (aFd < 0) { -- return -EBADF; -- } -- const auto maybeDomain = DoGetSockOpt(aFd, SO_DOMAIN); -- if (!maybeDomain) { -- return -errno; -- } -- if (*maybeDomain != AF_UNIX) { -- return -EAFNOSUPPORT; -- } -- const auto maybeType = DoGetSockOpt(aFd, SO_TYPE); -- if (!maybeType) { -- return -errno; -- } -- const int oldFlags = fcntl(aFd, F_GETFL); -- if (oldFlags == -1) { -- return -errno; -- } -- const int newFd = aBroker->Connect(aAddr, aLen, *maybeType); -- if (newFd < 0) { -- return newFd; -- } -- // Copy over the nonblocking flag. The connect() won't be -- // nonblocking in that case, but that shouldn't matter for -- // AF_UNIX. The other fcntl-settable flags are either irrelevant -- // for sockets (e.g., O_APPEND) or would be blocked by this -- // seccomp-bpf policy, so they're ignored. -- if (fcntl(newFd, F_SETFL, oldFlags & O_NONBLOCK) != 0) { -- close(newFd); -- return -errno; -- } -- if (dup2(newFd, aFd) < 0) { -- close(newFd); -- return -errno; -- } -- close(newFd); -- return 0; -- } -- -- static intptr_t ConnectTrap(ArgsRef aArgs, void* aux) { -- typedef const struct sockaddr_un* AddrPtr; -- -- return ConnectTrapCommon(static_cast(aux), -- static_cast(aArgs.args[0]), -- reinterpret_cast(aArgs.args[1]), -- static_cast(aArgs.args[2])); -- } -- -- static intptr_t ConnectTrapLegacy(ArgsRef aArgs, void* aux) { -- const auto innerArgs = reinterpret_cast(aArgs.args[1]); -- typedef const struct sockaddr_un* AddrPtr; -- -- return ConnectTrapCommon(static_cast(aux), -- static_cast(innerArgs[0]), -- reinterpret_cast(innerArgs[1]), -- static_cast(innerArgs[2])); -- } -- - public: - ContentSandboxPolicy(SandboxBrokerClient* aBroker, - ContentProcessSandboxParams&& aParams) - : mParams(std::move(aParams)), - mAllowSysV(PR_GetEnv("MOZ_SANDBOX_ALLOW_SYSV") != nullptr), - mUsingRenderDoc(PR_GetEnv("RENDERDOC_CAPTUREOPTS") != nullptr) { - mBroker = aBroker; - mMayCreateShmem = true; - mAllowUnsafeSocketPair = true; -+ mBrokeredConnect = true; - } - - ~ContentSandboxPolicy() override = default; - - Maybe EvaluateSocketCall(int aCall, -@@ -1232,18 +1262,16 @@ - - #ifdef ANDROID - case SYS_SOCKET: - return Some(Error(EACCES)); - #else // #ifdef DESKTOP -- case SYS_SOCKET: { -- const auto trapFn = aHasArgs ? FakeSocketTrap : FakeSocketTrapLegacy; -- return Some(AllowBelowLevel(4, Trap(trapFn, nullptr))); -- } -- case SYS_CONNECT: { -- const auto trapFn = aHasArgs ? ConnectTrap : ConnectTrapLegacy; -- return Some(AllowBelowLevel(4, Trap(trapFn, mBroker))); -- } -+ case SYS_SOCKET: -+ case SYS_CONNECT: -+ if (BelowLevel(4)) { -+ return Some(Allow()); -+ } -+ return SandboxPolicyCommon::EvaluateSocketCall(aCall, aHasArgs); - case SYS_RECV: - case SYS_SEND: - case SYS_GETSOCKOPT: - case SYS_SETSOCKOPT: - case SYS_GETSOCKNAME: -@@ -1458,13 +1486,10 @@ - - case __NR_getrusage: - case __NR_times: - return Allow(); - -- CASES_FOR_dup2: // See ConnectTrapCommon -- return Allow(); -- - case __NR_fsync: - case __NR_msync: - return Allow(); - - case __NR_getpriority: - diff --git a/D146273.diff b/D146273.diff deleted file mode 100644 index 0d838e2..0000000 --- a/D146273.diff +++ /dev/null @@ -1,90 +0,0 @@ -diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp ---- a/security/sandbox/linux/SandboxFilter.cpp -+++ b/security/sandbox/linux/SandboxFilter.cpp -@@ -699,10 +699,18 @@ - Maybe EvaluateSocketCall(int aCall, - bool aHasArgs) const override { - switch (aCall) { - case SYS_RECVMSG: - case SYS_SENDMSG: -+ // These next four aren't needed for IPC or other core -+ // functionality at the time of this writing, but they're -+ // subsets of recvmsg/sendmsg so there's nothing gained by not -+ // allowing them here (and simplifying subclasses). -+ case SYS_RECVFROM: -+ case SYS_SENDTO: -+ case SYS_RECV: -+ case SYS_SEND: - return Some(Allow()); - - case SYS_SOCKETPAIR: { - // We try to allow "safe" (always connected) socketpairs when using the - // file broker, or for content processes, but we may need to fall back -@@ -1253,12 +1261,10 @@ - ~ContentSandboxPolicy() override = default; - - Maybe EvaluateSocketCall(int aCall, - bool aHasArgs) const override { - switch (aCall) { -- case SYS_RECVFROM: -- case SYS_SENDTO: - case SYS_SENDMMSG: // libresolv via libasyncns; see bug 1355274 - return Some(Allow()); - - #ifdef ANDROID - case SYS_SOCKET: -@@ -1268,18 +1274,21 @@ - case SYS_CONNECT: - if (BelowLevel(4)) { - return Some(Allow()); - } - return SandboxPolicyCommon::EvaluateSocketCall(aCall, aHasArgs); -- case SYS_RECV: -- case SYS_SEND: -+ -+ // FIXME (bug 1761134): sockopts should be filtered - case SYS_GETSOCKOPT: - case SYS_SETSOCKOPT: -+ // These next 3 were needed for X11; they may not be needed -+ // with X11 lockdown, but there's not much attack surface here. - case SYS_GETSOCKNAME: - case SYS_GETPEERNAME: - case SYS_SHUTDOWN: - return Some(Allow()); -+ - case SYS_ACCEPT: - case SYS_ACCEPT4: - if (mUsingRenderDoc) { - return Some(Allow()); - } -@@ -1908,26 +1917,19 @@ - } - - Maybe EvaluateSocketCall(int aCall, - bool aHasArgs) const override { - switch (aCall) { -+ case SYS_SOCKET: -+ case SYS_CONNECT: - case SYS_BIND: - return Some(Allow()); - -- case SYS_SOCKET: -- return Some(Allow()); -- -- case SYS_CONNECT: -- return Some(Allow()); -- -- case SYS_RECVFROM: -- case SYS_SENDTO: -+ // FIXME(bug 1641401) do we really need this? - case SYS_SENDMMSG: - return Some(Allow()); - -- case SYS_RECV: -- case SYS_SEND: - case SYS_GETSOCKOPT: - case SYS_SETSOCKOPT: - case SYS_GETSOCKNAME: - case SYS_GETPEERNAME: - case SYS_SHUTDOWN: - diff --git a/D146274.diff b/D146274.diff deleted file mode 100644 index 8943ac4..0000000 --- a/D146274.diff +++ /dev/null @@ -1,158 +0,0 @@ -diff --git a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp ---- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp -+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp -@@ -325,30 +325,84 @@ - policy->AddDynamic(perms, trimPath.get()); - } - } - } - -+static void AddX11Dependencies(SandboxBroker::Policy* policy) { -+ // Allow Primus to contact the Bumblebee daemon to manage GPU -+ // switching on NVIDIA Optimus systems. -+ const char* bumblebeeSocket = PR_GetEnv("BUMBLEBEE_SOCKET"); -+ if (bumblebeeSocket == nullptr) { -+ bumblebeeSocket = "/var/run/bumblebee.socket"; -+ } -+ policy->AddPath(SandboxBroker::MAY_CONNECT, bumblebeeSocket); -+ -+#if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11) -+ // Allow local X11 connections, for several purposes: -+ // -+ // * for content processes to use WebGL when the browser is in headless -+ // mode, by opening the X display if/when needed -+ // -+ // * if Primus or VirtualGL is used, to contact the secondary X server -+ static const bool kIsX11 = -+ !mozilla::widget::GdkIsWaylandDisplay() && PR_GetEnv("DISPLAY"); -+ if (kIsX11) { -+ policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X"); -+ if (auto* const xauth = PR_GetEnv("XAUTHORITY")) { -+ policy->AddPath(rdonly, xauth); -+ } else if (auto* const home = PR_GetEnv("HOME")) { -+ // This follows the logic in libXau: append "/.Xauthority", -+ // even if $HOME ends in a slash, except in the special case -+ // where HOME=/ because POSIX allows implementations to treat -+ // an initial double slash specially. -+ nsAutoCString xauth(home); -+ if (xauth != "/"_ns) { -+ xauth.Append('/'); -+ } -+ xauth.AppendLiteral(".Xauthority"); -+ policy->AddPath(rdonly, xauth.get()); -+ } -+ } -+#endif -+} -+ -+static void AddGLDependencies(SandboxBroker::Policy* policy) { -+ // Devices -+ policy->AddDir(rdwr, "/dev/dri"); -+ policy->AddFilePrefix(rdwr, "/dev", "nvidia"); -+ -+ // Hardware info -+ AddDriPaths(policy); -+ -+ // /etc and /usr/share (glvnd, libdrm, drirc, ...?) -+ policy->AddDir(rdonly, "/etc"); -+ policy->AddDir(rdonly, "/usr/share"); -+ policy->AddDir(rdonly, "/usr/local/share"); -+ -+ // Note: This function doesn't do anything about Mesa's shader -+ // cache, because the details can vary by process type, including -+ // whether caching is enabled. -+ -+ AddX11Dependencies(policy); -+} -+ - void SandboxBrokerPolicyFactory::InitContentPolicy() { - const bool headless = - StaticPrefs::security_sandbox_content_headless_AtStartup(); - - // Policy entries that are the same in every process go here, and - // are cached over the lifetime of the factory. - SandboxBroker::Policy* policy = new SandboxBroker::Policy; - // Write permssions -- // -- if (!headless) { -- // Bug 1308851: NVIDIA proprietary driver when using WebGL -- policy->AddFilePrefix(rdwr, "/dev", "nvidia"); -- -- // Bug 1312678: Mesa with DRI when using WebGL -- policy->AddDir(rdwr, "/dev/dri"); -- } - - // Bug 1575985: WASM library sandbox needs RW access to /dev/null - policy->AddPath(rdwr, "/dev/null"); - -+ if (!headless) { -+ AddGLDependencies(policy); -+ } -+ - // Read permissions - policy->AddPath(rdonly, "/dev/urandom"); - policy->AddPath(rdonly, "/dev/random"); - policy->AddPath(rdonly, "/proc/sys/crypto/fips_enabled"); - policy->AddPath(rdonly, "/proc/cpuinfo"); -@@ -370,13 +424,10 @@ - policy->AddDir(rdonly, "/run/host/fonts"); - policy->AddDir(rdonly, "/run/host/user-fonts"); - policy->AddDir(rdonly, "/run/host/local-fonts"); - policy->AddDir(rdonly, "/var/cache/fontconfig"); - -- if (!headless) { -- AddDriPaths(policy); -- } - AddLdconfigPaths(policy); - AddLdLibraryEnvPaths(policy); - - if (!headless) { - // Bug 1385715: NVIDIA PRIME support -@@ -569,45 +620,11 @@ - } - } - #endif - - if (!headless) { -- // Allow Primus to contact the Bumblebee daemon to manage GPU -- // switching on NVIDIA Optimus systems. -- const char* bumblebeeSocket = PR_GetEnv("BUMBLEBEE_SOCKET"); -- if (bumblebeeSocket == nullptr) { -- bumblebeeSocket = "/var/run/bumblebee.socket"; -- } -- policy->AddPath(SandboxBroker::MAY_CONNECT, bumblebeeSocket); -- --#if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11) -- // Allow local X11 connections, for several purposes: -- // -- // * for content processes to use WebGL when the browser is in headless -- // mode, by opening the X display if/when needed -- // -- // * if Primus or VirtualGL is used, to contact the secondary X server -- static const bool kIsX11 = -- !mozilla::widget::GdkIsWaylandDisplay() && PR_GetEnv("DISPLAY"); -- if (kIsX11) { -- policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X"); -- if (auto* const xauth = PR_GetEnv("XAUTHORITY")) { -- policy->AddPath(rdonly, xauth); -- } else if (auto* const home = PR_GetEnv("HOME")) { -- // This follows the logic in libXau: append "/.Xauthority", -- // even if $HOME ends in a slash, except in the special case -- // where HOME=/ because POSIX allows implementations to treat -- // an initial double slash specially. -- nsAutoCString xauth(home); -- if (xauth != "/"_ns) { -- xauth.Append('/'); -- } -- xauth.AppendLiteral(".Xauthority"); -- policy->AddPath(rdonly, xauth.get()); -- } -- } --#endif -+ AddX11Dependencies(policy); - } - - // Bug 1732580: when packaged as a strictly confined snap, may need - // read-access to configuration files under $SNAP/. - const char* snap = PR_GetEnv("SNAP"); - diff --git a/D146275.diff b/D146275.diff deleted file mode 100644 index 989b317..0000000 --- a/D146275.diff +++ /dev/null @@ -1,125 +0,0 @@ -diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp ---- a/ipc/glue/GeckoChildProcessHost.cpp -+++ b/ipc/glue/GeckoChildProcessHost.cpp -@@ -418,10 +418,17 @@ - nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR, - getter_AddRefs(contentTempDir)); - if (NS_SUCCEEDED(rv)) { - contentTempDir->GetNativePath(mTmpDirName); - } -+ } else if (aProcessType == GeckoProcessType_RDD) { -+ // The RDD process makes limited use of EGL. If Mesa's shader -+ // cache is enabled and the directory isn't explicitly set, then -+ // it will try to getpwuid() the user which can cause problems -+ // with sandboxing. Because we shouldn't need shader caching in -+ // this process, we just disable the cache to prevent that. -+ mLaunchOptions->env_map["MESA_GLSL_CACHE_DISABLE"] = "true"; - } - #endif - #if defined(MOZ_ENABLE_FORKSERVER) - if (aProcessType == GeckoProcessType_Content && ForkServiceChild::Get()) { - mLaunchOptions->use_forkserver = true; -diff --git a/security/sandbox/common/test/SandboxTestingChildTests.h b/security/sandbox/common/test/SandboxTestingChildTests.h ---- a/security/sandbox/common/test/SandboxTestingChildTests.h -+++ b/security/sandbox/common/test/SandboxTestingChildTests.h -@@ -21,14 +21,16 @@ - # include - # include - # include - # include - # include -+# include - # include - # include - # include - # include "mozilla/ProcInfo_linux.h" -+# include "mozilla/UniquePtrExtensions.h" - # ifdef MOZ_X11 - # include "X11/Xlib.h" - # include "X11UndefineNone.h" - # endif // MOZ_X11 - # endif // XP_LINUX -@@ -595,12 +597,25 @@ - return rv; - }); - - RunTestsSched(child); - -- child->ErrnoTest("socket"_ns, false, -- [] { return socket(AF_UNIX, SOCK_STREAM, 0); }); -+ child->ErrnoTest("socket_inet"_ns, false, -+ [] { return socket(AF_INET, SOCK_STREAM, 0); }); -+ -+ { -+ UniqueFileHandle fd(socket(AF_UNIX, SOCK_STREAM, 0)); -+ child->ErrnoTest("socket_unix"_ns, true, [&] { return fd.get(); }); -+ -+ struct sockaddr_un sun {}; -+ sun.sun_family = AF_UNIX; -+ strncpy(sun.sun_path, "/tmp/forbidden-sock", sizeof(sun.sun_path)); -+ -+ child->ErrnoValueTest("socket_unix_bind"_ns, ENOSYS, [&] { -+ return bind(fd.get(), (struct sockaddr*)&sun, sizeof(sun)); -+ }); -+ } - - child->ErrnoTest("uname"_ns, true, [] { - struct utsname uts; - return uname(&uts); - }); -diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp ---- a/security/sandbox/linux/SandboxFilter.cpp -+++ b/security/sandbox/linux/SandboxFilter.cpp -@@ -1783,10 +1783,11 @@ - class RDDSandboxPolicy final : public SandboxPolicyCommon { - public: - explicit RDDSandboxPolicy(SandboxBrokerClient* aBroker) { - mBroker = aBroker; - mMayCreateShmem = true; -+ mBrokeredConnect = true; - } - - #ifndef ANDROID - Maybe EvaluateIpcCall(int aCall, int aArgShift) const override { - // The Intel media driver uses SysV IPC (semaphores and shared -@@ -1818,15 +1819,15 @@ - #endif - - Maybe EvaluateSocketCall(int aCall, - bool aHasArgs) const override { - switch (aCall) { -- // Mesa can call getpwuid_r to get the home dir, which can try -- // to connect to nscd (or maybe servers like NIS or LDAP); this -- // can't be safely allowed, but we can quietly deny it. -- case SYS_SOCKET: -- return Some(Error(EACCES)); -+ // These are for X11. -+ case SYS_GETSOCKNAME: -+ case SYS_GETPEERNAME: -+ case SYS_SHUTDOWN: -+ return Some(Allow()); - - default: - return SandboxPolicyCommon::EvaluateSocketCall(aCall, aHasArgs); - } - } -diff --git a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp ---- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp -+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp -@@ -853,13 +853,12 @@ - if (developer_repo_dir) { - policy->AddDir(rdonly, developer_repo_dir); - } - } - -- // VA-API needs DRI and GPU detection -- policy->AddDir(rdwr, "/dev/dri"); -- AddDriPaths(policy.get()); -+ // VA-API needs GPU access and GL context creation -+ AddGLDependencies(policy.get()); - - // FFmpeg and GPU drivers may need general-case library loading - AddLdconfigPaths(policy.get()); - AddLdLibraryEnvPaths(policy.get()); - - diff --git a/D147635.diff b/D147635.diff deleted file mode 100644 index 1d4bb58..0000000 --- a/D147635.diff +++ /dev/null @@ -1,125 +0,0 @@ -diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h ---- a/gfx/gl/GLLibraryEGL.h -+++ b/gfx/gl/GLLibraryEGL.h -@@ -106,10 +106,13 @@ - KHR_swap_buffers_with_damage, - EXT_buffer_age, - KHR_partial_update, - NV_robustness_video_memory_purge, - MESA_platform_surfaceless, -+ EXT_image_dma_buf_import, -+ EXT_image_dma_buf_import_modifiers, -+ MESA_image_dma_buf_export, - Max - }; - - // - - -@@ -461,10 +464,23 @@ - // EGL_KHR_partial_update - EGLBoolean fSetDamageRegion(EGLDisplay dpy, EGLSurface surface, - const EGLint* rects, EGLint n_rects) { - WRAP(fSetDamageRegion(dpy, surface, rects, n_rects)); - } -+ // EGL_MESA_image_dma_buf_export -+ EGLBoolean fExportDMABUFImageQuery(EGLDisplay dpy, EGLImage image, -+ int* fourcc, int* num_planes, -+ uint64_t* modifiers) { -+ WRAP( -+ fExportDMABUFImageQueryMESA(dpy, image, fourcc, num_planes, modifiers)); -+ } -+ EGLBoolean fExportDMABUFImage(EGLDisplay dpy, EGLImage image, int* fds, -+ EGLint* strides, EGLint* offsets) { -+ WRAP(fExportDMABUFImageMESA(dpy, image, fds, strides, offsets)); -+ } -+ -+#undef WRAP - - #undef WRAP - #undef PROFILE_CALL - #undef BEFORE_CALL - #undef AFTER_CALL -@@ -593,10 +609,22 @@ - EGLBoolean(GLAPIENTRY* fSetDamageRegion)(EGLDisplay dpy, EGLSurface surface, - const EGLint* rects, - EGLint n_rects); - EGLClientBuffer(GLAPIENTRY* fGetNativeClientBufferANDROID)( - const struct AHardwareBuffer* buffer); -+ -+ // EGL_MESA_image_dma_buf_export -+ EGLBoolean(GLAPIENTRY* fExportDMABUFImageQueryMESA)(EGLDisplay dpy, -+ EGLImage image, -+ int* fourcc, -+ int* num_planes, -+ uint64_t* modifiers); -+ EGLBoolean(GLAPIENTRY* fExportDMABUFImageMESA)(EGLDisplay dpy, -+ EGLImage image, int* fds, -+ EGLint* strides, -+ EGLint* offsets); -+ - } mSymbols = {}; - }; - - class EglDisplay final { - public: -@@ -852,10 +880,23 @@ - EGLBoolean fSetDamageRegion(EGLSurface surface, const EGLint* rects, - EGLint n_rects) { - MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_partial_update)); - return mLib->fSetDamageRegion(mDisplay, surface, rects, n_rects); - } -+ -+ EGLBoolean fExportDMABUFImageQuery(EGLImage image, int* fourcc, -+ int* num_planes, -+ uint64_t* modifiers) const { -+ MOZ_ASSERT(IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export)); -+ return mLib->fExportDMABUFImageQuery(mDisplay, image, fourcc, num_planes, -+ modifiers); -+ } -+ EGLBoolean fExportDMABUFImage(EGLImage image, int* fds, EGLint* strides, -+ EGLint* offsets) const { -+ MOZ_ASSERT(IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export)); -+ return mLib->fExportDMABUFImage(mDisplay, image, fds, strides, offsets); -+ } - }; - - } /* namespace gl */ - } /* namespace mozilla */ - -diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp ---- a/gfx/gl/GLLibraryEGL.cpp -+++ b/gfx/gl/GLLibraryEGL.cpp -@@ -82,11 +82,14 @@ - "EGL_EXT_swap_buffers_with_damage", - "EGL_KHR_swap_buffers_with_damage", - "EGL_EXT_buffer_age", - "EGL_KHR_partial_update", - "EGL_NV_robustness_video_memory_purge", -- "EGL_MESA_platform_surfaceless"}; -+ "EGL_MESA_platform_surfaceless", -+ "EGL_EXT_image_dma_buf_import", -+ "EGL_EXT_image_dma_buf_import_modifiers", -+ "EGL_MESA_image_dma_buf_export"}; - - PRLibrary* LoadApitraceLibrary() { - const char* path = nullptr; - - #ifdef ANDROID -@@ -647,10 +650,16 @@ - { - const SymLoadStruct symbols[] = {SYMBOL(GetPlatformDisplay), - END_OF_SYMBOLS}; - (void)fnLoadSymbols(symbols); - } -+ { -+ const SymLoadStruct symbols[] = {SYMBOL(ExportDMABUFImageQueryMESA), -+ SYMBOL(ExportDMABUFImageMESA), -+ END_OF_SYMBOLS}; -+ (void)fnLoadSymbols(symbols); -+ } - - return true; - } - - // - - diff --git a/D147636.diff b/D147636.diff deleted file mode 100644 index 52462f2..0000000 --- a/D147636.diff +++ /dev/null @@ -1,278 +0,0 @@ -diff --git a/widget/gtk/DMABufSurface.h b/widget/gtk/DMABufSurface.h ---- a/widget/gtk/DMABufSurface.h -+++ b/widget/gtk/DMABufSurface.h -@@ -173,13 +173,13 @@ - SurfaceType mSurfaceType; - uint64_t mBufferModifiers[DMABUF_BUFFER_PLANES]; - - int mBufferPlaneCount; - int mDmabufFds[DMABUF_BUFFER_PLANES]; -- uint32_t mDrmFormats[DMABUF_BUFFER_PLANES]; -- uint32_t mStrides[DMABUF_BUFFER_PLANES]; -- uint32_t mOffsets[DMABUF_BUFFER_PLANES]; -+ int32_t mDrmFormats[DMABUF_BUFFER_PLANES]; -+ int32_t mStrides[DMABUF_BUFFER_PLANES]; -+ int32_t mOffsets[DMABUF_BUFFER_PLANES]; - - struct gbm_bo* mGbmBufferObject[DMABUF_BUFFER_PLANES]; - void* mMappedRegion[DMABUF_BUFFER_PLANES]; - void* mMappedRegionData[DMABUF_BUFFER_PLANES]; - uint32_t mMappedRegionStride[DMABUF_BUFFER_PLANES]; -@@ -198,10 +198,14 @@ - class DMABufSurfaceRGBA : public DMABufSurface { - public: - static already_AddRefed CreateDMABufSurface( - int aWidth, int aHeight, int aDMABufSurfaceFlags); - -+ static already_AddRefed CreateDMABufSurface( -+ mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage, -+ int aWidth, int aHeight); -+ - bool Serialize(mozilla::layers::SurfaceDescriptor& aOutDescriptor); - - DMABufSurfaceRGBA* GetAsDMABufSurfaceRGBA() { return this; } - - void Clear(); -@@ -247,10 +251,12 @@ - private: - ~DMABufSurfaceRGBA(); - - bool Create(int aWidth, int aHeight, int aDMABufSurfaceFlags); - bool Create(const mozilla::layers::SurfaceDescriptor& aDesc); -+ bool Create(mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage, -+ int aWidth, int aHeight); - - bool ImportSurfaceDescriptor(const mozilla::layers::SurfaceDescriptor& aDesc); - - bool OpenFileDescriptorForPlane(const mozilla::MutexAutoLock& aProofOfLock, - int aPlane); -diff --git a/widget/gtk/DMABufSurface.cpp b/widget/gtk/DMABufSurface.cpp ---- a/widget/gtk/DMABufSurface.cpp -+++ b/widget/gtk/DMABufSurface.cpp -@@ -204,10 +204,12 @@ - } - } - - void DMABufSurface::FenceSet() { - if (!mGL || !mGL->MakeCurrent()) { -+ MOZ_DIAGNOSTIC_ASSERT(mGL, -+ "DMABufSurface::FenceSet(): missing GL context!"); - return; - } - const auto& gle = gl::GLContextEGL::Cast(mGL); - const auto& egl = gle->mEgl; - -@@ -228,21 +230,23 @@ - mGL->fFinish(); - } - - void DMABufSurface::FenceWait() { - if (!mGL || mSyncFd < 0) { -+ MOZ_DIAGNOSTIC_ASSERT(mGL, -+ "DMABufSurface::FenceWait() missing GL context!"); - return; - } - - const auto& gle = gl::GLContextEGL::Cast(mGL); - const auto& egl = gle->mEgl; - - const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, mSyncFd, - LOCAL_EGL_NONE}; - EGLSync sync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); - if (!sync) { -- MOZ_ASSERT(false, "Failed to create GLFence!"); -+ MOZ_ASSERT(false, "DMABufSurface::FenceWait(): Failed to create GLFence!"); - // We failed to create GLFence so clear mSyncFd to avoid another try. - close(mSyncFd); - mSyncFd = -1; - return; - } -@@ -338,17 +342,18 @@ - mGmbFormat = GetDMABufDevice()->GetGbmFormat(mSurfaceFlags & DMABUF_ALPHA); - if (!mGmbFormat) { - // Requested DRM format is not supported. - return false; - } -+ mDrmFormats[0] = mGmbFormat->mFormat; - - bool useModifiers = (aDMABufSurfaceFlags & DMABUF_USE_MODIFIERS) && - mGmbFormat->mModifiersCount > 0; - if (useModifiers) { - LOGDMABUF((" Creating with modifiers\n")); - mGbmBufferObject[0] = nsGbmLib::CreateWithModifiers( -- GetDMABufDevice()->GetGbmDevice(), mWidth, mHeight, mGmbFormat->mFormat, -+ GetDMABufDevice()->GetGbmDevice(), mWidth, mHeight, mDrmFormats[0], - mGmbFormat->mModifiers, mGmbFormat->mModifiersCount); - if (mGbmBufferObject[0]) { - mBufferModifiers[0] = nsGbmLib::GetModifier(mGbmBufferObject[0]); - } - } -@@ -356,11 +361,11 @@ - if (!mGbmBufferObject[0]) { - LOGDMABUF((" Creating without modifiers\n")); - mGbmBufferFlags = GBM_BO_USE_LINEAR; - mGbmBufferObject[0] = - nsGbmLib::Create(GetDMABufDevice()->GetGbmDevice(), mWidth, mHeight, -- mGmbFormat->mFormat, mGbmBufferFlags); -+ mDrmFormats[0], mGbmBufferFlags); - mBufferModifiers[0] = DRM_FORMAT_MOD_INVALID; - } - - if (!mGbmBufferObject[0]) { - LOGDMABUF((" Failed to create GbmBufferObject\n")); -@@ -386,22 +391,51 @@ - - LOGDMABUF((" Success\n")); - return true; - } - -+bool DMABufSurfaceRGBA::Create(mozilla::gl::GLContext* aGLContext, -+ const EGLImageKHR aEGLImage, int aWidth, -+ int aHeight) { -+ LOGDMABUF(("DMABufSurfaceRGBA::Create() from EGLImage UID = %d\n", mUID)); -+ if (!aGLContext) { -+ return false; -+ } -+ const auto& gle = gl::GLContextEGL::Cast(aGLContext); -+ const auto& egl = gle->mEgl; -+ -+ mGL = aGLContext; -+ mWidth = aWidth; -+ mHeight = aHeight; -+ mEGLImage = aEGLImage; -+ if (!egl->fExportDMABUFImageQuery(mEGLImage, mDrmFormats, &mBufferPlaneCount, -+ mBufferModifiers)) { -+ LOGDMABUF((" ExportDMABUFImageQueryMESA failed, quit\n")); -+ return false; -+ } -+ if (mBufferPlaneCount > DMABUF_BUFFER_PLANES) { -+ LOGDMABUF((" wrong plane count %d, quit\n", mBufferPlaneCount)); -+ return false; -+ } -+ if (!egl->fExportDMABUFImage(mEGLImage, mDmabufFds, mStrides, mOffsets)) { -+ LOGDMABUF((" ExportDMABUFImageMESA failed, quit\n")); -+ return false; -+ } -+ -+ LOGDMABUF((" imported size %d x %d format %x planes %d", mWidth, mHeight, -+ mDrmFormats[0], mBufferPlaneCount)); -+ return true; -+} -+ - bool DMABufSurfaceRGBA::ImportSurfaceDescriptor( - const SurfaceDescriptor& aDesc) { - const SurfaceDescriptorDMABuf& desc = aDesc.get_SurfaceDescriptorDMABuf(); - - mWidth = desc.width()[0]; - mHeight = desc.height()[0]; - mBufferModifiers[0] = desc.modifier()[0]; -- if (mBufferModifiers[0] != DRM_FORMAT_MOD_INVALID) { -- mGmbFormat = GetDMABufDevice()->GetExactGbmFormat(desc.format()[0]); -- } else { -- mDrmFormats[0] = desc.format()[0]; -- } -+ mDrmFormats[0] = desc.format()[0]; - mBufferPlaneCount = desc.fds().Length(); - mGbmBufferFlags = desc.flags(); - MOZ_RELEASE_ASSERT(mBufferPlaneCount <= DMABUF_BUFFER_PLANES); - mUID = desc.uid(); - -@@ -431,10 +465,12 @@ - - if (desc.refCount().Length() > 0) { - GlobalRefCountImport(desc.refCount()[0].ClonePlatformHandle().release()); - } - -+ LOGDMABUF((" imported size %d x %d format %x planes %d", mWidth, mHeight, -+ mDrmFormats[0], mBufferPlaneCount)); - return true; - } - - bool DMABufSurfaceRGBA::Create(const SurfaceDescriptor& aDesc) { - return ImportSurfaceDescriptor(aDesc); -@@ -460,11 +496,11 @@ - return false; - } - - width.AppendElement(mWidth); - height.AppendElement(mHeight); -- format.AppendElement(mGmbFormat->mFormat); -+ format.AppendElement(mDrmFormats[0]); - modifiers.AppendElement(mBufferModifiers[0]); - for (int i = 0; i < mBufferPlaneCount; i++) { - fds.AppendElement(ipc::FileDescriptor(mDmabufFds[i])); - strides.AppendElement(mStrides[i]); - offsets.AppendElement(mOffsets[i]); -@@ -486,23 +522,20 @@ - fenceFDs, mUID, refCountFDs); - return true; - } - - bool DMABufSurfaceRGBA::CreateTexture(GLContext* aGLContext, int aPlane) { -+ LOGDMABUF(("DMABufSurfaceRGBA::CreateTexture() UID %d\n", mUID)); - MOZ_ASSERT(!mEGLImage && !mTexture, "EGLImage is already created!"); - - nsTArray attribs; - attribs.AppendElement(LOCAL_EGL_WIDTH); - attribs.AppendElement(mWidth); - attribs.AppendElement(LOCAL_EGL_HEIGHT); - attribs.AppendElement(mHeight); - attribs.AppendElement(LOCAL_EGL_LINUX_DRM_FOURCC_EXT); -- if (mGmbFormat) { -- attribs.AppendElement(mGmbFormat->mFormat); -- } else { -- attribs.AppendElement(mDrmFormats[0]); -- } -+ attribs.AppendElement(mDrmFormats[0]); - #define ADD_PLANE_ATTRIBS(plane_idx) \ - { \ - attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_FD_EXT); \ - attribs.AppendElement(mDmabufFds[plane_idx]); \ - attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_OFFSET_EXT); \ -@@ -560,10 +593,11 @@ - - return true; - } - - void DMABufSurfaceRGBA::ReleaseTextures() { -+ LOGDMABUF(("DMABufSurfaceRGBA::ReleaseTextures() UID %d\n", mUID)); - FenceDelete(); - - if (!mTexture) { - return; - } -@@ -618,11 +652,11 @@ - zwp_linux_buffer_params_v1_add(params, mDmabufFds[0], 0, mOffsets[0], - mStrides[0], mBufferModifiers[0] >> 32, - mBufferModifiers[0] & 0xffffffff); - - mWlBuffer = zwp_linux_buffer_params_v1_create_immed( -- params, GetWidth(), GetHeight(), mGmbFormat->mFormat, 0); -+ params, GetWidth(), GetHeight(), mDrmFormats[0], 0); - - CloseFileDescriptors(lockFD); - - return mWlBuffer != nullptr; - } -@@ -806,10 +840,20 @@ - return nullptr; - } - return surf.forget(); - } - -+already_AddRefed DMABufSurfaceRGBA::CreateDMABufSurface( -+ mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage, int aWidth, -+ int aHeight) { -+ RefPtr surf = new DMABufSurfaceRGBA(); -+ if (!surf->Create(aGLContext, aEGLImage, aWidth, aHeight)) { -+ return nullptr; -+ } -+ return surf.forget(); -+} -+ - already_AddRefed DMABufSurfaceYUV::CreateYUVSurface( - const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, int aHeight) { - RefPtr surf = new DMABufSurfaceYUV(); - LOGDMABUF(("DMABufSurfaceYUV::CreateYUVSurface() UID %d from desc\n", - surf->GetUID())); - diff --git a/D147637.diff b/D147637.diff deleted file mode 100644 index 89bb25e..0000000 --- a/D147637.diff +++ /dev/null @@ -1,139 +0,0 @@ -diff -up firefox-102.0/gfx/gl/SharedSurfaceDMABUF.cpp.D147637.diff firefox-102.0/gfx/gl/SharedSurfaceDMABUF.cpp ---- firefox-102.0/gfx/gl/SharedSurfaceDMABUF.cpp.D147637.diff 2022-06-23 09:08:46.000000000 +0200 -+++ firefox-102.0/gfx/gl/SharedSurfaceDMABUF.cpp 2022-06-28 16:37:52.264835137 +0200 -@@ -9,25 +9,58 @@ - #include "GLContextEGL.h" - #include "MozFramebuffer.h" - #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc -+#include "mozilla/gfx/gfxVars.h" - - namespace mozilla::gl { - -+static bool HasDmaBufExtensions(const GLContextEGL* gl) { -+ const auto& egl = *(gl->mEgl); -+ return egl.IsExtensionSupported(EGLExtension::EXT_image_dma_buf_import) && -+ egl.IsExtensionSupported( -+ EGLExtension::EXT_image_dma_buf_import_modifiers) && -+ egl.IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export); -+} -+ - /*static*/ - UniquePtr SharedSurface_DMABUF::Create( - const SharedSurfaceDesc& desc) { -- const auto flags = static_cast( -- DMABUF_TEXTURE | DMABUF_USE_MODIFIERS | DMABUF_ALPHA); -- const RefPtr surface = DMABufSurfaceRGBA::CreateDMABufSurface( -- desc.size.width, desc.size.height, flags); -- if (!surface || !surface->CreateTexture(desc.gl)) { -- return nullptr; -+ const auto& gle = GLContextEGL::Cast(desc.gl); -+ const auto& context = gle->mContext; -+ const auto& egl = *(gle->mEgl); -+ -+ RefPtr surface; -+ UniquePtr fb; -+ -+ if (!HasDmaBufExtensions(gle) || !gfx::gfxVars::UseDMABufSurfaceExport()) { -+ // Use MESA_image_dma_buf_export is not supported or it's broken. -+ // Create dmabuf surface directly via. GBM and create -+ // EGLImage/framebuffer over it. -+ const auto flags = static_cast( -+ DMABUF_TEXTURE | DMABUF_USE_MODIFIERS | DMABUF_ALPHA); -+ surface = DMABufSurfaceRGBA::CreateDMABufSurface(desc.size.width, -+ desc.size.height, flags); -+ if (!surface || !surface->CreateTexture(desc.gl)) { -+ return nullptr; -+ } -+ const auto tex = surface->GetTexture(); -+ fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false, -+ LOCAL_GL_TEXTURE_2D, tex); -+ if (!fb) return nullptr; -+ } else { -+ // Use MESA_image_dma_buf_export so create EGLImage/framebuffer directly -+ // and derive dmabuf from it. -+ fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false); -+ if (!fb) return nullptr; -+ -+ const auto buffer = reinterpret_cast(fb->ColorTex()); -+ const auto image = -+ egl.fCreateImage(context, LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr); -+ if (!image) return nullptr; -+ -+ surface = DMABufSurfaceRGBA::CreateDMABufSurface( -+ desc.gl, image, desc.size.width, desc.size.height); -+ if (!surface) return nullptr; - } -- -- const auto tex = surface->GetTexture(); -- auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false, -- LOCAL_GL_TEXTURE_2D, tex); -- if (!fb) return nullptr; -- - return AsUnique(new SharedSurface_DMABUF(desc, std::move(fb), surface)); - } - -@@ -61,7 +94,7 @@ UniquePtr Surface - } - - auto dmabufFactory = MakeUnique(gl); -- if (dmabufFactory->CanCreateSurface()) { -+ if (dmabufFactory->CanCreateSurface(gl)) { - return dmabufFactory; - } - -@@ -71,8 +104,38 @@ UniquePtr Surface - return nullptr; - } - -+bool SurfaceFactory_DMABUF::CanCreateSurface(GLContext& gl) { -+ UniquePtr test = -+ CreateShared(gfx::IntSize(1, 1), gfx::ColorSpace2::SRGB); -+ if (!test) { -+ LOGDMABUF(( -+ "SurfaceFactory_DMABUF::CanCreateSurface() failed to create surface.")); -+ return false; -+ } -+ auto desc = test->ToSurfaceDescriptor(); -+ if (!desc) { -+ LOGDMABUF( -+ ("SurfaceFactory_DMABUF::CanCreateSurface() failed to serialize " -+ "surface.")); -+ return false; -+ } -+ RefPtr importedSurface = -+ DMABufSurface::CreateDMABufSurface(*desc); -+ if (!importedSurface) { -+ LOGDMABUF(( -+ "SurfaceFactory_DMABUF::CanCreateSurface() failed to import surface.")); -+ return false; -+ } -+ if (!importedSurface->CreateTexture(&gl)) { -+ LOGDMABUF( -+ ("SurfaceFactory_DMABUF::CanCreateSurface() failed to create texture " -+ "over surface.")); -+ return false; -+ } -+ return true; -+} -+ - SurfaceFactory_DMABUF::SurfaceFactory_DMABUF(GLContext& gl) - : SurfaceFactory({&gl, SharedSurfaceType::EGLSurfaceDMABUF, - layers::TextureType::DMABUF, true}) {} -- - } // namespace mozilla::gl -diff -up firefox-102.0/gfx/gl/SharedSurfaceDMABUF.h.D147637.diff firefox-102.0/gfx/gl/SharedSurfaceDMABUF.h ---- firefox-102.0/gfx/gl/SharedSurfaceDMABUF.h.D147637.diff 2022-06-23 09:08:47.000000000 +0200 -+++ firefox-102.0/gfx/gl/SharedSurfaceDMABUF.h 2022-06-28 15:00:20.339991965 +0200 -@@ -59,11 +59,7 @@ class SurfaceFactory_DMABUF : public Sur - return SharedSurface_DMABUF::Create(desc); - } - -- bool CanCreateSurface() { -- UniquePtr test = -- CreateShared(gfx::IntSize(1, 1), gfx::ColorSpace2::SRGB); -- return test != nullptr; -- } -+ bool CanCreateSurface(GLContext& gl); - }; - - } // namespace gl diff --git a/D147874.diff b/D147874.diff deleted file mode 100644 index f0c57dd..0000000 --- a/D147874.diff +++ /dev/null @@ -1,64 +0,0 @@ -diff -up firefox-101.0/gfx/thebes/gfxPlatformGtk.cpp.D147874.diff firefox-101.0/gfx/thebes/gfxPlatformGtk.cpp ---- firefox-101.0/gfx/thebes/gfxPlatformGtk.cpp.D147874.diff 2022-05-27 01:16:54.000000000 +0200 -+++ firefox-101.0/gfx/thebes/gfxPlatformGtk.cpp 2022-06-07 11:16:03.791419558 +0200 -@@ -233,13 +233,7 @@ void gfxPlatformGtk::InitDmabufConfig() - void gfxPlatformGtk::InitVAAPIConfig() { - FeatureState& feature = gfxConfig::GetFeature(Feature::VAAPI); - #ifdef MOZ_WAYLAND -- feature.DisableByDefault(FeatureStatus::Disabled, -- "VAAPI is disabled by default", -- "FEATURE_VAAPI_DISABLED"_ns); -- -- if (StaticPrefs::media_ffmpeg_vaapi_enabled()) { -- feature.UserForceEnable("Force enabled by pref"); -- } -+ feature.EnableByDefault(); - - nsCString failureId; - int32_t status; -@@ -253,6 +247,10 @@ void gfxPlatformGtk::InitVAAPIConfig() { - failureId); - } - -+ if (StaticPrefs::media_ffmpeg_vaapi_enabled()) { -+ feature.UserForceEnable("Force enabled by pref"); -+ } -+ - if (!gfxVars::UseEGL()) { - feature.ForceDisable(FeatureStatus::Unavailable, "Requires EGL", - "FEATURE_FAILURE_REQUIRES_EGL"_ns); -diff -up firefox-101.0/widget/gtk/GfxInfo.cpp.D147874.diff firefox-101.0/widget/gtk/GfxInfo.cpp ---- firefox-101.0/widget/gtk/GfxInfo.cpp.D147874.diff 2022-05-27 01:17:06.000000000 +0200 -+++ firefox-101.0/widget/gtk/GfxInfo.cpp 2022-06-07 09:52:54.416701418 +0200 -@@ -843,6 +843,31 @@ const nsTArray& GfxInfo:: - V(495, 44, 0, 0), "FEATURE_FAILURE_NO_GBM", "495.44.0"); - - //////////////////////////////////// -+ // FEATURE_VAAPI -+ APPEND_TO_DRIVER_BLOCKLIST_EXT( -+ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, -+ DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll, -+ DeviceFamily::All, nsIGfxInfo::FEATURE_VAAPI, -+ nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN, -+ V(21, 0, 0, 0), "FEATURE_ROLLOUT_VAAPI_MESA", "Mesa 21.0.0.0"); -+ -+ // Disable on all NVIDIA hardware -+ APPEND_TO_DRIVER_BLOCKLIST_EXT( -+ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, -+ DesktopEnvironment::All, WindowProtocol::All, DriverVendor::All, -+ DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_VAAPI, -+ nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED, -+ V(0, 0, 0, 0), "FEATURE_FAILURE_VAAPI_NO_LINUX_NVIDIA", ""); -+ -+ // Disable on all AMD devices not using Mesa. -+ APPEND_TO_DRIVER_BLOCKLIST_EXT( -+ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, -+ DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll, -+ DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_VAAPI, -+ nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED, -+ V(0, 0, 0, 0), "FEATURE_FAILURE_VAAPI_NO_LINUX_AMD", ""); -+ -+ //////////////////////////////////// - // FEATURE_WEBRENDER_PARTIAL_PRESENT - APPEND_TO_DRIVER_BLOCKLIST_EXT( - OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, diff --git a/D148946.diff b/D148946.diff deleted file mode 100644 index 0ab7380..0000000 --- a/D148946.diff +++ /dev/null @@ -1,250 +0,0 @@ -diff -up firefox-102.0/gfx/gl/GLContextProviderEGL.cpp.D148946.diff firefox-102.0/gfx/gl/GLContextProviderEGL.cpp ---- firefox-102.0/gfx/gl/GLContextProviderEGL.cpp.D148946.diff 2022-06-23 09:08:47.000000000 +0200 -+++ firefox-102.0/gfx/gl/GLContextProviderEGL.cpp 2022-06-28 14:47:40.904700050 +0200 -@@ -1182,42 +1182,16 @@ RefPtr GLContextEGL::Creat - } - - /*static*/ --RefPtr GLContextEGL::CreateEGLSurfacelessContext( -- const std::shared_ptr display, const GLContextCreateDesc& desc, -- nsACString* const out_failureId) { -- const EGLConfig config = {}; -- auto fullDesc = GLContextDesc{desc}; -- fullDesc.isOffscreen = true; -- RefPtr gl = GLContextEGL::CreateGLContext( -- display, fullDesc, config, EGL_NO_SURFACE, false, out_failureId); -- if (!gl) { -- NS_WARNING("Failed to create surfaceless GL context"); -- return nullptr; -- } -- return gl; --} -- --/*static*/ - already_AddRefed GLContextProviderEGL::CreateHeadless( - const GLContextCreateDesc& desc, nsACString* const out_failureId) { - const auto display = DefaultEglDisplay(out_failureId); - if (!display) { - return nullptr; - } -- RefPtr gl; --#ifdef MOZ_WAYLAND -- if (!gdk_display_get_default() && -- display->IsExtensionSupported(EGLExtension::MESA_platform_surfaceless)) { -- gl = -- GLContextEGL::CreateEGLSurfacelessContext(display, desc, out_failureId); -- } else --#endif -- { -- mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16); -- gl = GLContextEGL::CreateEGLPBufferOffscreenContext( -- display, desc, dummySize, out_failureId); -- } -- return gl.forget(); -+ mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16); -+ auto ret = GLContextEGL::CreateEGLPBufferOffscreenContext( -+ display, desc, dummySize, out_failureId); -+ return ret.forget(); - } - - // Don't want a global context on Android as 1) share groups across 2 threads -diff -up firefox-102.0/gfx/gl/GLDefs.h.D148946.diff firefox-102.0/gfx/gl/GLDefs.h ---- firefox-102.0/gfx/gl/GLDefs.h.D148946.diff 2022-06-23 09:08:47.000000000 +0200 -+++ firefox-102.0/gfx/gl/GLDefs.h 2022-06-28 14:47:40.904700050 +0200 -@@ -104,9 +104,6 @@ bool CheckContextLost(const GLContext* g - // EGL_ANGLE_image_d3d11_texture - #define LOCAL_EGL_D3D11_TEXTURE_ANGLE 0x3484 - --// EGL_MESA_platform_surfaceless --#define LOCAL_EGL_PLATFORM_SURFACELESS_MESA 0x31DD -- - // clang-format on - - #endif -diff -up firefox-102.0/gfx/gl/GLLibraryEGL.cpp.D148946.diff firefox-102.0/gfx/gl/GLLibraryEGL.cpp ---- firefox-102.0/gfx/gl/GLLibraryEGL.cpp.D148946.diff 2022-06-28 14:47:40.900699918 +0200 -+++ firefox-102.0/gfx/gl/GLLibraryEGL.cpp 2022-06-28 14:49:47.810911199 +0200 -@@ -54,9 +54,15 @@ StaticRefPtr GLLibraryEGL: - - // should match the order of EGLExtensions, and be null-terminated. - static const char* sEGLLibraryExtensionNames[] = { -- "EGL_ANDROID_get_native_client_buffer", "EGL_ANGLE_device_creation", -- "EGL_ANGLE_device_creation_d3d11", "EGL_ANGLE_platform_angle", -- "EGL_ANGLE_platform_angle_d3d", "EGL_EXT_device_query"}; -+ "EGL_ANDROID_get_native_client_buffer", -+ "EGL_ANGLE_device_creation", -+ "EGL_ANGLE_device_creation_d3d11", -+ "EGL_ANGLE_platform_angle", -+ "EGL_ANGLE_platform_angle_d3d", -+ "EGL_EXT_device_enumeration", -+ "EGL_EXT_device_query", -+ "EGL_EXT_platform_device", -+ "EGL_MESA_platform_surfaceless"}; - - // should match the order of EGLExtensions, and be null-terminated. - static const char* sEGLExtensionNames[] = { -@@ -84,7 +90,6 @@ static const char* sEGLExtensionNames[] - "EGL_EXT_buffer_age", - "EGL_KHR_partial_update", - "EGL_NV_robustness_video_memory_purge", -- "EGL_MESA_platform_surfaceless", - "EGL_EXT_image_dma_buf_import", - "EGL_EXT_image_dma_buf_import_modifiers", - "EGL_MESA_image_dma_buf_export"}; -@@ -157,8 +162,52 @@ static std::shared_ptr GetAn - } - - #ifdef MOZ_WAYLAND -+static std::shared_ptr GetAndInitDeviceDisplay( -+ GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) { -+ nsAutoCString drmRenderDevice(gfx::gfxVars::DrmRenderDevice()); -+ if (drmRenderDevice.IsEmpty() || -+ !egl.IsExtensionSupported(EGLLibExtension::EXT_platform_device) || -+ !egl.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration)) { -+ return nullptr; -+ } -+ -+ EGLint maxDevices; -+ if (!egl.fQueryDevicesEXT(0, nullptr, &maxDevices)) { -+ return nullptr; -+ } -+ -+ std::vector devices(maxDevices); -+ EGLint numDevices; -+ if (!egl.fQueryDevicesEXT(devices.size(), devices.data(), &numDevices)) { -+ return nullptr; -+ } -+ devices.resize(numDevices); -+ -+ EGLDisplay display = EGL_NO_DISPLAY; -+ for (const auto& device : devices) { -+ const char* renderNodeString = -+ egl.fQueryDeviceStringEXT(device, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT); -+ if (renderNodeString && -+ strcmp(renderNodeString, drmRenderDevice.get()) == 0) { -+ const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE}; -+ display = egl.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, device, -+ attrib_list); -+ break; -+ } -+ } -+ if (!display) { -+ return nullptr; -+ } -+ -+ return EglDisplay::Create(egl, display, true, aProofOfLock); -+} -+ - static std::shared_ptr GetAndInitSurfacelessDisplay( - GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) { -+ if (!egl.IsExtensionSupported(EGLLibExtension::MESA_platform_surfaceless)) { -+ return nullptr; -+ } -+ - const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE}; - const EGLDisplay display = egl.fGetPlatformDisplay( - LOCAL_EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, attrib_list); -@@ -611,9 +660,9 @@ bool GLLibraryEGL::Init(nsACString* cons - (void)fnLoadSymbols(symbols); - } - { -- const SymLoadStruct symbols[] = {SYMBOL(QueryDisplayAttribEXT), -- SYMBOL(QueryDeviceAttribEXT), -- END_OF_SYMBOLS}; -+ const SymLoadStruct symbols[] = { -+ SYMBOL(QueryDisplayAttribEXT), SYMBOL(QueryDeviceAttribEXT), -+ SYMBOL(QueryDeviceStringEXT), END_OF_SYMBOLS}; - (void)fnLoadSymbols(symbols); - } - { -@@ -658,6 +707,10 @@ bool GLLibraryEGL::Init(nsACString* cons - END_OF_SYMBOLS}; - (void)fnLoadSymbols(symbols); - } -+ { -+ const SymLoadStruct symbols[] = {SYMBOL(QueryDevicesEXT), END_OF_SYMBOLS}; -+ (void)fnLoadSymbols(symbols); -+ } - - return true; - } -@@ -835,7 +888,10 @@ std::shared_ptr GLLibraryEGL - #ifdef MOZ_WAYLAND - GdkDisplay* gdkDisplay = gdk_display_get_default(); - if (!gdkDisplay) { -- ret = GetAndInitSurfacelessDisplay(*this, aProofOfLock); -+ ret = GetAndInitDeviceDisplay(*this, aProofOfLock); -+ if (!ret) { -+ ret = GetAndInitSurfacelessDisplay(*this, aProofOfLock); -+ } - } else if (widget::GdkIsWaylandDisplay(gdkDisplay)) { - // Wayland does not support EGL_DEFAULT_DISPLAY - nativeDisplay = widget::WaylandDisplayGetWLDisplay(gdkDisplay); -diff -up firefox-102.0/gfx/gl/GLLibraryEGL.h.D148946.diff firefox-102.0/gfx/gl/GLLibraryEGL.h ---- firefox-102.0/gfx/gl/GLLibraryEGL.h.D148946.diff 2022-06-28 14:47:40.899699885 +0200 -+++ firefox-102.0/gfx/gl/GLLibraryEGL.h 2022-06-28 14:47:40.904700050 +0200 -@@ -71,7 +71,10 @@ enum class EGLLibExtension { - ANGLE_device_creation_d3d11, - ANGLE_platform_angle, - ANGLE_platform_angle_d3d, -+ EXT_device_enumeration, - EXT_device_query, -+ EXT_platform_device, -+ MESA_platform_surfaceless, - Max - }; - -@@ -107,7 +110,6 @@ enum class EGLExtension { - EXT_buffer_age, - KHR_partial_update, - NV_robustness_video_memory_purge, -- MESA_platform_surfaceless, - EXT_image_dma_buf_import, - EXT_image_dma_buf_import_modifiers, - MESA_image_dma_buf_export, -@@ -436,6 +438,10 @@ class GLLibraryEGL final { - WRAP(fQueryDeviceAttribEXT(device, attribute, value)); - } - -+ const char* fQueryDeviceStringEXT(EGLDeviceEXT device, EGLint name) { -+ WRAP(fQueryDeviceStringEXT(device, name)); -+ } -+ - private: - // NV_stream_consumer_gltexture_yuv - EGLBoolean fStreamConsumerGLTextureExternalAttribsNV( -@@ -478,6 +484,13 @@ class GLLibraryEGL final { - WRAP(fExportDMABUFImageMESA(dpy, image, fds, strides, offsets)); - } - -+ public: -+ // EGL_EXT_device_enumeration -+ EGLBoolean fQueryDevicesEXT(EGLint max_devices, EGLDeviceEXT* devices, -+ EGLint* num_devices) { -+ WRAP(fQueryDevicesEXT(max_devices, devices, num_devices)); -+ } -+ - #undef WRAP - - #undef WRAP -@@ -586,6 +599,9 @@ class GLLibraryEGL final { - EGLBoolean(GLAPIENTRY* fQueryDeviceAttribEXT)(EGLDeviceEXT device, - EGLint attribute, - EGLAttrib* value); -+ const char*(GLAPIENTRY* fQueryDeviceStringEXT)(EGLDeviceEXT device, -+ EGLint name); -+ - // NV_stream_consumer_gltexture_yuv - EGLBoolean(GLAPIENTRY* fStreamConsumerGLTextureExternalAttribsNV)( - EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list); -@@ -623,6 +639,10 @@ class GLLibraryEGL final { - EGLint* strides, - EGLint* offsets); - -+ EGLBoolean(GLAPIENTRY* fQueryDevicesEXT)(EGLint max_devices, -+ EGLDeviceEXT* devices, -+ EGLint* num_devices); -+ - } mSymbols = {}; - }; - diff --git a/D149135.diff b/D149135.diff deleted file mode 100644 index 6e93f2b..0000000 --- a/D149135.diff +++ /dev/null @@ -1,80 +0,0 @@ -diff --git a/widget/gtk/DMABufSurface.cpp b/widget/gtk/DMABufSurface.cpp ---- a/widget/gtk/DMABufSurface.cpp -+++ b/widget/gtk/DMABufSurface.cpp -@@ -642,11 +642,11 @@ - - void DMABufSurfaceRGBA::ReleaseTextures() { - LOGDMABUF(("DMABufSurfaceRGBA::ReleaseTextures() UID %d\n", mUID)); - FenceDelete(); - -- if (!mTexture) { -+ if (!mTexture && mEGLImage == LOCAL_EGL_NO_IMAGE) { - return; - } - - if (!mGL) { - #ifdef NIGHTLY -@@ -663,17 +663,17 @@ - const auto& egl = gle->mEgl; - - if (mTexture && mGL->MakeCurrent()) { - mGL->fDeleteTextures(1, &mTexture); - mTexture = 0; -- mGL = nullptr; - } - - if (mEGLImage != LOCAL_EGL_NO_IMAGE) { - egl->fDestroyImage(mEGLImage); - mEGLImage = LOCAL_EGL_NO_IMAGE; - } -+ mGL = nullptr; - } - - void DMABufSurfaceRGBA::ReleaseSurface() { - MOZ_ASSERT(!IsMapped(), "We can't release mapped buffer!"); - -@@ -1325,11 +1325,11 @@ - - FenceDelete(); - - bool textureActive = false; - for (int i = 0; i < mBufferPlaneCount; i++) { -- if (mTexture[i]) { -+ if (mTexture[i] || mEGLImage[i] != LOCAL_EGL_NO_IMAGE) { - textureActive = true; - break; - } - } - -@@ -1346,18 +1346,23 @@ - "leaking textures!"); - return; - #endif - } - -- if (textureActive && mGL->MakeCurrent()) { -- mGL->fDeleteTextures(DMABUF_BUFFER_PLANES, mTexture); -- for (int i = 0; i < DMABUF_BUFFER_PLANES; i++) { -- mTexture[i] = 0; -- } -- ReleaseEGLImages(mGL); -- mGL = nullptr; -+ if (!mGL->MakeCurrent()) { -+ NS_WARNING( -+ "DMABufSurfaceYUV::ReleaseTextures(): Failed to create GL context " -+ "current. We're leaking textures!"); -+ return; - } -+ -+ mGL->fDeleteTextures(DMABUF_BUFFER_PLANES, mTexture); -+ for (int i = 0; i < DMABUF_BUFFER_PLANES; i++) { -+ mTexture[i] = 0; -+ } -+ ReleaseEGLImages(mGL); -+ mGL = nullptr; - } - - bool DMABufSurfaceYUV::VerifyTextureCreation() { - LOGDMABUF(("DMABufSurfaceYUV::VerifyTextureCreation() UID %d", mUID)); - - diff --git a/D149238.diff b/D149238.diff deleted file mode 100644 index e89c1bf..0000000 --- a/D149238.diff +++ /dev/null @@ -1,34 +0,0 @@ -diff -up firefox-102.0/gfx/config/gfxVars.h.D149238.diff firefox-102.0/gfx/config/gfxVars.h ---- firefox-102.0/gfx/config/gfxVars.h.D149238.diff 2022-06-23 09:08:47.000000000 +0200 -+++ firefox-102.0/gfx/config/gfxVars.h 2022-06-28 16:40:54.130895063 +0200 -@@ -91,7 +91,8 @@ class gfxVarReceiver; - _(AllowWebGPU, bool, false) \ - _(UseVP8HwDecode, bool, false) \ - _(UseVP9HwDecode, bool, false) \ -- _(HwDecodedVideoZeroCopy, bool, false) -+ _(HwDecodedVideoZeroCopy, bool, false) \ -+ _(UseDMABufSurfaceExport, bool, true) - - /* Add new entries above this line. */ - -diff -up firefox-102.0/gfx/thebes/gfxPlatform.cpp.D149238.diff firefox-102.0/gfx/thebes/gfxPlatform.cpp ---- firefox-102.0/gfx/thebes/gfxPlatform.cpp.D149238.diff 2022-06-23 09:08:47.000000000 +0200 -+++ firefox-102.0/gfx/thebes/gfxPlatform.cpp 2022-06-28 16:40:54.130895063 +0200 -@@ -2861,6 +2861,17 @@ void gfxPlatform::InitWebGLConfig() { - gfxVars::SetAllowEglRbab(false); - } - } -+ -+ if (kIsWayland || kIsX11) { -+ // Disable EGL_MESA_image_dma_buf_export on mesa/radeonsi due to -+ // https://gitlab.freedesktop.org/mesa/mesa/-/issues/6666 -+ nsString adapterDriverVendor; -+ gfxInfo->GetAdapterDriverVendor(adapterDriverVendor); -+ if (adapterDriverVendor.Find("mesa") != -1 && -+ adapterDriverVendor.Find("radeonsi") != -1) { -+ gfxVars::SetUseDMABufSurfaceExport(false); -+ } -+ } - } - - void gfxPlatform::InitWebGPUConfig() { diff --git a/build-cubeb-pulse-arm.patch b/build-cubeb-pulse-arm.patch deleted file mode 100644 index 008208c..0000000 --- a/build-cubeb-pulse-arm.patch +++ /dev/null @@ -1,4946 +0,0 @@ -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/Cargo.toml 2017-08-04 13:37:46.383821740 +0200 -@@ -7,7 +7,11 @@ description = "Cubeb backed for PulseAud - [features] - pulse-dlopen = ["pulse-ffi/dlopen"] - -+[lib] -+crate-type = ["staticlib", "rlib"] -+ - [dependencies] - cubeb-ffi = { path = "cubeb-ffi" } - pulse-ffi = { path = "pulse-ffi" } -+pulse = { path = "pulse-rs" } - semver = "^0.6" -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs 2017-08-04 13:37:46.384821737 +0200 -@@ -11,45 +11,45 @@ pub enum Context {} - pub enum Stream {} - - // These need to match cubeb_sample_format --pub const SAMPLE_S16LE: c_int = 0; --pub const SAMPLE_S16BE: c_int = 1; --pub const SAMPLE_FLOAT32LE: c_int = 2; --pub const SAMPLE_FLOAT32BE: c_int = 3; - pub type SampleFormat = c_int; -+pub const SAMPLE_S16LE: SampleFormat = 0; -+pub const SAMPLE_S16BE: SampleFormat = 1; -+pub const SAMPLE_FLOAT32LE: SampleFormat = 2; -+pub const SAMPLE_FLOAT32BE: SampleFormat = 3; - - #[cfg(target_endian = "little")] --pub const SAMPLE_S16NE: c_int = SAMPLE_S16LE; -+pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16LE; - #[cfg(target_endian = "little")] --pub const SAMPLE_FLOAT32NE: c_int = SAMPLE_FLOAT32LE; -+pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32LE; - #[cfg(target_endian = "big")] --pub const SAMPLE_S16NE: c_int = SAMPLE_S16BE; -+pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16BE; - #[cfg(target_endian = "big")] --pub const SAMPLE_FLOAT32NE: c_int = SAMPLE_FLOAT32BE; -+pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32BE; - - pub type DeviceId = *const c_void; - - // These need to match cubeb_channel_layout --pub const LAYOUT_UNDEFINED: c_int = 0; --pub const LAYOUT_DUAL_MONO: c_int = 1; --pub const LAYOUT_DUAL_MONO_LFE: c_int = 2; --pub const LAYOUT_MONO: c_int = 3; --pub const LAYOUT_MONO_LFE: c_int = 4; --pub const LAYOUT_STEREO: c_int = 5; --pub const LAYOUT_STEREO_LFE: c_int = 6; --pub const LAYOUT_3F: c_int = 7; --pub const LAYOUT_3F_LFE: c_int = 8; --pub const LAYOUT_2F1: c_int = 9; --pub const LAYOUT_2F1_LFE: c_int = 10; --pub const LAYOUT_3F1: c_int = 11; --pub const LAYOUT_3F1_LFE: c_int = 12; --pub const LAYOUT_2F2: c_int = 13; --pub const LAYOUT_2F2_LFE: c_int = 14; --pub const LAYOUT_3F2: c_int = 15; --pub const LAYOUT_3F2_LFE: c_int = 16; --pub const LAYOUT_3F3R_LFE: c_int = 17; --pub const LAYOUT_3F4_LFE: c_int = 18; --pub const LAYOUT_MAX: c_int = 19; - pub type ChannelLayout = c_int; -+pub const LAYOUT_UNDEFINED: ChannelLayout = 0; -+pub const LAYOUT_DUAL_MONO: ChannelLayout = 1; -+pub const LAYOUT_DUAL_MONO_LFE: ChannelLayout = 2; -+pub const LAYOUT_MONO: ChannelLayout = 3; -+pub const LAYOUT_MONO_LFE: ChannelLayout = 4; -+pub const LAYOUT_STEREO: ChannelLayout = 5; -+pub const LAYOUT_STEREO_LFE: ChannelLayout = 6; -+pub const LAYOUT_3F: ChannelLayout = 7; -+pub const LAYOUT_3F_LFE: ChannelLayout = 8; -+pub const LAYOUT_2F1: ChannelLayout = 9; -+pub const LAYOUT_2F1_LFE: ChannelLayout = 10; -+pub const LAYOUT_3F1: ChannelLayout = 11; -+pub const LAYOUT_3F1_LFE: ChannelLayout = 12; -+pub const LAYOUT_2F2: ChannelLayout = 13; -+pub const LAYOUT_2F2_LFE: ChannelLayout = 14; -+pub const LAYOUT_3F2: ChannelLayout = 15; -+pub const LAYOUT_3F2_LFE: ChannelLayout = 16; -+pub const LAYOUT_3F3R_LFE: ChannelLayout = 17; -+pub const LAYOUT_3F4_LFE: ChannelLayout = 18; -+pub const LAYOUT_MAX: ChannelLayout = 256; - - #[repr(C)] - #[derive(Clone, Copy, Debug)] -@@ -77,11 +77,11 @@ impl Default for Device { - } - - // These need to match cubeb_state --pub const STATE_STARTED: c_int = 0; --pub const STATE_STOPPED: c_int = 1; --pub const STATE_DRAINED: c_int = 2; --pub const STATE_ERROR: c_int = 3; - pub type State = c_int; -+pub const STATE_STARTED: State = 0; -+pub const STATE_STOPPED: State = 1; -+pub const STATE_DRAINED: State = 2; -+pub const STATE_ERROR: State = 3; - - pub const OK: i32 = 0; - pub const ERROR: i32 = -1; -@@ -249,32 +249,42 @@ pub struct LayoutMap { - } - - // cubeb_mixer.h -+pub type Channel = c_int; - - // These need to match cubeb_channel --pub const CHANNEL_INVALID: c_int = -1; --pub const CHANNEL_MONO: c_int = 0; --pub const CHANNEL_LEFT: c_int = 1; --pub const CHANNEL_RIGHT: c_int = 2; --pub const CHANNEL_CENTER: c_int = 3; --pub const CHANNEL_LS: c_int = 4; --pub const CHANNEL_RS: c_int = 5; --pub const CHANNEL_RLS: c_int = 6; --pub const CHANNEL_RCENTER: c_int = 7; --pub const CHANNEL_RRS: c_int = 8; --pub const CHANNEL_LFE: c_int = 9; --pub const CHANNEL_MAX: c_int = 256; --pub type Channel = c_int; -+pub const CHANNEL_INVALID: Channel = -1; -+pub const CHANNEL_MONO: Channel = 0; -+pub const CHANNEL_LEFT: Channel = 1; -+pub const CHANNEL_RIGHT: Channel = 2; -+pub const CHANNEL_CENTER: Channel = 3; -+pub const CHANNEL_LS: Channel = 4; -+pub const CHANNEL_RS: Channel = 5; -+pub const CHANNEL_RLS: Channel = 6; -+pub const CHANNEL_RCENTER: Channel = 7; -+pub const CHANNEL_RRS: Channel = 8; -+pub const CHANNEL_LFE: Channel = 9; -+pub const CHANNEL_MAX: Channel = 10; - - #[repr(C)] -+#[derive(Clone, Copy, Debug)] - pub struct ChannelMap { - pub channels: c_uint, -- pub map: [Channel; 256], -+ pub map: [Channel; CHANNEL_MAX as usize], - } - impl ::std::default::Default for ChannelMap { - fn default() -> Self { - ChannelMap { - channels: 0, -- map: unsafe { ::std::mem::zeroed() }, -+ map: [CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID, -+ CHANNEL_INVALID], - } - } - } -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs 2017-08-04 13:37:46.384821737 +0200 -@@ -8,8 +8,8 @@ macro_rules! cstr { - - #[cfg(not(feature = "dlopen"))] - mod static_fns { -- use std::os::raw::{c_char, c_double, c_int, c_float, c_uint, c_void}; - use super::*; -+ use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void}; - - #[link(name = "pulse")] - extern "C" { -@@ -62,6 +62,7 @@ mod static_fns { - userdata: *mut c_void) - -> *mut pa_operation; - pub fn pa_context_set_state_callback(c: *mut pa_context, cb: pa_context_notify_cb_t, userdata: *mut c_void); -+ pub fn pa_context_errno(c: *mut pa_context) -> c_int; - pub fn pa_context_set_subscribe_callback(c: *mut pa_context, - cb: pa_context_subscribe_cb_t, - userdata: *mut c_void); -@@ -70,6 +71,7 @@ mod static_fns { - cb: pa_context_success_cb_t, - userdata: *mut c_void) - -> *mut pa_operation; -+ pub fn pa_context_ref(c: *mut pa_context) -> *mut pa_context; - pub fn pa_context_unref(c: *mut pa_context); - pub fn pa_cvolume_set(a: *mut pa_cvolume, channels: c_uint, v: pa_volume_t) -> *mut pa_cvolume; - pub fn pa_cvolume_set_balance(v: *mut pa_cvolume, -@@ -80,12 +82,20 @@ mod static_fns { - pub fn pa_mainloop_api_once(m: *mut pa_mainloop_api, - callback: pa_mainloop_api_once_cb_t, - userdata: *mut c_void); -- pub fn pa_operation_get_state(o: *const pa_operation) -> pa_operation_state_t; -+ pub fn pa_strerror(error: pa_error_code_t) -> *const c_char; -+ pub fn pa_operation_ref(o: *mut pa_operation) -> *mut pa_operation; - pub fn pa_operation_unref(o: *mut pa_operation); -+ pub fn pa_operation_cancel(o: *mut pa_operation); -+ pub fn pa_operation_get_state(o: *const pa_operation) -> pa_operation_state_t; -+ pub fn pa_operation_set_state_callback(o: *mut pa_operation, -+ cb: pa_operation_notify_cb_t, -+ userdata: *mut c_void); - pub fn pa_proplist_gets(p: *mut pa_proplist, key: *const c_char) -> *const c_char; - pub fn pa_rtclock_now() -> pa_usec_t; - pub fn pa_stream_begin_write(p: *mut pa_stream, data: *mut *mut c_void, nbytes: *mut usize) -> c_int; - pub fn pa_stream_cancel_write(p: *mut pa_stream) -> c_int; -+ pub fn pa_stream_is_suspended(s: *const pa_stream) -> c_int; -+ pub fn pa_stream_is_corked(s: *const pa_stream) -> c_int; - pub fn pa_stream_connect_playback(s: *mut pa_stream, - dev: *const c_char, - attr: *const pa_buffer_attr, -@@ -112,6 +122,7 @@ mod static_fns { - pub fn pa_stream_get_latency(s: *const pa_stream, r_usec: *mut pa_usec_t, negative: *mut c_int) -> c_int; - pub fn pa_stream_get_sample_spec(s: *const pa_stream) -> *const pa_sample_spec; - pub fn pa_stream_get_state(p: *const pa_stream) -> pa_stream_state_t; -+ pub fn pa_stream_get_context(s: *const pa_stream) -> *mut pa_context; - pub fn pa_stream_get_time(s: *const pa_stream, r_usec: *mut pa_usec_t) -> c_int; - pub fn pa_stream_new(c: *mut pa_context, - name: *const c_char, -@@ -123,6 +134,7 @@ mod static_fns { - pub fn pa_stream_set_state_callback(s: *mut pa_stream, cb: pa_stream_notify_cb_t, userdata: *mut c_void); - pub fn pa_stream_set_write_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void); - pub fn pa_stream_set_read_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void); -+ pub fn pa_stream_ref(s: *mut pa_stream) -> *mut pa_stream; - pub fn pa_stream_unref(s: *mut pa_stream); - pub fn pa_stream_update_timing_info(p: *mut pa_stream, - cb: pa_stream_success_cb_t, -@@ -148,8 +160,6 @@ mod static_fns { - pub fn pa_threaded_mainloop_unlock(m: *mut pa_threaded_mainloop); - pub fn pa_threaded_mainloop_wait(m: *mut pa_threaded_mainloop); - pub fn pa_usec_to_bytes(t: pa_usec_t, spec: *const pa_sample_spec) -> usize; -- pub fn pa_xfree(ptr: *mut c_void); -- pub fn pa_xstrdup(str: *const c_char) -> *mut c_char; - pub fn pa_xrealloc(ptr: *mut c_void, size: usize) -> *mut c_void; - } - } -@@ -159,9 +169,9 @@ pub use self::static_fns::*; - - #[cfg(feature = "dlopen")] - mod dynamic_fns { -- use std::os::raw::{c_char, c_double, c_int, c_float, c_uint, c_void}; -- use libc::{dlclose, dlopen, dlsym, RTLD_LAZY}; - use super::*; -+ use libc::{RTLD_LAZY, dlclose, dlopen, dlsym}; -+ use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void}; - - #[derive(Debug)] - pub struct LibLoader { -@@ -287,6 +297,13 @@ mod dynamic_fns { - } - fp - }; -+ PA_CONTEXT_ERRNO = { -+ let fp = dlsym(h, cstr!("pa_context_errno")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; - PA_CONTEXT_SET_SUBSCRIBE_CALLBACK = { - let fp = dlsym(h, cstr!("pa_context_set_subscribe_callback")); - if fp.is_null() { -@@ -301,6 +318,13 @@ mod dynamic_fns { - } - fp - }; -+ PA_CONTEXT_REF = { -+ let fp = dlsym(h, cstr!("pa_context_ref")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; - PA_CONTEXT_UNREF = { - let fp = dlsym(h, cstr!("pa_context_unref")); - if fp.is_null() { -@@ -336,8 +360,15 @@ mod dynamic_fns { - } - fp - }; -- PA_OPERATION_GET_STATE = { -- let fp = dlsym(h, cstr!("pa_operation_get_state")); -+ PA_STRERROR = { -+ let fp = dlsym(h, cstr!("pa_strerror")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; -+ PA_OPERATION_REF = { -+ let fp = dlsym(h, cstr!("pa_operation_ref")); - if fp.is_null() { - return None; - } -@@ -350,6 +381,27 @@ mod dynamic_fns { - } - fp - }; -+ PA_OPERATION_CANCEL = { -+ let fp = dlsym(h, cstr!("pa_operation_cancel")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; -+ PA_OPERATION_GET_STATE = { -+ let fp = dlsym(h, cstr!("pa_operation_get_state")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; -+ PA_OPERATION_SET_STATE_CALLBACK = { -+ let fp = dlsym(h, cstr!("pa_operation_set_state_callback")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; - PA_PROPLIST_GETS = { - let fp = dlsym(h, cstr!("pa_proplist_gets")); - if fp.is_null() { -@@ -378,6 +430,20 @@ mod dynamic_fns { - } - fp - }; -+ PA_STREAM_IS_SUSPENDED = { -+ let fp = dlsym(h, cstr!("pa_stream_is_suspended")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; -+ PA_STREAM_IS_CORKED = { -+ let fp = dlsym(h, cstr!("pa_stream_is_corked")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; - PA_STREAM_CONNECT_PLAYBACK = { - let fp = dlsym(h, cstr!("pa_stream_connect_playback")); - if fp.is_null() { -@@ -462,6 +528,13 @@ mod dynamic_fns { - } - fp - }; -+ PA_STREAM_GET_CONTEXT = { -+ let fp = dlsym(h, cstr!("pa_stream_get_context")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; - PA_STREAM_GET_TIME = { - let fp = dlsym(h, cstr!("pa_stream_get_time")); - if fp.is_null() { -@@ -511,6 +584,13 @@ mod dynamic_fns { - } - fp - }; -+ PA_STREAM_REF = { -+ let fp = dlsym(h, cstr!("pa_stream_ref")); -+ if fp.is_null() { -+ return None; -+ } -+ fp -+ }; - PA_STREAM_UNREF = { - let fp = dlsym(h, cstr!("pa_stream_unref")); - if fp.is_null() { -@@ -623,20 +703,6 @@ mod dynamic_fns { - } - fp - }; -- PA_XFREE = { -- let fp = dlsym(h, cstr!("pa_xfree")); -- if fp.is_null() { -- return None; -- } -- fp -- }; -- PA_XSTRDUP = { -- let fp = dlsym(h, cstr!("pa_xstrdup")); -- if fp.is_null() { -- return None; -- } -- fp -- }; - PA_XREALLOC = { - let fp = dlsym(h, cstr!("pa_xrealloc")); - if fp.is_null() { -@@ -837,6 +903,12 @@ mod dynamic_fns { - *mut c_void)>(PA_CONTEXT_SET_STATE_CALLBACK))(c, cb, userdata) - } - -+ static mut PA_CONTEXT_ERRNO: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_context_errno(c: *mut pa_context) -> c_int { -+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_context) -> c_int>(PA_CONTEXT_ERRNO))(c) -+ } -+ - static mut PA_CONTEXT_SET_SUBSCRIBE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_context_set_subscribe_callback(c: *mut pa_context, -@@ -863,6 +935,12 @@ mod dynamic_fns { - -> *mut pa_operation>(PA_CONTEXT_SUBSCRIBE))(c, m, cb, userdata) - } - -+ static mut PA_CONTEXT_REF: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_context_ref(c: *mut pa_context) -> *mut pa_context { -+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_context) -> *mut pa_context>(PA_CONTEXT_REF))(c) -+ } -+ - static mut PA_CONTEXT_UNREF: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_context_unref(c: *mut pa_context) { -@@ -907,6 +985,30 @@ mod dynamic_fns { - *mut c_void)>(PA_MAINLOOP_API_ONCE))(m, callback, userdata) - } - -+ static mut PA_STRERROR: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_strerror(error: pa_error_code_t) -> *const c_char { -+ (::std::mem::transmute::<_, extern "C" fn(pa_error_code_t) -> *const c_char>(PA_STRERROR))(error) -+ } -+ -+ static mut PA_OPERATION_REF: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_operation_ref(o: *mut pa_operation) -> *mut pa_operation { -+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation) -> *mut pa_operation>(PA_OPERATION_REF))(o) -+ } -+ -+ static mut PA_OPERATION_UNREF: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_operation_unref(o: *mut pa_operation) { -+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation)>(PA_OPERATION_UNREF))(o) -+ } -+ -+ static mut PA_OPERATION_CANCEL: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_operation_cancel(o: *mut pa_operation) { -+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation)>(PA_OPERATION_CANCEL))(o) -+ } -+ - static mut PA_OPERATION_GET_STATE: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_operation_get_state(o: *const pa_operation) -> pa_operation_state_t { -@@ -915,10 +1017,15 @@ mod dynamic_fns { - -> pa_operation_state_t>(PA_OPERATION_GET_STATE))(o) - } - -- static mut PA_OPERATION_UNREF: *mut ::libc::c_void = 0 as *mut _; -+ static mut PA_OPERATION_SET_STATE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; - #[inline] -- pub unsafe fn pa_operation_unref(o: *mut pa_operation) { -- (::std::mem::transmute::<_, extern "C" fn(*mut pa_operation)>(PA_OPERATION_UNREF))(o) -+ pub unsafe fn pa_operation_set_state_callback(o: *mut pa_operation, -+ cb: pa_operation_notify_cb_t, -+ userdata: *mut c_void) { -+ (::std::mem::transmute::<_, -+ extern "C" fn(*mut pa_operation, -+ pa_operation_notify_cb_t, -+ *mut c_void)>(PA_OPERATION_SET_STATE_CALLBACK))(o, cb, userdata) - } - - static mut PA_PROPLIST_GETS: *mut ::libc::c_void = 0 as *mut _; -@@ -951,6 +1058,18 @@ mod dynamic_fns { - (::std::mem::transmute::<_, extern "C" fn(*mut pa_stream) -> c_int>(PA_STREAM_CANCEL_WRITE))(p) - } - -+ static mut PA_STREAM_IS_SUSPENDED: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_stream_is_suspended(s: *const pa_stream) -> c_int { -+ (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> c_int>(PA_STREAM_IS_SUSPENDED))(s) -+ } -+ -+ static mut PA_STREAM_IS_CORKED: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_stream_is_corked(s: *const pa_stream) -> c_int { -+ (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> c_int>(PA_STREAM_IS_CORKED))(s) -+ } -+ - static mut PA_STREAM_CONNECT_PLAYBACK: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_stream_connect_playback(s: *mut pa_stream, -@@ -1066,6 +1185,12 @@ mod dynamic_fns { - (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> pa_stream_state_t>(PA_STREAM_GET_STATE))(p) - } - -+ static mut PA_STREAM_GET_CONTEXT: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_stream_get_context(s: *const pa_stream) -> *mut pa_context { -+ (::std::mem::transmute::<_, extern "C" fn(*const pa_stream) -> *mut pa_context>(PA_STREAM_GET_CONTEXT))(s) -+ } -+ - static mut PA_STREAM_GET_TIME: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_stream_get_time(s: *const pa_stream, r_usec: *mut pa_usec_t) -> c_int { -@@ -1132,6 +1257,12 @@ mod dynamic_fns { - *mut c_void)>(PA_STREAM_SET_READ_CALLBACK))(p, cb, userdata) - } - -+ static mut PA_STREAM_REF: *mut ::libc::c_void = 0 as *mut _; -+ #[inline] -+ pub unsafe fn pa_stream_ref(s: *mut pa_stream) -> *mut pa_stream { -+ (::std::mem::transmute::<_, extern "C" fn(*mut pa_stream) -> *mut pa_stream>(PA_STREAM_REF))(s) -+ } -+ - static mut PA_STREAM_UNREF: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_stream_unref(s: *mut pa_stream) { -@@ -1253,18 +1384,6 @@ mod dynamic_fns { - spec) - } - -- static mut PA_XFREE: *mut ::libc::c_void = 0 as *mut _; -- #[inline] -- pub unsafe fn pa_xfree(ptr: *mut c_void) { -- (::std::mem::transmute::<_, extern "C" fn(*mut c_void)>(PA_XFREE))(ptr) -- } -- -- static mut PA_XSTRDUP: *mut ::libc::c_void = 0 as *mut _; -- #[inline] -- pub unsafe fn pa_xstrdup(str: *const c_char) -> *mut c_char { -- (::std::mem::transmute::<_, extern "C" fn(*const c_char) -> *mut c_char>(PA_XSTRDUP))(str) -- } -- - static mut PA_XREALLOC: *mut ::libc::c_void = 0 as *mut _; - #[inline] - pub unsafe fn pa_xrealloc(ptr: *mut c_void, size: usize) -> *mut c_void { -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs 2017-08-04 13:37:46.384821737 +0200 -@@ -1,6 +1,6 @@ - #![allow(non_camel_case_types)] - --use std::os::raw::{c_char, c_int, c_long, c_ulong, c_void}; -+use std::os::raw::{c_char, c_int, c_long, c_uint, c_ulong, c_void}; - - /* automatically generated by rust-bindgen */ - pub const PA_RATE_MAX: u32 = 48000 * 8; -@@ -74,10 +74,10 @@ pub const PA_OPERATION_DONE: c_int = 1; - pub const PA_OPERATION_CANCELLED: c_int = 2; - pub type pa_operation_state_t = c_int; - --pub const PA_CONTEXT_NOFLAGS: c_int = 0; --pub const PA_CONTEXT_NOAUTOSPAWN: c_int = 1; --pub const PA_CONTEXT_NOFAIL: c_int = 2; --pub type pa_context_flags_t = c_int; -+pub const PA_CONTEXT_NOFLAGS: c_uint = 0; -+pub const PA_CONTEXT_NOAUTOSPAWN: c_uint = 1; -+pub const PA_CONTEXT_NOFAIL: c_uint = 2; -+pub type pa_context_flags_t = c_uint; - - pub const PA_DIRECTION_OUTPUT: c_int = 1; - pub const PA_DIRECTION_INPUT: c_int = 2; -@@ -93,28 +93,28 @@ pub const PA_STREAM_RECORD: c_int = 2; - pub const PA_STREAM_UPLOAD: c_int = 3; - pub type pa_stream_direction_t = c_int; - --pub const PA_STREAM_NOFLAGS: c_int = 0x0_0000; --pub const PA_STREAM_START_CORKED: c_int = 0x0_0001; --pub const PA_STREAM_INTERPOLATE_TIMING: c_int = 0x0_0002; --pub const PA_STREAM_NOT_MONOTONIC: c_int = 0x0_0004; --pub const PA_STREAM_AUTO_TIMING_UPDATE: c_int = 0x0_0008; --pub const PA_STREAM_NO_REMAP_CHANNELS: c_int = 0x0_0010; --pub const PA_STREAM_NO_REMIX_CHANNELS: c_int = 0x0_0020; --pub const PA_STREAM_FIX_FORMAT: c_int = 0x0_0040; --pub const PA_STREAM_FIX_RATE: c_int = 0x0_0080; --pub const PA_STREAM_FIX_CHANNELS: c_int = 0x0_0100; --pub const PA_STREAM_DONT_MOVE: c_int = 0x0_0200; --pub const PA_STREAM_VARIABLE_RATE: c_int = 0x0_0400; --pub const PA_STREAM_PEAK_DETECT: c_int = 0x0_0800; --pub const PA_STREAM_START_MUTED: c_int = 0x0_1000; --pub const PA_STREAM_ADJUST_LATENCY: c_int = 0x0_2000; --pub const PA_STREAM_EARLY_REQUESTS: c_int = 0x0_4000; --pub const PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND: c_int = 0x0_8000; --pub const PA_STREAM_START_UNMUTED: c_int = 0x1_0000; --pub const PA_STREAM_FAIL_ON_SUSPEND: c_int = 0x2_0000; --pub const PA_STREAM_RELATIVE_VOLUME: c_int = 0x4_0000; --pub const PA_STREAM_PASSTHROUGH: c_int = 0x8_0000; --pub type pa_stream_flags_t = c_int; -+pub const PA_STREAM_NOFLAGS: c_uint = 0x0_0000; -+pub const PA_STREAM_START_CORKED: c_uint = 0x0_0001; -+pub const PA_STREAM_INTERPOLATE_TIMING: c_uint = 0x0_0002; -+pub const PA_STREAM_NOT_MONOTONIC: c_uint = 0x0_0004; -+pub const PA_STREAM_AUTO_TIMING_UPDATE: c_uint = 0x0_0008; -+pub const PA_STREAM_NO_REMAP_CHANNELS: c_uint = 0x0_0010; -+pub const PA_STREAM_NO_REMIX_CHANNELS: c_uint = 0x0_0020; -+pub const PA_STREAM_FIX_FORMAT: c_uint = 0x0_0040; -+pub const PA_STREAM_FIX_RATE: c_uint = 0x0_0080; -+pub const PA_STREAM_FIX_CHANNELS: c_uint = 0x0_0100; -+pub const PA_STREAM_DONT_MOVE: c_uint = 0x0_0200; -+pub const PA_STREAM_VARIABLE_RATE: c_uint = 0x0_0400; -+pub const PA_STREAM_PEAK_DETECT: c_uint = 0x0_0800; -+pub const PA_STREAM_START_MUTED: c_uint = 0x0_1000; -+pub const PA_STREAM_ADJUST_LATENCY: c_uint = 0x0_2000; -+pub const PA_STREAM_EARLY_REQUESTS: c_uint = 0x0_4000; -+pub const PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND: c_uint = 0x0_8000; -+pub const PA_STREAM_START_UNMUTED: c_uint = 0x1_0000; -+pub const PA_STREAM_FAIL_ON_SUSPEND: c_uint = 0x2_0000; -+pub const PA_STREAM_RELATIVE_VOLUME: c_uint = 0x4_0000; -+pub const PA_STREAM_PASSTHROUGH: c_uint = 0x8_0000; -+pub type pa_stream_flags_t = c_uint; - - #[repr(C)] - #[derive(Clone, Copy, Debug)] -@@ -162,19 +162,19 @@ pub const PA_ERR_BUSY: c_int = 26; - pub const PA_ERR_MAX: c_int = 27; - pub type pa_error_code_t = c_int; - --pub const PA_SUBSCRIPTION_MASK_NULL: c_int = 0; --pub const PA_SUBSCRIPTION_MASK_SINK: c_int = 1; --pub const PA_SUBSCRIPTION_MASK_SOURCE: c_int = 2; --pub const PA_SUBSCRIPTION_MASK_SINK_INPUT: c_int = 4; --pub const PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT: c_int = 8; --pub const PA_SUBSCRIPTION_MASK_MODULE: c_int = 16; --pub const PA_SUBSCRIPTION_MASK_CLIENT: c_int = 32; --pub const PA_SUBSCRIPTION_MASK_SAMPLE_CACHE: c_int = 64; --pub const PA_SUBSCRIPTION_MASK_SERVER: c_int = 128; --pub const PA_SUBSCRIPTION_MASK_AUTOLOAD: c_int = 256; --pub const PA_SUBSCRIPTION_MASK_CARD: c_int = 512; --pub const PA_SUBSCRIPTION_MASK_ALL: c_int = 767; --pub type pa_subscription_mask_t = c_int; -+pub const PA_SUBSCRIPTION_MASK_NULL: c_uint = 0x0; -+pub const PA_SUBSCRIPTION_MASK_SINK: c_uint = 0x1; -+pub const PA_SUBSCRIPTION_MASK_SOURCE: c_uint = 0x2; -+pub const PA_SUBSCRIPTION_MASK_SINK_INPUT: c_uint = 0x4; -+pub const PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT: c_uint = 0x8; -+pub const PA_SUBSCRIPTION_MASK_MODULE: c_uint = 0x10; -+pub const PA_SUBSCRIPTION_MASK_CLIENT: c_uint = 0x20; -+pub const PA_SUBSCRIPTION_MASK_SAMPLE_CACHE: c_uint = 0x40; -+pub const PA_SUBSCRIPTION_MASK_SERVER: c_uint = 0x80; -+pub const PA_SUBSCRIPTION_MASK_AUTOLOAD: c_uint = 0x100; -+pub const PA_SUBSCRIPTION_MASK_CARD: c_uint = 0x200; -+pub const PA_SUBSCRIPTION_MASK_ALL: c_uint = 0x3FF; -+pub type pa_subscription_mask_t = c_uint; - - pub const PA_SUBSCRIPTION_EVENT_SINK: c_int = 0; - pub const PA_SUBSCRIPTION_EVENT_SOURCE: c_int = 1; -@@ -244,17 +244,17 @@ pub const PA_SEEK_RELATIVE_ON_READ: c_in - pub const PA_SEEK_RELATIVE_END: c_int = 3; - pub type pa_seek_mode_t = c_int; - --pub const PA_SINK_NOFLAGS: c_int = 0; --pub const PA_SINK_HW_VOLUME_CTRL: c_int = 1; --pub const PA_SINK_LATENCY: c_int = 2; --pub const PA_SINK_HARDWARE: c_int = 4; --pub const PA_SINK_NETWORK: c_int = 8; --pub const PA_SINK_HW_MUTE_CTRL: c_int = 16; --pub const PA_SINK_DECIBEL_VOLUME: c_int = 32; --pub const PA_SINK_FLAT_VOLUME: c_int = 64; --pub const PA_SINK_DYNAMIC_LATENCY: c_int = 128; --pub const PA_SINK_SET_FORMATS: c_int = 256; --pub type pa_sink_flags_t = c_int; -+pub const PA_SINK_NOFLAGS: c_uint = 0x000; -+pub const PA_SINK_HW_VOLUME_CTRL: c_uint = 0x001; -+pub const PA_SINK_LATENCY: c_uint = 0x002; -+pub const PA_SINK_HARDWARE: c_uint = 0x004; -+pub const PA_SINK_NETWORK: c_uint = 0x008; -+pub const PA_SINK_HW_MUTE_CTRL: c_uint = 0x010; -+pub const PA_SINK_DECIBEL_VOLUME: c_uint = 0x020; -+pub const PA_SINK_FLAT_VOLUME: c_uint = 0x040; -+pub const PA_SINK_DYNAMIC_LATENCY: c_uint = 0x080; -+pub const PA_SINK_SET_FORMATS: c_uint = 0x100; -+pub type pa_sink_flags_t = c_uint; - - pub const PA_SINK_INVALID_STATE: c_int = -1; - pub const PA_SINK_RUNNING: c_int = 0; -@@ -264,16 +264,16 @@ pub const PA_SINK_INIT: c_int = -2; - pub const PA_SINK_UNLINKED: c_int = -3; - pub type pa_sink_state_t = c_int; - --pub const PA_SOURCE_NOFLAGS: c_int = 0x00; --pub const PA_SOURCE_HW_VOLUME_CTRL: c_int = 0x01; --pub const PA_SOURCE_LATENCY: c_int = 0x02; --pub const PA_SOURCE_HARDWARE: c_int = 0x04; --pub const PA_SOURCE_NETWORK: c_int = 0x08; --pub const PA_SOURCE_HW_MUTE_CTRL: c_int = 0x10; --pub const PA_SOURCE_DECIBEL_VOLUME: c_int = 0x20; --pub const PA_SOURCE_DYNAMIC_LATENCY: c_int = 0x40; --pub const PA_SOURCE_FLAT_VOLUME: c_int = 0x80; --pub type pa_source_flags_t = c_int; -+pub const PA_SOURCE_NOFLAGS: c_uint = 0x00; -+pub const PA_SOURCE_HW_VOLUME_CTRL: c_uint = 0x01; -+pub const PA_SOURCE_LATENCY: c_uint = 0x02; -+pub const PA_SOURCE_HARDWARE: c_uint = 0x04; -+pub const PA_SOURCE_NETWORK: c_uint = 0x08; -+pub const PA_SOURCE_HW_MUTE_CTRL: c_uint = 0x10; -+pub const PA_SOURCE_DECIBEL_VOLUME: c_uint = 0x20; -+pub const PA_SOURCE_DYNAMIC_LATENCY: c_uint = 0x40; -+pub const PA_SOURCE_FLAT_VOLUME: c_uint = 0x80; -+pub type pa_source_flags_t = c_uint; - - pub const PA_SOURCE_INVALID_STATE: c_int = -1; - pub const PA_SOURCE_RUNNING: c_int = 0; -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml.cubeb-pulse-arm 2017-08-04 13:37:46.384821737 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/Cargo.toml 2017-08-04 13:37:46.384821737 +0200 -@@ -0,0 +1,8 @@ -+[package] -+name = "pulse" -+version = "0.1.0" -+authors = ["Dan Glastonbury "] -+ -+[dependencies] -+bitflags = "^0.7.0" -+pulse-ffi = { path = "../pulse-ffi" } -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs 2017-08-04 13:37:46.385821734 +0200 -@@ -0,0 +1,394 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ::*; -+use ffi; -+use std::ffi::CStr; -+use std::os::raw::{c_int, c_void}; -+use std::ptr; -+use util::UnwrapCStr; -+ -+// A note about `wrapped` functions -+// -+// C FFI demands `unsafe extern fn(*mut pa_context, ...) -> i32`, etc, -+// but we want to allow such callbacks to be safe. This means no -+// `unsafe` or `extern`, and callbacks should be called with a safe -+// wrapper of `*mut pa_context`. Since the callback doesn't take -+// ownership, this is `&Context`. `fn wrapped(...)` defines a -+// function that converts from our safe signature to the unsafe -+// signature. -+// -+// Currently, we use a property of Rust, namely that each function -+// gets its own unique type. These unique types can't be written -+// directly, so we use generic and a type parameter, and let the Rust -+// compiler fill in the name for us: -+// -+// fn get_sink_input_info(&self, ..., _: CB, ...) -> ... -+// where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void) -+// -+// Because we aren't storing or passing any state, we assert, at run-time :-(, -+// that our functions are zero-sized: -+// -+// assert!(mem::size_of::() == 0); -+// -+// We need to obtain a value of type F in order to call it. Since we -+// can't name the function, we have to unsafely construct that value -+// somehow - we do this using mem::uninitialized. Then, we call that -+// function with a reference to the Context, and save the result: -+// -+// | generate value || call it | -+// let result = ::std::mem::uninitialized::()(&mut object); -+// -+// Lastly, since our Object is an owned type, we need to avoid -+// dropping it, then return the result we just generated. -+// -+// mem::forget(object); -+// result -+ -+// Aid in returning Operation from callbacks -+macro_rules! op_or_err { -+ ($self_:ident, $e:expr) => {{ -+ let o = unsafe { $e }; -+ if o.is_null() { -+ Err(ErrorCode::from_error_code($self_.errno())) -+ } else { -+ Ok(unsafe { operation::from_raw_ptr(o) }) -+ } -+ }} -+} -+ -+#[repr(C)] -+#[derive(Debug)] -+pub struct Context(*mut ffi::pa_context); -+ -+impl Context { -+ pub fn new<'a, OPT>(api: &MainloopApi, name: OPT) -> Option -+ where OPT: Into> -+ { -+ let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) }; -+ if ptr.is_null() { -+ None -+ } else { -+ Some(Context(ptr)) -+ } -+ } -+ -+ #[doc(hidden)] -+ pub fn raw_mut(&self) -> &mut ffi::pa_context { -+ unsafe { &mut *self.0 } -+ } -+ -+ pub fn unref(self) { -+ unsafe { -+ ffi::pa_context_unref(self.raw_mut()); -+ } -+ } -+ -+ pub fn clear_state_callback(&self) { -+ unsafe { -+ ffi::pa_context_set_state_callback(self.raw_mut(), None, ptr::null_mut()); -+ } -+ } -+ -+ pub fn set_state_callback(&self, _: CB, userdata: *mut c_void) -+ where CB: Fn(&Context, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, userdata: *mut c_void) -+ where F: Fn(&Context, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ unsafe { -+ ffi::pa_context_set_state_callback(self.raw_mut(), Some(wrapped::), userdata); -+ } -+ } -+ -+ pub fn errno(&self) -> ffi::pa_error_code_t { -+ unsafe { ffi::pa_context_errno(self.raw_mut()) } -+ } -+ -+ pub fn get_state(&self) -> ContextState { -+ ContextState::try_from(unsafe { -+ ffi::pa_context_get_state(self.raw_mut()) -+ }).expect("pa_context_get_state returned invalid ContextState") -+ } -+ -+ pub fn connect<'a, OPT>(&self, server: OPT, flags: ContextFlags, api: *const ffi::pa_spawn_api) -> Result<()> -+ where OPT: Into> -+ { -+ let r = unsafe { -+ ffi::pa_context_connect(self.raw_mut(), -+ server.into().unwrap_cstr(), -+ flags.into(), -+ api) -+ }; -+ error_result!((), r) -+ } -+ -+ pub fn disconnect(&self) { -+ unsafe { -+ ffi::pa_context_disconnect(self.raw_mut()); -+ } -+ } -+ -+ -+ pub fn drain(&self, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, userdata: *mut c_void) -+ where F: Fn(&Context, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_drain(self.raw_mut(), Some(wrapped::), userdata)) -+ } -+ -+ pub fn rttime_new(&self, usec: USec, _: CB, userdata: *mut c_void) -> *mut ffi::pa_time_event -+ where CB: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(a: *mut ffi::pa_mainloop_api, -+ e: *mut ffi::pa_time_event, -+ tv: *const TimeVal, -+ userdata: *mut c_void) -+ where F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let api = mainloop_api::from_raw_ptr(a); -+ let timeval = &*tv; -+ let result = uninitialized::()(&api, e, timeval, userdata); -+ forget(api); -+ -+ result -+ } -+ -+ unsafe { ffi::pa_context_rttime_new(self.raw_mut(), usec, Some(wrapped::), userdata) } -+ } -+ -+ pub fn get_server_info(&self, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, &ServerInfo, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, i: *const ffi::pa_server_info, userdata: *mut c_void) -+ where F: Fn(&Context, &ServerInfo, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ debug_assert_ne!(i, ptr::null_mut()); -+ let info = &*i; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, info, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::), userdata)) -+ } -+ -+ pub fn get_sink_info_by_name(&self, name: &CStr, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, -+ info: *const ffi::pa_sink_info, -+ eol: c_int, -+ userdata: *mut c_void) -+ where F: Fn(&Context, *const SinkInfo, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, info, eol, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_get_sink_info_by_name(self.raw_mut(), name.as_ptr(), Some(wrapped::), userdata)) -+ } -+ -+ pub fn get_sink_info_list(&self, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, *const SinkInfo, i32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, -+ info: *const ffi::pa_sink_info, -+ eol: c_int, -+ userdata: *mut c_void) -+ where F: Fn(&Context, *const SinkInfo, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, info, eol, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::), userdata)) -+ } -+ -+ pub fn get_sink_input_info(&self, idx: u32, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, -+ info: *const ffi::pa_sink_input_info, -+ eol: c_int, -+ userdata: *mut c_void) -+ where F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, info, eol, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::), userdata)) -+ } -+ -+ pub fn get_source_info_list(&self, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, *const SourceInfo, i32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, -+ info: *const ffi::pa_source_info, -+ eol: c_int, -+ userdata: *mut c_void) -+ where F: Fn(&Context, *const SourceInfo, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, info, eol, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::), userdata)) -+ } -+ -+ pub fn set_sink_input_volume(&self, -+ idx: u32, -+ volume: &CVolume, -+ _: CB, -+ userdata: *mut c_void) -+ -> Result -+ where CB: Fn(&Context, i32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void) -+ where F: Fn(&Context, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, success, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_set_sink_input_volume(self.raw_mut(), idx, volume, Some(wrapped::), userdata)) -+ } -+ -+ pub fn subscribe(&self, m: SubscriptionMask, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Context, i32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void) -+ where F: Fn(&Context, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let result = uninitialized::()(&ctx, success, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ op_or_err!(self, -+ ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::), userdata)) -+ } -+ -+ pub fn clear_subscribe_callback(&self) { -+ unsafe { -+ ffi::pa_context_set_subscribe_callback(self.raw_mut(), None, ptr::null_mut()); -+ } -+ } -+ -+ pub fn set_subscribe_callback(&self, _: CB, userdata: *mut c_void) -+ where CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void) -+ { -+ debug_assert_eq!(::std::mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(c: *mut ffi::pa_context, -+ t: ffi::pa_subscription_event_type_t, -+ idx: u32, -+ userdata: *mut c_void) -+ where F: Fn(&Context, SubscriptionEvent, u32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let ctx = context::from_raw_ptr(c); -+ let event = SubscriptionEvent::try_from(t) -+ .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t"); -+ let result = uninitialized::()(&ctx, event, idx, userdata); -+ forget(ctx); -+ -+ result -+ } -+ -+ unsafe { -+ ffi::pa_context_set_subscribe_callback(self.raw_mut(), Some(wrapped::), userdata); -+ } -+ } -+} -+ -+#[doc(hidden)] -+pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_context) -> Context { -+ Context(ptr) -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs 2017-08-04 13:37:46.385821734 +0200 -@@ -0,0 +1,56 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ffi; -+use std::ffi::CStr; -+ -+#[macro_export] -+macro_rules! error_result { -+ ($t:expr, $err:expr) => { -+ if $err >= 0 { -+ Ok($t) -+ } else { -+ Err(ErrorCode::from_error_result($err)) -+ } -+ } -+} -+ -+#[derive(Debug, PartialEq)] -+pub struct ErrorCode { -+ err: ffi::pa_error_code_t, -+} -+ -+impl ErrorCode { -+ pub fn from_error_result(err: i32) -> Self { -+ debug_assert!(err < 0); -+ ErrorCode { -+ err: (-err) as ffi::pa_error_code_t, -+ } -+ } -+ -+ pub fn from_error_code(err: ffi::pa_error_code_t) -> Self { -+ debug_assert!(err > 0); -+ ErrorCode { -+ err: err, -+ } -+ } -+ -+ fn desc(&self) -> &'static str { -+ let cstr = unsafe { CStr::from_ptr(ffi::pa_strerror(self.err)) }; -+ cstr.to_str().unwrap() -+ } -+} -+ -+impl ::std::error::Error for ErrorCode { -+ fn description(&self) -> &str { -+ self.desc() -+ } -+} -+ -+impl ::std::fmt::Display for ErrorCode { -+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { -+ write!(f, "{:?}: {}", self, self.desc()) -+ } -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs 2017-08-04 13:37:46.385821734 +0200 -@@ -0,0 +1,653 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+#[macro_use] -+extern crate bitflags; -+extern crate pulse_ffi as ffi; -+ -+#[macro_use] -+mod error; -+mod context; -+mod mainloop_api; -+mod operation; -+mod proplist; -+mod stream; -+mod threaded_mainloop; -+mod util; -+ -+pub use context::Context; -+pub use error::ErrorCode; -+pub use ffi::pa_buffer_attr as BufferAttr; -+pub use ffi::pa_channel_map as ChannelMap; -+pub use ffi::pa_cvolume as CVolume; -+pub use ffi::pa_sample_spec as SampleSpec; -+pub use ffi::pa_server_info as ServerInfo; -+pub use ffi::pa_sink_info as SinkInfo; -+pub use ffi::pa_sink_input_info as SinkInputInfo; -+pub use ffi::pa_source_info as SourceInfo; -+pub use ffi::pa_usec_t as USec; -+pub use ffi::pa_volume_t as Volume; -+pub use ffi::timeval as TimeVal; -+pub use mainloop_api::MainloopApi; -+pub use operation::Operation; -+pub use proplist::Proplist; -+use std::os::raw::{c_char, c_uint}; -+pub use stream::Stream; -+pub use threaded_mainloop::ThreadedMainloop; -+ -+#[allow(non_camel_case_types)] -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum SampleFormat { -+ Invalid = ffi::PA_SAMPLE_INVALID, -+ U8 = ffi::PA_SAMPLE_U8, -+ Alaw = ffi::PA_SAMPLE_ALAW, -+ Ulaw = ffi::PA_SAMPLE_ULAW, -+ Signed16LE = ffi::PA_SAMPLE_S16LE, -+ Signed16BE = ffi::PA_SAMPLE_S16BE, -+ Float32LE = ffi::PA_SAMPLE_FLOAT32LE, -+ Float32BE = ffi::PA_SAMPLE_FLOAT32BE, -+ Signed32LE = ffi::PA_SAMPLE_S32LE, -+ Signed32BE = ffi::PA_SAMPLE_S32BE, -+ Signed24LE = ffi::PA_SAMPLE_S24LE, -+ Signed24BE = ffi::PA_SAMPLE_S24BE, -+ Signed24_32LE = ffi::PA_SAMPLE_S24_32LE, -+ Signed23_32BE = ffi::PA_SAMPLE_S24_32BE, -+} -+ -+impl Default for SampleFormat { -+ fn default() -> Self { -+ SampleFormat::Invalid -+ } -+} -+ -+impl Into for SampleFormat { -+ fn into(self) -> ffi::pa_sample_format_t { -+ self as ffi::pa_sample_format_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum ContextState { -+ Unconnected = ffi::PA_CONTEXT_UNCONNECTED, -+ Connecting = ffi::PA_CONTEXT_CONNECTING, -+ Authorizing = ffi::PA_CONTEXT_AUTHORIZING, -+ SettingName = ffi::PA_CONTEXT_SETTING_NAME, -+ Ready = ffi::PA_CONTEXT_READY, -+ Failed = ffi::PA_CONTEXT_FAILED, -+ Terminated = ffi::PA_CONTEXT_TERMINATED, -+} -+ -+impl ContextState { -+ // This function implements the PA_CONTENT_IS_GOOD macro from pulse/def.h -+ // It must match the version from PA headers. -+ pub fn is_good(self) -> bool { -+ match self { -+ ContextState::Connecting | -+ ContextState::Authorizing | -+ ContextState::SettingName | -+ ContextState::Ready => true, -+ _ => false, -+ } -+ } -+ -+ pub fn try_from(x: ffi::pa_context_state_t) -> Option { -+ if x >= ffi::PA_CONTEXT_UNCONNECTED && x <= ffi::PA_CONTEXT_TERMINATED { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Default for ContextState { -+ fn default() -> Self { -+ ContextState::Unconnected -+ } -+} -+ -+impl Into for ContextState { -+ fn into(self) -> ffi::pa_context_state_t { -+ self as ffi::pa_context_state_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum StreamState { -+ Unconnected = ffi::PA_STREAM_UNCONNECTED, -+ Creating = ffi::PA_STREAM_CREATING, -+ Ready = ffi::PA_STREAM_READY, -+ Failed = ffi::PA_STREAM_FAILED, -+ Terminated = ffi::PA_STREAM_TERMINATED, -+} -+ -+impl StreamState { -+ // This function implements the PA_STREAM_IS_GOOD macro from pulse/def.h -+ // It must match the version from PA headers. -+ pub fn is_good(self) -> bool { -+ match self { -+ StreamState::Creating | StreamState::Ready => true, -+ _ => false, -+ } -+ } -+ -+ pub fn try_from(x: ffi::pa_stream_state_t) -> Option { -+ if x >= ffi::PA_STREAM_UNCONNECTED && x <= ffi::PA_STREAM_TERMINATED { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Default for StreamState { -+ fn default() -> Self { -+ StreamState::Unconnected -+ } -+} -+ -+impl Into for StreamState { -+ fn into(self) -> ffi::pa_stream_state_t { -+ self as ffi::pa_stream_state_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum OperationState { -+ Running = ffi::PA_OPERATION_RUNNING, -+ Done = ffi::PA_OPERATION_DONE, -+ Cancelled = ffi::PA_OPERATION_CANCELLED, -+} -+ -+impl OperationState { -+ pub fn try_from(x: ffi::pa_operation_state_t) -> Option { -+ if x >= ffi::PA_OPERATION_RUNNING && x <= ffi::PA_OPERATION_CANCELLED { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for OperationState { -+ fn into(self) -> ffi::pa_operation_state_t { -+ self as ffi::pa_operation_state_t -+ } -+} -+ -+bitflags! { -+ pub flags ContextFlags: u32 { -+ const CONTEXT_FLAGS_NOAUTOSPAWN = ffi::PA_CONTEXT_NOAUTOSPAWN, -+ const CONTEXT_FLAGS_NOFAIL = ffi::PA_CONTEXT_NOFAIL, -+ } -+} -+ -+impl Into for ContextFlags { -+ fn into(self) -> ffi::pa_context_flags_t { -+ self.bits() as ffi::pa_context_flags_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum DeviceType { -+ Sink = ffi::PA_DEVICE_TYPE_SINK, -+ Source = ffi::PA_DEVICE_TYPE_SOURCE, -+} -+ -+impl DeviceType { -+ pub fn try_from(x: ffi::pa_device_type_t) -> Option { -+ if x >= ffi::PA_DEVICE_TYPE_SINK && x <= ffi::PA_DEVICE_TYPE_SOURCE { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for DeviceType { -+ fn into(self) -> ffi::pa_device_type_t { -+ self as ffi::pa_device_type_t -+ } -+} -+ -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum StreamDirection { -+ NoDirection = ffi::PA_STREAM_NODIRECTION, -+ Playback = ffi::PA_STREAM_PLAYBACK, -+ Record = ffi::PA_STREAM_RECORD, -+ StreamUpload = ffi::PA_STREAM_UPLOAD, -+} -+ -+impl StreamDirection { -+ pub fn try_from(x: ffi::pa_stream_direction_t) -> Option { -+ if x >= ffi::PA_STREAM_NODIRECTION && x <= ffi::PA_STREAM_UPLOAD { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for StreamDirection { -+ fn into(self) -> ffi::pa_stream_direction_t { -+ self as ffi::pa_stream_direction_t -+ } -+} -+ -+bitflags! { -+ pub flags StreamFlags : u32 { -+ const STREAM_START_CORKED = ffi::PA_STREAM_START_CORKED, -+ const STREAM_INTERPOLATE_TIMING = ffi::PA_STREAM_INTERPOLATE_TIMING, -+ const STREAM_NOT_MONOTONIC = ffi::PA_STREAM_NOT_MONOTONIC, -+ const STREAM_AUTO_TIMING_UPDATE = ffi::PA_STREAM_AUTO_TIMING_UPDATE, -+ const STREAM_NO_REMAP_CHANNELS = ffi::PA_STREAM_NO_REMAP_CHANNELS, -+ const STREAM_NO_REMIX_CHANNELS = ffi::PA_STREAM_NO_REMIX_CHANNELS, -+ const STREAM_FIX_FORMAT = ffi::PA_STREAM_FIX_FORMAT, -+ const STREAM_FIX_RATE = ffi::PA_STREAM_FIX_RATE, -+ const STREAM_FIX_CHANNELS = ffi::PA_STREAM_FIX_CHANNELS, -+ const STREAM_DONT_MOVE = ffi::PA_STREAM_DONT_MOVE, -+ const STREAM_VARIABLE_RATE = ffi::PA_STREAM_VARIABLE_RATE, -+ const STREAM_PEAK_DETECT = ffi::PA_STREAM_PEAK_DETECT, -+ const STREAM_START_MUTED = ffi::PA_STREAM_START_MUTED, -+ const STREAM_ADJUST_LATENCY = ffi::PA_STREAM_ADJUST_LATENCY, -+ const STREAM_EARLY_REQUESTS = ffi::PA_STREAM_EARLY_REQUESTS, -+ const STREAM_DONT_INHIBIT_AUTO_SUSPEND = ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND, -+ const STREAM_START_UNMUTED = ffi::PA_STREAM_START_UNMUTED, -+ const STREAM_FAIL_ON_SUSPEND = ffi::PA_STREAM_FAIL_ON_SUSPEND, -+ const STREAM_RELATIVE_VOLUME = ffi::PA_STREAM_RELATIVE_VOLUME, -+ const STREAM_PASSTHROUGH = ffi::PA_STREAM_PASSTHROUGH, -+ } -+} -+ -+impl StreamFlags { -+ pub fn try_from(x: ffi::pa_stream_flags_t) -> Option { -+ if (x & -+ !(ffi::PA_STREAM_NOFLAGS | ffi::PA_STREAM_START_CORKED | ffi::PA_STREAM_INTERPOLATE_TIMING | -+ ffi::PA_STREAM_NOT_MONOTONIC | ffi::PA_STREAM_AUTO_TIMING_UPDATE | -+ ffi::PA_STREAM_NO_REMAP_CHANNELS | -+ ffi::PA_STREAM_NO_REMIX_CHANNELS | ffi::PA_STREAM_FIX_FORMAT | ffi::PA_STREAM_FIX_RATE | -+ ffi::PA_STREAM_FIX_CHANNELS | -+ ffi::PA_STREAM_DONT_MOVE | ffi::PA_STREAM_VARIABLE_RATE | ffi::PA_STREAM_PEAK_DETECT | -+ ffi::PA_STREAM_START_MUTED | ffi::PA_STREAM_ADJUST_LATENCY | -+ ffi::PA_STREAM_EARLY_REQUESTS | -+ ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND | -+ ffi::PA_STREAM_START_UNMUTED | ffi::PA_STREAM_FAIL_ON_SUSPEND | -+ ffi::PA_STREAM_RELATIVE_VOLUME | ffi::PA_STREAM_PASSTHROUGH)) == 0 { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for StreamFlags { -+ fn into(self) -> ffi::pa_stream_flags_t { -+ self.bits() as ffi::pa_stream_flags_t -+ } -+} -+ -+bitflags!{ -+ pub flags SubscriptionMask : u32 { -+ const SUBSCRIPTION_MASK_SINK = ffi::PA_SUBSCRIPTION_MASK_SINK, -+ const SUBSCRIPTION_MASK_SOURCE = ffi::PA_SUBSCRIPTION_MASK_SOURCE, -+ const SUBSCRIPTION_MASK_SINK_INPUT = ffi::PA_SUBSCRIPTION_MASK_SINK_INPUT, -+ const SUBSCRIPTION_MASK_SOURCE_OUTPUT = ffi::PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, -+ const SUBSCRIPTION_MASK_MODULE = ffi::PA_SUBSCRIPTION_MASK_MODULE, -+ const SUBSCRIPTION_MASK_CLIENT = ffi::PA_SUBSCRIPTION_MASK_CLIENT, -+ const SUBSCRIPTION_MASK_SAMPLE_CACHE = ffi::PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, -+ const SUBSCRIPTION_MASK_SERVER = ffi::PA_SUBSCRIPTION_MASK_SERVER, -+ const SUBSCRIPTION_MASK_AUTOLOAD = ffi::PA_SUBSCRIPTION_MASK_AUTOLOAD, -+ const SUBSCRIPTION_MASK_CARD = ffi::PA_SUBSCRIPTION_MASK_CARD, -+ } -+} -+ -+impl SubscriptionMask { -+ pub fn try_from(x: ffi::pa_subscription_mask_t) -> Option { -+ if (x & !ffi::PA_SUBSCRIPTION_MASK_ALL) == 0 { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for SubscriptionMask { -+ fn into(self) -> ffi::pa_subscription_mask_t { -+ self.bits() as ffi::pa_subscription_mask_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum SubscriptionEventFacility { -+ Sink = ffi::PA_SUBSCRIPTION_EVENT_SINK, -+ Source = ffi::PA_SUBSCRIPTION_EVENT_SOURCE, -+ SinkInput = ffi::PA_SUBSCRIPTION_EVENT_SINK_INPUT, -+ SourceOutput = ffi::PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT, -+ Module = ffi::PA_SUBSCRIPTION_EVENT_MODULE, -+ Client = ffi::PA_SUBSCRIPTION_EVENT_CLIENT, -+ SampleCache = ffi::PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE, -+ Server = ffi::PA_SUBSCRIPTION_EVENT_SERVER, -+ Autoload = ffi::PA_SUBSCRIPTION_EVENT_AUTOLOAD, -+ Card = ffi::PA_SUBSCRIPTION_EVENT_CARD, -+} -+ -+#[repr(C)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum SubscriptionEventType { -+ New, -+ Change, -+ Remove, -+} -+ -+#[repr(C)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub struct SubscriptionEvent(ffi::pa_subscription_event_type_t); -+impl SubscriptionEvent { -+ pub fn try_from(x: ffi::pa_subscription_event_type_t) -> Option { -+ if (x & !(ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK | ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK)) == 0 { -+ Some(SubscriptionEvent(x)) -+ } else { -+ None -+ } -+ } -+ -+ pub fn event_facility(self) -> SubscriptionEventFacility { -+ unsafe { ::std::mem::transmute(self.0 & ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK) } -+ } -+ -+ pub fn event_type(self) -> SubscriptionEventType { -+ unsafe { ::std::mem::transmute(((self.0 & ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK) >> 4)) } -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum SeekMode { -+ Relative = ffi::PA_SEEK_RELATIVE, -+ Absolute = ffi::PA_SEEK_ABSOLUTE, -+ RelativeOnRead = ffi::PA_SEEK_RELATIVE_ON_READ, -+ RelativeEnd = ffi::PA_SEEK_RELATIVE_END, -+} -+ -+impl SeekMode { -+ pub fn try_from(x: ffi::pa_seek_mode_t) -> Option { -+ if x >= ffi::PA_SEEK_RELATIVE && x <= ffi::PA_SEEK_RELATIVE_END { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for SeekMode { -+ fn into(self) -> ffi::pa_seek_mode_t { -+ self as ffi::pa_seek_mode_t -+ } -+} -+ -+bitflags! { -+ pub flags SinkFlags: u32 { -+ const SINK_HW_VOLUME_CTRL = ffi::PA_SINK_HW_VOLUME_CTRL, -+ const SINK_LATENCY = ffi::PA_SINK_LATENCY, -+ const SINK_HARDWARE = ffi::PA_SINK_HARDWARE, -+ const SINK_NETWORK = ffi::PA_SINK_NETWORK, -+ const SINK_HW_MUTE_CTRL = ffi::PA_SINK_HW_MUTE_CTRL, -+ const SINK_DECIBEL_VOLUME = ffi::PA_SINK_DECIBEL_VOLUME, -+ const SINK_FLAT_VOLUME = ffi::PA_SINK_FLAT_VOLUME, -+ const SINK_DYNAMIC_LATENCY = ffi::PA_SINK_DYNAMIC_LATENCY, -+ const SINK_SET_FORMATS = ffi::PA_SINK_SET_FORMATS, -+ } -+} -+ -+impl SinkFlags { -+ pub fn try_from(x: ffi::pa_sink_flags_t) -> Option { -+ if (x & -+ !(ffi::PA_SOURCE_NOFLAGS | ffi::PA_SOURCE_HW_VOLUME_CTRL | ffi::PA_SOURCE_LATENCY | -+ ffi::PA_SOURCE_HARDWARE | ffi::PA_SOURCE_NETWORK | ffi::PA_SOURCE_HW_MUTE_CTRL | -+ ffi::PA_SOURCE_DECIBEL_VOLUME | -+ ffi::PA_SOURCE_DYNAMIC_LATENCY | ffi::PA_SOURCE_FLAT_VOLUME)) == 0 { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum SinkState { -+ InvalidState = ffi::PA_SINK_INVALID_STATE, -+ Running = ffi::PA_SINK_RUNNING, -+ Idle = ffi::PA_SINK_IDLE, -+ Suspended = ffi::PA_SINK_SUSPENDED, -+ Init = ffi::PA_SINK_INIT, -+ Unlinked = ffi::PA_SINK_UNLINKED, -+} -+ -+bitflags!{ -+ pub flags SourceFlags: u32 { -+ const SOURCE_FLAGS_HW_VOLUME_CTRL = ffi::PA_SOURCE_HW_VOLUME_CTRL, -+ const SOURCE_FLAGS_LATENCY = ffi::PA_SOURCE_LATENCY, -+ const SOURCE_FLAGS_HARDWARE = ffi::PA_SOURCE_HARDWARE, -+ const SOURCE_FLAGS_NETWORK = ffi::PA_SOURCE_NETWORK, -+ const SOURCE_FLAGS_HW_MUTE_CTRL = ffi::PA_SOURCE_HW_MUTE_CTRL, -+ const SOURCE_FLAGS_DECIBEL_VOLUME = ffi::PA_SOURCE_DECIBEL_VOLUME, -+ const SOURCE_FLAGS_DYNAMIC_LATENCY = ffi::PA_SOURCE_DYNAMIC_LATENCY, -+ const SOURCE_FLAGS_FLAT_VOLUME = ffi::PA_SOURCE_FLAT_VOLUME, -+ } -+} -+ -+impl Into for SourceFlags { -+ fn into(self) -> ffi::pa_source_flags_t { -+ self.bits() as ffi::pa_source_flags_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum SourceState { -+ InvalidState = ffi::PA_SOURCE_INVALID_STATE, -+ Running = ffi::PA_SOURCE_RUNNING, -+ Idle = ffi::PA_SOURCE_IDLE, -+ Suspended = ffi::PA_SOURCE_SUSPENDED, -+ Init = ffi::PA_SOURCE_INIT, -+ Unlinked = ffi::PA_SOURCE_UNLINKED, -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum PortAvailable { -+ Unknown = ffi::PA_PORT_AVAILABLE_UNKNOWN, -+ No = ffi::PA_PORT_AVAILABLE_NO, -+ Yes = ffi::PA_PORT_AVAILABLE_YES, -+} -+ -+impl PortAvailable { -+ pub fn try_from(x: ffi::pa_port_available_t) -> Option { -+ if x >= ffi::PA_PORT_AVAILABLE_UNKNOWN && x <= ffi::PA_PORT_AVAILABLE_YES { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Into for PortAvailable { -+ fn into(self) -> ffi::pa_port_available_t { -+ self as ffi::pa_port_available_t -+ } -+} -+ -+#[repr(i32)] -+#[derive(Clone, Copy, Debug, PartialEq, Eq)] -+pub enum ChannelPosition { -+ Invalid = ffi::PA_CHANNEL_POSITION_INVALID, -+ Mono = ffi::PA_CHANNEL_POSITION_MONO, -+ FrontLeft = ffi::PA_CHANNEL_POSITION_FRONT_LEFT, -+ FrontRight = ffi::PA_CHANNEL_POSITION_FRONT_RIGHT, -+ FrontCenter = ffi::PA_CHANNEL_POSITION_FRONT_CENTER, -+ RearCenter = ffi::PA_CHANNEL_POSITION_REAR_CENTER, -+ RearLeft = ffi::PA_CHANNEL_POSITION_REAR_LEFT, -+ RearRight = ffi::PA_CHANNEL_POSITION_REAR_RIGHT, -+ LowFreqEffects = ffi::PA_CHANNEL_POSITION_LFE, -+ FrontLeftOfCenter = ffi::PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, -+ FrontRightOfCenter = ffi::PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, -+ SideLeft = ffi::PA_CHANNEL_POSITION_SIDE_LEFT, -+ SideRight = ffi::PA_CHANNEL_POSITION_SIDE_RIGHT, -+ Aux0 = ffi::PA_CHANNEL_POSITION_AUX0, -+ Aux1 = ffi::PA_CHANNEL_POSITION_AUX1, -+ Aux2 = ffi::PA_CHANNEL_POSITION_AUX2, -+ Aux3 = ffi::PA_CHANNEL_POSITION_AUX3, -+ Aux4 = ffi::PA_CHANNEL_POSITION_AUX4, -+ Aux5 = ffi::PA_CHANNEL_POSITION_AUX5, -+ Aux6 = ffi::PA_CHANNEL_POSITION_AUX6, -+ Aux7 = ffi::PA_CHANNEL_POSITION_AUX7, -+ Aux8 = ffi::PA_CHANNEL_POSITION_AUX8, -+ Aux9 = ffi::PA_CHANNEL_POSITION_AUX9, -+ Aux10 = ffi::PA_CHANNEL_POSITION_AUX10, -+ Aux11 = ffi::PA_CHANNEL_POSITION_AUX11, -+ Aux12 = ffi::PA_CHANNEL_POSITION_AUX12, -+ Aux13 = ffi::PA_CHANNEL_POSITION_AUX13, -+ Aux14 = ffi::PA_CHANNEL_POSITION_AUX14, -+ Aux15 = ffi::PA_CHANNEL_POSITION_AUX15, -+ Aux16 = ffi::PA_CHANNEL_POSITION_AUX16, -+ Aux17 = ffi::PA_CHANNEL_POSITION_AUX17, -+ Aux18 = ffi::PA_CHANNEL_POSITION_AUX18, -+ Aux19 = ffi::PA_CHANNEL_POSITION_AUX19, -+ Aux20 = ffi::PA_CHANNEL_POSITION_AUX20, -+ Aux21 = ffi::PA_CHANNEL_POSITION_AUX21, -+ Aux22 = ffi::PA_CHANNEL_POSITION_AUX22, -+ Aux23 = ffi::PA_CHANNEL_POSITION_AUX23, -+ Aux24 = ffi::PA_CHANNEL_POSITION_AUX24, -+ Aux25 = ffi::PA_CHANNEL_POSITION_AUX25, -+ Aux26 = ffi::PA_CHANNEL_POSITION_AUX26, -+ Aux27 = ffi::PA_CHANNEL_POSITION_AUX27, -+ Aux28 = ffi::PA_CHANNEL_POSITION_AUX28, -+ Aux29 = ffi::PA_CHANNEL_POSITION_AUX29, -+ Aux30 = ffi::PA_CHANNEL_POSITION_AUX30, -+ Aux31 = ffi::PA_CHANNEL_POSITION_AUX31, -+ TopCenter = ffi::PA_CHANNEL_POSITION_TOP_CENTER, -+ TopFrontLeft = ffi::PA_CHANNEL_POSITION_TOP_FRONT_LEFT, -+ TopFrontRight = ffi::PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, -+ TopFrontCenter = ffi::PA_CHANNEL_POSITION_TOP_FRONT_CENTER, -+ TopRearLeft = ffi::PA_CHANNEL_POSITION_TOP_REAR_LEFT, -+ TopRearRight = ffi::PA_CHANNEL_POSITION_TOP_REAR_RIGHT, -+ TopRearCenter = ffi::PA_CHANNEL_POSITION_TOP_REAR_CENTER, -+} -+ -+impl ChannelPosition { -+ pub fn try_from(x: ffi::pa_channel_position_t) -> Option { -+ if x >= ffi::PA_CHANNEL_POSITION_INVALID && x < ffi::PA_CHANNEL_POSITION_MAX { -+ Some(unsafe { ::std::mem::transmute(x) }) -+ } else { -+ None -+ } -+ } -+} -+ -+impl Default for ChannelPosition { -+ fn default() -> Self { -+ ChannelPosition::Invalid -+ } -+} -+ -+impl Into for ChannelPosition { -+ fn into(self) -> ffi::pa_channel_position_t { -+ self as ffi::pa_channel_position_t -+ } -+} -+pub type Result = ::std::result::Result; -+ -+pub trait CVolumeExt { -+ fn set(&mut self, channels: c_uint, v: Volume); -+ fn set_balance(&mut self, map: &ChannelMap, new_balance: f32); -+} -+ -+impl CVolumeExt for CVolume { -+ fn set(&mut self, channels: c_uint, v: Volume) { -+ unsafe { -+ ffi::pa_cvolume_set(self, channels, v); -+ } -+ } -+ -+ fn set_balance(&mut self, map: &ChannelMap, new_balance: f32) { -+ unsafe { -+ ffi::pa_cvolume_set_balance(self, map, new_balance); -+ } -+ } -+} -+ -+pub trait ChannelMapExt { -+ fn init() -> ChannelMap; -+ fn can_balance(&self) -> bool; -+} -+ -+impl ChannelMapExt for ChannelMap { -+ fn init() -> ChannelMap { -+ let mut cm = ChannelMap::default(); -+ unsafe { -+ ffi::pa_channel_map_init(&mut cm); -+ } -+ cm -+ } -+ fn can_balance(&self) -> bool { -+ unsafe { ffi::pa_channel_map_can_balance(self) > 0 } -+ } -+} -+ -+pub trait ProplistExt { -+ fn proplist(&self) -> Proplist; -+} -+ -+impl ProplistExt for SinkInfo { -+ fn proplist(&self) -> Proplist { -+ unsafe { proplist::from_raw_ptr(self.proplist) } -+ } -+} -+ -+impl ProplistExt for SourceInfo { -+ fn proplist(&self) -> Proplist { -+ unsafe { proplist::from_raw_ptr(self.proplist) } -+ } -+} -+ -+pub trait SampleSpecExt { -+ fn frame_size(&self) -> usize; -+} -+ -+impl SampleSpecExt for SampleSpec { -+ fn frame_size(&self) -> usize { -+ unsafe { ffi::pa_frame_size(self) } -+ } -+} -+ -+pub trait USecExt { -+ fn to_bytes(self, spec: &SampleSpec) -> usize; -+} -+ -+impl USecExt for USec { -+ fn to_bytes(self, spec: &SampleSpec) -> usize { -+ unsafe { ffi::pa_usec_to_bytes(self, spec) } -+ } -+} -+ -+pub fn library_version() -> *const c_char { -+ unsafe { ffi::pa_get_library_version() } -+} -+ -+pub fn sw_volume_from_linear(vol: f64) -> Volume { -+ unsafe { ffi::pa_sw_volume_from_linear(vol) } -+} -+ -+pub fn rtclock_now() -> USec { -+ unsafe { ffi::pa_rtclock_now() } -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs 2017-08-04 13:37:46.385821734 +0200 -@@ -0,0 +1,58 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ffi; -+use std::mem; -+use std::os::raw::c_void; -+ -+ -+#[allow(non_camel_case_types)] -+type pa_once_cb_t = Option; -+fn wrap_once_cb(_: F) -> pa_once_cb_t -+ where F: Fn(&MainloopApi, *mut c_void) -+{ -+ assert!(mem::size_of::() == 0); -+ -+ unsafe extern "C" fn wrapped(m: *mut ffi::pa_mainloop_api, userdata: *mut c_void) -+ where F: Fn(&MainloopApi, *mut c_void) -+ { -+ let api = from_raw_ptr(m); -+ let result = mem::transmute::<_, &F>(&())(&api, userdata); -+ mem::forget(api); -+ result -+ } -+ -+ Some(wrapped::) -+} -+ -+pub struct MainloopApi(*mut ffi::pa_mainloop_api); -+ -+impl MainloopApi { -+ pub fn raw_mut(&self) -> &mut ffi::pa_mainloop_api { -+ unsafe { &mut *self.0 } -+ } -+ -+ pub fn once(&self, cb: CB, userdata: *mut c_void) -+ where CB: Fn(&MainloopApi, *mut c_void) -+ { -+ let wrapped = wrap_once_cb(cb); -+ unsafe { -+ ffi::pa_mainloop_api_once(self.raw_mut(), wrapped, userdata); -+ } -+ } -+ -+ pub fn time_free(&self, e: *mut ffi::pa_time_event) { -+ unsafe { -+ if let Some(f) = self.raw_mut().time_free { -+ f(e); -+ } -+ } -+ } -+} -+ -+pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_mainloop_api) -> MainloopApi { -+ MainloopApi(raw) -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/operation.rs 2017-08-04 13:37:46.385821734 +0200 -@@ -0,0 +1,43 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ffi; -+ -+#[derive(Debug)] -+pub struct Operation(*mut ffi::pa_operation); -+ -+impl Operation { -+ pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_operation) -> Operation { -+ Operation(raw) -+ } -+ -+ pub fn cancel(&mut self) { -+ unsafe { -+ ffi::pa_operation_cancel(self.0); -+ } -+ } -+ -+ pub fn get_state(&self) -> ffi::pa_operation_state_t { -+ unsafe { ffi::pa_operation_get_state(self.0) } -+ } -+} -+ -+impl Clone for Operation { -+ fn clone(&self) -> Self { -+ Operation(unsafe { ffi::pa_operation_ref(self.0) }) -+ } -+} -+ -+impl Drop for Operation { -+ fn drop(&mut self) { -+ unsafe { -+ ffi::pa_operation_unref(self.0); -+ } -+ } -+} -+ -+pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_operation) -> Operation { -+ Operation::from_raw_ptr(raw) -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs.cubeb-pulse-arm 2017-08-04 13:37:46.385821734 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs 2017-08-04 13:37:46.385821734 +0200 -@@ -0,0 +1,31 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ffi; -+use std::ffi::{CStr, CString}; -+ -+#[derive(Debug)] -+pub struct Proplist(*mut ffi::pa_proplist); -+ -+impl Proplist { -+ pub fn gets(&self, key: T) -> Option<&CStr> -+ where T: Into> -+ { -+ let key = match CString::new(key) { -+ Ok(k) => k, -+ _ => return None, -+ }; -+ let r = unsafe { ffi::pa_proplist_gets(self.0, key.as_ptr()) }; -+ if r.is_null() { -+ None -+ } else { -+ Some(unsafe { CStr::from_ptr(r) }) -+ } -+ } -+} -+ -+pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_proplist) -> Proplist { -+ return Proplist(raw); -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs.cubeb-pulse-arm 2017-08-04 13:37:46.386821731 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs 2017-08-04 13:37:46.386821731 +0200 -@@ -0,0 +1,367 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ::*; -+use context; -+use ffi; -+use operation; -+use std::ffi::CStr; -+use std::mem; -+use std::os::raw::{c_int, c_void}; -+use std::ptr; -+use util::*; -+ -+#[derive(Debug)] -+pub struct Stream(*mut ffi::pa_stream); -+ -+impl Stream { -+ pub fn new<'a, CM>(c: &Context, name: &::std::ffi::CStr, ss: &SampleSpec, map: CM) -> Option -+ where CM: Into> -+ { -+ let ptr = unsafe { -+ ffi::pa_stream_new(c.raw_mut(), -+ name.as_ptr(), -+ ss as *const _, -+ to_ptr(map.into())) -+ }; -+ if ptr.is_null() { -+ None -+ } else { -+ Some(Stream(ptr)) -+ } -+ } -+ -+ #[doc(hidden)] -+ pub fn raw_mut(&self) -> &mut ffi::pa_stream { -+ unsafe { &mut *self.0 } -+ } -+ -+ pub fn unref(self) { -+ unsafe { -+ ffi::pa_stream_unref(self.raw_mut()); -+ } -+ } -+ -+ pub fn get_state(&self) -> StreamState { -+ StreamState::try_from(unsafe { -+ ffi::pa_stream_get_state(self.raw_mut()) -+ }).expect("pa_stream_get_state returned invalid StreamState") -+ } -+ -+ pub fn get_context(&self) -> Option { -+ let ptr = unsafe { ffi::pa_stream_get_context(self.raw_mut()) }; -+ if ptr.is_null() { -+ return None; -+ } -+ -+ let ctx = unsafe { context::from_raw_ptr(ptr) }; -+ Some(ctx) -+ } -+ -+ pub fn get_index(&self) -> u32 { -+ unsafe { ffi::pa_stream_get_index(self.raw_mut()) } -+ } -+ -+ pub fn get_device_name<'a>(&'a self) -> Result<&'a CStr> { -+ let r = unsafe { ffi::pa_stream_get_device_name(self.raw_mut()) }; -+ if r.is_null() { -+ let err = if let Some(c) = self.get_context() { -+ c.errno() -+ } else { -+ ffi::PA_ERR_UNKNOWN -+ }; -+ return Err(ErrorCode::from_error_code(err)); -+ } -+ Ok(unsafe { CStr::from_ptr(r) }) -+ } -+ -+ pub fn is_suspended(&self) -> Result { -+ let r = unsafe { ffi::pa_stream_is_suspended(self.raw_mut()) }; -+ error_result!(r != 0, r) -+ } -+ -+ pub fn is_corked(&self) -> Result { -+ let r = unsafe { ffi::pa_stream_is_corked(self.raw_mut()) }; -+ error_result!(r != 0, r) -+ } -+ -+ pub fn connect_playback<'a, D, A, V, S>(&self, -+ dev: D, -+ attr: A, -+ flags: StreamFlags, -+ volume: V, -+ sync_stream: S) -+ -> Result<()> -+ where D: Into>, -+ A: Into>, -+ V: Into>, -+ S: Into> -+ { -+ let r = unsafe { -+ ffi::pa_stream_connect_playback(self.raw_mut(), -+ str_to_ptr(dev.into()), -+ to_ptr(attr.into()), -+ flags.into(), -+ to_ptr(volume.into()), -+ map_to_mut_ptr(sync_stream.into(), |p| p.0)) -+ }; -+ error_result!((), r) -+ } -+ -+ pub fn connect_record<'a, D, A>(&self, dev: D, attr: A, flags: StreamFlags) -> Result<()> -+ where D: Into>, -+ A: Into> -+ { -+ let r = unsafe { -+ ffi::pa_stream_connect_record(self.raw_mut(), -+ str_to_ptr(dev.into()), -+ to_ptr(attr.into()), -+ flags.into()) -+ }; -+ error_result!((), r) -+ } -+ -+ pub fn disconnect(&self) -> Result<()> { -+ let r = unsafe { ffi::pa_stream_disconnect(self.raw_mut()) }; -+ error_result!((), r) -+ } -+ -+ pub fn begin_write(&self, req_bytes: usize) -> Result<(*mut c_void, usize)> { -+ let mut data: *mut c_void = ptr::null_mut(); -+ let mut nbytes = req_bytes; -+ let r = unsafe { ffi::pa_stream_begin_write(self.raw_mut(), &mut data, &mut nbytes) }; -+ error_result!((data, nbytes), r) -+ } -+ -+ pub fn cancel_write(&self) -> Result<()> { -+ let r = unsafe { ffi::pa_stream_cancel_write(self.raw_mut()) }; -+ error_result!((), r) -+ } -+ -+ pub fn write(&self, data: *const c_void, nbytes: usize, offset: i64, seek: SeekMode) -> Result<()> { -+ let r = unsafe { ffi::pa_stream_write(self.raw_mut(), data, nbytes, None, offset, seek.into()) }; -+ error_result!((), r) -+ } -+ -+ pub unsafe fn peek(&self, data: *mut *const c_void, length: *mut usize) -> Result<()> { -+ let r = ffi::pa_stream_peek(self.raw_mut(), data, length); -+ error_result!((), r) -+ } -+ -+ pub fn drop(&self) -> Result<()> { -+ let r = unsafe { ffi::pa_stream_drop(self.raw_mut()) }; -+ error_result!((), r) -+ } -+ -+ pub fn writable_size(&self) -> Result { -+ let r = unsafe { ffi::pa_stream_writable_size(self.raw_mut()) }; -+ if r == ::std::usize::MAX { -+ let err = if let Some(c) = self.get_context() { -+ c.errno() -+ } else { -+ ffi::PA_ERR_UNKNOWN -+ }; -+ return Err(ErrorCode::from_error_code(err)); -+ } -+ Ok(r) -+ } -+ -+ pub fn readable_size(&self) -> Result { -+ let r = unsafe { ffi::pa_stream_readable_size(self.raw_mut()) }; -+ if r == ::std::usize::MAX { -+ let err = if let Some(c) = self.get_context() { -+ c.errno() -+ } else { -+ ffi::PA_ERR_UNKNOWN -+ }; -+ return Err(ErrorCode::from_error_code(err)); -+ } -+ Ok(r) -+ } -+ -+ pub fn update_timing_info(&self, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Stream, i32, *mut c_void) -+ { -+ debug_assert_eq!(mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void) -+ where F: Fn(&Stream, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let mut stm = stream::from_raw_ptr(s); -+ let result = uninitialized::()(&mut stm, success, userdata); -+ forget(stm); -+ -+ result -+ } -+ -+ let r = unsafe { ffi::pa_stream_update_timing_info(self.raw_mut(), Some(wrapped::), userdata) }; -+ if r.is_null() { -+ let err = if let Some(c) = self.get_context() { -+ c.errno() -+ } else { -+ ffi::PA_ERR_UNKNOWN -+ }; -+ return Err(ErrorCode::from_error_code(err)); -+ } -+ Ok(unsafe { operation::from_raw_ptr(r) }) -+ } -+ -+ pub fn clear_state_callback(&self) { -+ unsafe { -+ ffi::pa_stream_set_state_callback(self.raw_mut(), None, ptr::null_mut()); -+ } -+ } -+ -+ pub fn set_state_callback(&self, _: CB, userdata: *mut c_void) -+ where CB: Fn(&Stream, *mut c_void) -+ { -+ debug_assert_eq!(mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(s: *mut ffi::pa_stream, userdata: *mut c_void) -+ where F: Fn(&Stream, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let mut stm = stream::from_raw_ptr(s); -+ let result = uninitialized::()(&mut stm, userdata); -+ forget(stm); -+ -+ result -+ } -+ -+ unsafe { -+ ffi::pa_stream_set_state_callback(self.raw_mut(), Some(wrapped::), userdata); -+ } -+ } -+ -+ pub fn clear_write_callback(&self) { -+ unsafe { -+ ffi::pa_stream_set_write_callback(self.raw_mut(), None, ptr::null_mut()); -+ } -+ } -+ -+ pub fn set_write_callback(&self, _: CB, userdata: *mut c_void) -+ where CB: Fn(&Stream, usize, *mut c_void) -+ { -+ debug_assert_eq!(mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void) -+ where F: Fn(&Stream, usize, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let mut stm = stream::from_raw_ptr(s); -+ let result = uninitialized::()(&mut stm, nbytes, userdata); -+ forget(stm); -+ -+ result -+ } -+ -+ unsafe { -+ ffi::pa_stream_set_write_callback(self.raw_mut(), Some(wrapped::), userdata); -+ } -+ } -+ -+ pub fn clear_read_callback(&self) { -+ unsafe { -+ ffi::pa_stream_set_read_callback(self.raw_mut(), None, ptr::null_mut()); -+ } -+ } -+ -+ pub fn set_read_callback(&self, _: CB, userdata: *mut c_void) -+ where CB: Fn(&Stream, usize, *mut c_void) -+ { -+ debug_assert_eq!(mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void) -+ where F: Fn(&Stream, usize, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let mut stm = stream::from_raw_ptr(s); -+ let result = uninitialized::()(&mut stm, nbytes, userdata); -+ forget(stm); -+ -+ result -+ } -+ -+ unsafe { -+ ffi::pa_stream_set_read_callback(self.raw_mut(), Some(wrapped::), userdata); -+ } -+ } -+ -+ pub fn cork(&self, b: i32, _: CB, userdata: *mut c_void) -> Result -+ where CB: Fn(&Stream, i32, *mut c_void) -+ { -+ debug_assert_eq!(mem::size_of::(), 0); -+ -+ // See: A note about `wrapped` functions -+ unsafe extern "C" fn wrapped(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void) -+ where F: Fn(&Stream, i32, *mut c_void) -+ { -+ use std::mem::{forget, uninitialized}; -+ let mut stm = stream::from_raw_ptr(s); -+ let result = uninitialized::()(&mut stm, success, userdata); -+ forget(stm); -+ -+ result -+ } -+ -+ let r = unsafe { ffi::pa_stream_cork(self.raw_mut(), b, Some(wrapped::), userdata) }; -+ if r.is_null() { -+ let err = if let Some(c) = self.get_context() { -+ c.errno() -+ } else { -+ ffi::PA_ERR_UNKNOWN -+ }; -+ return Err(ErrorCode::from_error_code(err)); -+ } -+ Ok(unsafe { operation::from_raw_ptr(r) }) -+ } -+ -+ pub fn get_time(&self) -> Result<(u64)> { -+ let mut usec: u64 = 0; -+ let r = unsafe { ffi::pa_stream_get_time(self.raw_mut(), &mut usec) }; -+ error_result!(usec, r) -+ } -+ -+ pub fn get_latency(&self) -> Result<(u64, bool)> { -+ let mut usec: u64 = 0; -+ let mut negative: i32 = 0; -+ let r = unsafe { ffi::pa_stream_get_latency(self.raw_mut(), &mut usec, &mut negative) }; -+ error_result!((usec, negative != 0), r) -+ } -+ -+ pub fn get_sample_spec(&self) -> &SampleSpec { -+ unsafe { -+ let ptr = ffi::pa_stream_get_sample_spec(self.raw_mut()); -+ debug_assert!(!ptr.is_null()); -+ &*ptr -+ } -+ } -+ -+ pub fn get_channel_map(&self) -> &ChannelMap { -+ unsafe { -+ let ptr = ffi::pa_stream_get_channel_map(self.raw_mut()); -+ debug_assert!(!ptr.is_null()); -+ &*ptr -+ } -+ } -+ -+ pub fn get_buffer_attr(&self) -> &BufferAttr { -+ unsafe { -+ let ptr = ffi::pa_stream_get_buffer_attr(self.raw_mut()); -+ debug_assert!(!ptr.is_null()); -+ &*ptr -+ } -+ } -+} -+ -+#[doc(hidden)] -+pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_stream) -> Stream { -+ Stream(ptr) -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs.cubeb-pulse-arm 2017-08-04 13:37:46.386821731 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs 2017-08-04 13:37:46.386821731 +0200 -@@ -0,0 +1,92 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use ErrorCode; -+use Result; -+use ffi; -+use mainloop_api; -+use mainloop_api::MainloopApi; -+ -+#[derive(Debug)] -+pub struct ThreadedMainloop(*mut ffi::pa_threaded_mainloop); -+ -+impl ThreadedMainloop { -+ pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_threaded_mainloop) -> Self { -+ ThreadedMainloop(raw) -+ } -+ -+ pub fn new() -> Self { -+ unsafe { ThreadedMainloop::from_raw_ptr(ffi::pa_threaded_mainloop_new()) } -+ } -+ -+ pub fn raw_mut(&self) -> &mut ffi::pa_threaded_mainloop { -+ unsafe { &mut *self.0 } -+ } -+ -+ pub fn is_null(&self) -> bool { -+ self.0.is_null() -+ } -+ -+ pub fn start(&self) -> Result<()> { -+ match unsafe { ffi::pa_threaded_mainloop_start(self.raw_mut()) } { -+ 0 => Ok(()), -+ _ => Err(ErrorCode::from_error_code(ffi::PA_ERR_UNKNOWN)), -+ } -+ } -+ -+ pub fn stop(&self) { -+ unsafe { -+ ffi::pa_threaded_mainloop_stop(self.raw_mut()); -+ } -+ } -+ -+ pub fn lock(&self) { -+ unsafe { -+ ffi::pa_threaded_mainloop_lock(self.raw_mut()); -+ } -+ } -+ -+ pub fn unlock(&self) { -+ unsafe { -+ ffi::pa_threaded_mainloop_unlock(self.raw_mut()); -+ } -+ } -+ -+ pub fn wait(&self) { -+ unsafe { -+ ffi::pa_threaded_mainloop_wait(self.raw_mut()); -+ } -+ } -+ -+ pub fn signal(&self) { -+ unsafe { -+ ffi::pa_threaded_mainloop_signal(self.raw_mut(), 0); -+ } -+ } -+ -+ pub fn get_api(&self) -> MainloopApi { -+ unsafe { mainloop_api::from_raw_ptr(ffi::pa_threaded_mainloop_get_api(self.raw_mut())) } -+ } -+ -+ pub fn in_thread(&self) -> bool { -+ unsafe { ffi::pa_threaded_mainloop_in_thread(self.raw_mut()) != 0 } -+ } -+} -+ -+impl ::std::default::Default for ThreadedMainloop { -+ fn default() -> Self { -+ ThreadedMainloop(::std::ptr::null_mut()) -+ } -+} -+ -+impl ::std::ops::Drop for ThreadedMainloop { -+ fn drop(&mut self) { -+ if !self.is_null() { -+ unsafe { -+ ffi::pa_threaded_mainloop_free(self.raw_mut()); -+ } -+ } -+ } -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs.cubeb-pulse-arm 2017-08-04 13:37:46.386821731 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs 2017-08-04 13:37:46.386821731 +0200 -@@ -0,0 +1,41 @@ -+// Copyright © 2017 Mozilla Foundation -+// -+// This program is made available under an ISC-style license. See the -+// accompanying file LICENSE for details. -+ -+use std::ffi::CStr; -+use std::os::raw::c_char; -+use std::ptr; -+ -+pub trait UnwrapCStr { -+ fn unwrap_cstr(self) -> *const c_char; -+} -+ -+impl<'a, U> UnwrapCStr for U -+ where U: Into> -+{ -+ fn unwrap_cstr(self) -> *const c_char { -+ self.into().map(|o| o.as_ptr()).unwrap_or(0 as *const _) -+ } -+} -+ -+pub fn map_to_mut_ptr *mut U>(t: Option<&mut T>, f: F) -> *mut U { -+ match t { -+ Some(x) => f(x), -+ None => ptr::null_mut(), -+ } -+} -+ -+pub fn str_to_ptr(s: Option<&CStr>) -> *const c_char { -+ match s { -+ Some(x) => x.as_ptr(), -+ None => ptr::null(), -+ } -+} -+ -+pub fn to_ptr(t: Option<&T>) -> *const T { -+ match t { -+ Some(x) => x as *const T, -+ None => ptr::null(), -+ } -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/README.md 2017-08-04 13:37:46.383821740 +0200 -@@ -3,3 +3,4 @@ - Implementation of PulseAudio backend for Cubeb written in Rust. - - [![Travis Build Status](https://travis-ci.org/djg/cubeb-pulse-rs.svg?branch=master)](https://travis-ci.org/djg/cubeb-pulse-rs) -+[![Travis Build Status](https://travis-ci.org/djg/cubeb-pulse-rs.svg?branch=dev)](https://travis-ci.org/djg/cubeb-pulse-rs) -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/README_MOZILLA 2017-08-04 13:37:46.383821740 +0200 -@@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla - - The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git - --The git commit ID used was dbcd7f96aea8d249a4b78f9a7597768c9dff22eb (2017-04-25 11:42:10 +1000) -+The git commit ID used was 64515819cdf54a16626df5dce5f5c7cb1220d53b (2017-06-19 17:41:30 +1000) -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs 2017-08-04 13:50:38.145480458 +0200 -@@ -4,67 +4,60 @@ - // accompanying file LICENSE for details. - - use backend::*; --use backend::cork_state::CorkState; - use capi::PULSE_OPS; - use cubeb; -+use pulse::{self, ProplistExt}; - use pulse_ffi::*; - use semver; - use std::default::Default; --use std::ffi::CStr; -+use std::ffi::{CStr, CString}; - use std::mem; --use std::os::raw::{c_char, c_int, c_void}; -+use std::os::raw::{c_char, c_void}; - use std::ptr; - --macro_rules! dup_str { -- ($Dst: expr, $Src: expr) => { -- if !$Dst.is_null() { -- pa_xfree($Dst as *mut _); -- } -- -- $Dst = pa_xstrdup($Src); -- } --} -- --fn pa_channel_to_cubeb_channel(channel: pa_channel_position_t) -> cubeb::Channel { -- assert_ne!(channel, PA_CHANNEL_POSITION_INVALID); -+fn pa_channel_to_cubeb_channel(channel: pulse::ChannelPosition) -> cubeb::Channel { -+ use pulse::ChannelPosition; -+ assert_ne!(channel, ChannelPosition::Invalid); - match channel { -- PA_CHANNEL_POSITION_MONO => cubeb::CHANNEL_MONO, -- PA_CHANNEL_POSITION_FRONT_LEFT => cubeb::CHANNEL_LEFT, -- PA_CHANNEL_POSITION_FRONT_RIGHT => cubeb::CHANNEL_RIGHT, -- PA_CHANNEL_POSITION_FRONT_CENTER => cubeb::CHANNEL_CENTER, -- PA_CHANNEL_POSITION_SIDE_LEFT => cubeb::CHANNEL_LS, -- PA_CHANNEL_POSITION_SIDE_RIGHT => cubeb::CHANNEL_RS, -- PA_CHANNEL_POSITION_REAR_LEFT => cubeb::CHANNEL_RLS, -- PA_CHANNEL_POSITION_REAR_CENTER => cubeb::CHANNEL_RCENTER, -- PA_CHANNEL_POSITION_REAR_RIGHT => cubeb::CHANNEL_RRS, -- PA_CHANNEL_POSITION_LFE => cubeb::CHANNEL_LFE, -+ ChannelPosition::Mono => cubeb::CHANNEL_MONO, -+ ChannelPosition::FrontLeft => cubeb::CHANNEL_LEFT, -+ ChannelPosition::FrontRight => cubeb::CHANNEL_RIGHT, -+ ChannelPosition::FrontCenter => cubeb::CHANNEL_CENTER, -+ ChannelPosition::SideLeft => cubeb::CHANNEL_LS, -+ ChannelPosition::SideRight => cubeb::CHANNEL_RS, -+ ChannelPosition::RearLeft => cubeb::CHANNEL_RLS, -+ ChannelPosition::RearCenter => cubeb::CHANNEL_RCENTER, -+ ChannelPosition::RearRight => cubeb::CHANNEL_RRS, -+ ChannelPosition::LowFreqEffects => cubeb::CHANNEL_LFE, - _ => cubeb::CHANNEL_INVALID, - } - } - --fn channel_map_to_layout(cm: &pa_channel_map) -> cubeb::ChannelLayout { -+fn channel_map_to_layout(cm: &pulse::ChannelMap) -> cubeb::ChannelLayout { -+ use pulse::ChannelPosition; - let mut cubeb_map: cubeb::ChannelMap = Default::default(); - cubeb_map.channels = cm.channels as u32; - for i in 0usize..cm.channels as usize { -- cubeb_map.map[i] = pa_channel_to_cubeb_channel(cm.map[i]); -+ cubeb_map.map[i] = pa_channel_to_cubeb_channel(ChannelPosition::try_from(cm.map[i]) -+ .unwrap_or(ChannelPosition::Invalid)); - } - unsafe { cubeb::cubeb_channel_map_to_layout(&cubeb_map) } - } - - #[derive(Debug)] - pub struct DefaultInfo { -- pub sample_spec: pa_sample_spec, -- pub channel_map: pa_channel_map, -- pub flags: pa_sink_flags_t, -+ pub sample_spec: pulse::SampleSpec, -+ pub channel_map: pulse::ChannelMap, -+ pub flags: pulse::SinkFlags, - } - - #[derive(Debug)] - pub struct Context { - pub ops: *const cubeb::Ops, -- pub mainloop: *mut pa_threaded_mainloop, -- pub context: *mut pa_context, -+ pub mainloop: pulse::ThreadedMainloop, -+ pub context: Option, - pub default_sink_info: Option, -- pub context_name: *const c_char, -+ pub context_name: Option, - pub collection_changed_callback: cubeb::DeviceCollectionChangedCallback, - pub collection_changed_user_ptr: *mut c_void, - pub error: bool, -@@ -82,7 +75,7 @@ impl Drop for Context { - - impl Context { - #[cfg(feature = "pulse-dlopen")] -- fn _new(name: *const i8) -> Result> { -+ fn _new(name: Option) -> Result> { - let libpulse = unsafe { open() }; - if libpulse.is_none() { - return Err(cubeb::ERROR); -@@ -91,12 +84,12 @@ impl Context { - let ctx = Box::new(Context { - ops: &PULSE_OPS, - libpulse: libpulse.unwrap(), -- mainloop: unsafe { pa_threaded_mainloop_new() }, -- context: 0 as *mut _, -+ mainloop: pulse::ThreadedMainloop::new(), -+ context: None, - default_sink_info: None, - context_name: name, - collection_changed_callback: None, -- collection_changed_user_ptr: 0 as *mut _, -+ collection_changed_user_ptr: ptr::null_mut(), - error: true, - version_0_9_8: false, - version_2_0_0: false, -@@ -106,15 +99,15 @@ impl Context { - } - - #[cfg(not(feature = "pulse-dlopen"))] -- fn _new(name: *const i8) -> Result> { -+ fn _new(name: Option) -> Result> { - Ok(Box::new(Context { - ops: &PULSE_OPS, -- mainloop: unsafe { pa_threaded_mainloop_new() }, -- context: 0 as *mut _, -+ mainloop: pulse::ThreadedMainloop::new(), -+ context: None, - default_sink_info: None, - context_name: name, - collection_changed_callback: None, -- collection_changed_user_ptr: 0 as *mut _, -+ collection_changed_user_ptr: ptr::null_mut(), - error: true, - version_0_9_8: false, - version_2_0_0: false, -@@ -122,53 +115,66 @@ impl Context { - } - - pub fn new(name: *const c_char) -> Result> { -+ fn server_info_cb(context: &pulse::Context, info: &pulse::ServerInfo, u: *mut c_void) { -+ fn sink_info_cb(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, u: *mut c_void) { -+ let mut ctx = unsafe { &mut *(u as *mut Context) }; -+ if eol == 0 { -+ let info = unsafe { &*i }; -+ let flags = pulse::SinkFlags::try_from(info.flags).expect("SinkInfo contains invalid flags"); -+ ctx.default_sink_info = Some(DefaultInfo { -+ sample_spec: info.sample_spec, -+ channel_map: info.channel_map, -+ flags: flags, -+ }); -+ } -+ ctx.mainloop.signal(); -+ } -+ -+ let _ = context.get_sink_info_by_name(unsafe { CStr::from_ptr(info.default_sink_name) }, -+ sink_info_cb, -+ u); -+ } -+ -+ let name = super::try_cstr_from(name).map(|s| s.to_owned()); - let mut ctx = try!(Context::_new(name)); - -- unsafe { pa_threaded_mainloop_start(ctx.mainloop) }; -+ if ctx.mainloop.start().is_err() { -+ ctx.destroy(); -+ return Err(cubeb::ERROR); -+ } - -- if ctx.pulse_context_init() != cubeb::OK { -+ if ctx.context_init() != cubeb::OK { - ctx.destroy(); - return Err(cubeb::ERROR); - } - -- unsafe { -- /* server_info_callback performs a second async query, -- * which is responsible for initializing default_sink_info -- * and signalling the mainloop to end the wait. */ -- pa_threaded_mainloop_lock(ctx.mainloop); -- let o = pa_context_get_server_info(ctx.context, -- Some(server_info_callback), -- ctx.as_mut() as *mut Context as *mut _); -- if !o.is_null() { -- ctx.operation_wait(ptr::null_mut(), o); -- pa_operation_unref(o); -+ ctx.mainloop.lock(); -+ /* server_info_callback performs a second async query, -+ * which is responsible for initializing default_sink_info -+ * and signalling the mainloop to end the wait. */ -+ let user_data: *mut c_void = ctx.as_mut() as *mut _ as *mut _; -+ if let Some(ref context) = ctx.context { -+ if let Ok(o) = context.get_server_info(server_info_cb, user_data) { -+ ctx.operation_wait(None, &o); - } -- pa_threaded_mainloop_unlock(ctx.mainloop); -- assert!(ctx.default_sink_info.is_some()); - } -+ assert!(ctx.default_sink_info.is_some()); -+ ctx.mainloop.unlock(); - - // Return the result. - Ok(ctx) - } - - pub fn destroy(&mut self) { -- if !self.context.is_null() { -- unsafe { self.pulse_context_destroy() }; -- } -- assert!(self.context.is_null()); -+ self.context_destroy(); - - if !self.mainloop.is_null() { -- unsafe { -- pa_threaded_mainloop_stop(self.mainloop); -- pa_threaded_mainloop_free(self.mainloop); -- self.mainloop = ptr::null_mut(); -- } -+ self.mainloop.stop(); - } -- assert!(self.mainloop.is_null()); - } - - pub fn new_stream(&mut self, -- stream_name: *const c_char, -+ stream_name: &CStr, - input_device: cubeb::DeviceId, - input_stream_params: Option, - output_device: cubeb::DeviceId, -@@ -178,7 +184,7 @@ impl Context { - state_callback: cubeb::StateCallback, - user_ptr: *mut c_void) - -> Result> { -- if self.error && self.pulse_context_init() != 0 { -+ if self.error && self.context_init() != 0 { - return Err(cubeb::ERROR); - } - -@@ -221,41 +227,151 @@ impl Context { - } - - pub fn enumerate_devices(&self, devtype: cubeb::DeviceType) -> Result { -- let mut user_data: PulseDevListData = Default::default(); -- user_data.context = self as *const _ as *mut _; -+ fn add_output_device(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, user_data: *mut c_void) { -+ if eol != 0 { -+ return; -+ } - -- unsafe { -- pa_threaded_mainloop_lock(self.mainloop); -+ debug_assert!(!i.is_null()); -+ debug_assert!(!user_data.is_null()); -+ -+ let mut list_data = unsafe { &mut *(user_data as *mut PulseDevListData) }; -+ let info = unsafe { &*i }; -+ -+ let group_id = match info.proplist().gets("sysfs.path") { -+ Some(p) => p.to_owned().into_raw(), -+ _ => ptr::null_mut(), -+ }; -+ -+ let vendor_name = match info.proplist().gets("device.vendor.name") { -+ Some(p) => p.to_owned().into_raw(), -+ _ => ptr::null_mut(), -+ }; -+ -+ let info_name = unsafe { CStr::from_ptr(info.name) }.to_owned(); -+ let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned(); -+ -+ let preferred = if info_name == list_data.default_sink_name { -+ cubeb::DEVICE_PREF_ALL -+ } else { -+ cubeb::DevicePref::empty() -+ }; -+ -+ let ctx = &(*list_data.context); -+ -+ let device_id = info_name.into_raw(); -+ let friendly_name = info_description.into_raw(); -+ let devinfo = cubeb::DeviceInfo { -+ device_id: device_id, -+ devid: device_id as cubeb::DeviceId, -+ friendly_name: friendly_name, -+ group_id: group_id, -+ vendor_name: vendor_name, -+ devtype: cubeb::DEVICE_TYPE_OUTPUT, -+ state: ctx.state_from_port(info.active_port), -+ preferred: preferred, -+ format: cubeb::DeviceFmt::all(), -+ default_format: pulse_format_to_cubeb_format(info.sample_spec.format), -+ max_channels: info.channel_map.channels as u32, -+ min_rate: 1, -+ max_rate: PA_RATE_MAX, -+ default_rate: info.sample_spec.rate, -+ latency_lo: 0, -+ latency_hi: 0, -+ }; -+ list_data.devinfo.push(devinfo); -+ -+ ctx.mainloop.signal(); -+ } -+ -+ fn add_input_device(_: &pulse::Context, i: *const pulse::SourceInfo, eol: i32, user_data: *mut c_void) { -+ if eol != 0 { -+ return; -+ } -+ -+ debug_assert!(!user_data.is_null()); -+ debug_assert!(!i.is_null()); -+ -+ let mut list_data = unsafe { &mut *(user_data as *mut PulseDevListData) }; -+ let info = unsafe { &*i }; -+ -+ let group_id = match info.proplist().gets("sysfs.path") { -+ Some(p) => p.to_owned().into_raw(), -+ _ => ptr::null_mut(), -+ }; -+ -+ let vendor_name = match info.proplist().gets("device.vendor.name") { -+ Some(p) => p.to_owned().into_raw(), -+ _ => ptr::null_mut(), -+ }; - -- let o = pa_context_get_server_info(self.context, -- Some(pulse_server_info_cb), -- &mut user_data as *mut _ as *mut _); -- if !o.is_null() { -- self.operation_wait(ptr::null_mut(), o); -- pa_operation_unref(o); -+ let info_name = unsafe { CStr::from_ptr(info.name) }.to_owned(); -+ let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned(); -+ -+ let preferred = if info_name == list_data.default_source_name { -+ cubeb::DEVICE_PREF_ALL -+ } else { -+ cubeb::DevicePref::empty() -+ }; -+ -+ let ctx = &(*list_data.context); -+ let device_id = info_name.into_raw(); -+ let friendly_name = info_description.into_raw(); -+ let devinfo = cubeb::DeviceInfo { -+ device_id: device_id, -+ devid: device_id as cubeb::DeviceId, -+ friendly_name: friendly_name, -+ group_id: group_id, -+ vendor_name: vendor_name, -+ devtype: cubeb::DEVICE_TYPE_INPUT, -+ state: ctx.state_from_port(info.active_port), -+ preferred: preferred, -+ format: cubeb::DeviceFmt::all(), -+ default_format: pulse_format_to_cubeb_format(info.sample_spec.format), -+ max_channels: info.channel_map.channels as u32, -+ min_rate: 1, -+ max_rate: PA_RATE_MAX, -+ default_rate: info.sample_spec.rate, -+ latency_lo: 0, -+ latency_hi: 0, -+ }; -+ -+ list_data.devinfo.push(devinfo); -+ -+ ctx.mainloop.signal(); -+ } -+ -+ fn default_device_names(_: &pulse::Context, info: &pulse::ServerInfo, user_data: *mut c_void) { -+ let list_data = unsafe { &mut *(user_data as *mut PulseDevListData) }; -+ -+ list_data.default_sink_name = unsafe { CStr::from_ptr(info.default_sink_name) }.to_owned(); -+ list_data.default_source_name = unsafe { CStr::from_ptr(info.default_source_name) }.to_owned(); -+ -+ (*list_data.context).mainloop.signal(); -+ } -+ -+ let mut user_data = PulseDevListData::new(self); -+ -+ if let Some(ref context) = self.context { -+ self.mainloop.lock(); -+ -+ if let Ok(o) = context.get_server_info(default_device_names, &mut user_data as *mut _ as *mut _) { -+ self.operation_wait(None, &o); - } - - if devtype == cubeb::DEVICE_TYPE_OUTPUT { -- let o = pa_context_get_sink_info_list(self.context, -- Some(pulse_sink_info_cb), -- &mut user_data as *mut _ as *mut _); -- if !o.is_null() { -- self.operation_wait(ptr::null_mut(), o); -- pa_operation_unref(o); -+ if let Ok(o) = context.get_sink_info_list(add_output_device, &mut user_data as *mut _ as *mut _) { -+ self.operation_wait(None, &o); - } - } - - if devtype == cubeb::DEVICE_TYPE_INPUT { -- let o = pa_context_get_source_info_list(self.context, -- Some(pulse_source_info_cb), -- &mut user_data as *mut _ as *mut _); -- if !o.is_null() { -- self.operation_wait(ptr::null_mut(), o); -- pa_operation_unref(o); -+ if let Ok(o) = context.get_source_info_list(add_input_device, &mut user_data as *mut _ as *mut _) { -+ self.operation_wait(None, &o); - } - } - -- pa_threaded_mainloop_unlock(self.mainloop); -+ self.mainloop.unlock(); - } - - // Extract the array of cubeb_device_info from -@@ -282,16 +398,16 @@ impl Context { - coll.count); - for dev in devices.iter_mut() { - if !dev.device_id.is_null() { -- pa_xfree(dev.device_id as *mut _); -+ let _ = CString::from_raw(dev.device_id as *mut _); - } - if !dev.group_id.is_null() { -- pa_xfree(dev.group_id as *mut _); -+ let _ = CString::from_raw(dev.group_id as *mut _); - } - if !dev.vendor_name.is_null() { -- pa_xfree(dev.vendor_name as *mut _); -+ let _ = CString::from_raw(dev.vendor_name as *mut _); - } - if !dev.friendly_name.is_null() { -- pa_xfree(dev.friendly_name as *mut _); -+ let _ = CString::from_raw(dev.friendly_name as *mut _); - } - } - } -@@ -302,115 +418,125 @@ impl Context { - cb: cubeb::DeviceCollectionChangedCallback, - user_ptr: *mut c_void) - -> i32 { -- unsafe extern "C" fn subscribe_success(_: *mut pa_context, success: i32, user_data: *mut c_void) { -- let ctx = &*(user_data as *mut Context); -+ fn update_collection(_: &pulse::Context, event: pulse::SubscriptionEvent, index: u32, user_data: *mut c_void) { -+ let mut ctx = unsafe { &mut *(user_data as *mut Context) }; -+ -+ let (f, t) = (event.event_facility(), event.event_type()); -+ match f { -+ pulse::SubscriptionEventFacility::Source | -+ pulse::SubscriptionEventFacility::Sink => { -+ match t { -+ pulse::SubscriptionEventType::Remove | -+ pulse::SubscriptionEventType::New => { -+ if cubeb::log_enabled() { -+ let op = if t == pulse::SubscriptionEventType::New { -+ "Adding" -+ } else { -+ "Removing" -+ }; -+ let dev = if f == pulse::SubscriptionEventFacility::Sink { -+ "sink" -+ } else { -+ "source " -+ }; -+ log!("{} {} index {}", op, dev, index); -+ -+ unsafe { -+ ctx.collection_changed_callback.unwrap()(ctx as *mut _ as *mut _, -+ ctx.collection_changed_user_ptr); -+ } -+ } -+ }, -+ _ => {}, -+ } -+ }, -+ _ => {}, -+ } -+ } -+ -+ fn success(_: &pulse::Context, success: i32, user_data: *mut c_void) { -+ let ctx = unsafe { &*(user_data as *mut Context) }; - debug_assert_ne!(success, 0); -- pa_threaded_mainloop_signal(ctx.mainloop, 0); -+ ctx.mainloop.signal(); - } - - self.collection_changed_callback = cb; - self.collection_changed_user_ptr = user_ptr; - -- unsafe { -- pa_threaded_mainloop_lock(self.mainloop); -+ let user_data: *mut c_void = self as *mut _ as *mut _; -+ if let Some(ref context) = self.context { -+ self.mainloop.lock(); - -- let mut mask: pa_subscription_mask_t = PA_SUBSCRIPTION_MASK_NULL; -+ let mut mask = pulse::SubscriptionMask::empty(); - if self.collection_changed_callback.is_none() { - // Unregister subscription -- pa_context_set_subscribe_callback(self.context, None, ptr::null_mut()); -+ context.clear_subscribe_callback(); - } else { -- pa_context_set_subscribe_callback(self.context, -- Some(pulse_subscribe_callback), -- self as *mut _ as *mut _); -- if devtype == cubeb::DEVICE_TYPE_INPUT { -- mask |= PA_SUBSCRIPTION_MASK_SOURCE -+ context.set_subscribe_callback(update_collection, user_data); -+ if devtype.contains(cubeb::DEVICE_TYPE_INPUT) { -+ mask |= pulse::SUBSCRIPTION_MASK_SOURCE - }; -- if devtype == cubeb::DEVICE_TYPE_OUTPUT { -- mask |= PA_SUBSCRIPTION_MASK_SOURCE -+ if devtype.contains(cubeb::DEVICE_TYPE_OUTPUT) { -+ mask = pulse::SUBSCRIPTION_MASK_SINK - }; - } - -- let o = pa_context_subscribe(self.context, -- mask, -- Some(subscribe_success), -- self as *const _ as *mut _); -- if o.is_null() { -+ if let Ok(o) = context.subscribe(mask, success, self as *const _ as *mut _) { -+ self.operation_wait(None, &o); -+ } else { - log!("Context subscribe failed"); - return cubeb::ERROR; - } -- self.operation_wait(ptr::null_mut(), o); -- pa_operation_unref(o); - -- pa_threaded_mainloop_unlock(self.mainloop); -+ self.mainloop.unlock(); - } - - cubeb::OK - } - -- // -- -- pub fn pulse_stream_cork(&self, stream: *mut pa_stream, state: CorkState) { -- unsafe extern "C" fn cork_success(_: *mut pa_stream, _: i32, u: *mut c_void) { -- let mainloop = u as *mut pa_threaded_mainloop; -- pa_threaded_mainloop_signal(mainloop, 0); -+ pub fn context_init(&mut self) -> i32 { -+ fn error_state(c: &pulse::Context, u: *mut c_void) { -+ let mut ctx = unsafe { &mut *(u as *mut Context) }; -+ if !c.get_state().is_good() { -+ ctx.error = true; -+ } -+ ctx.mainloop.signal(); - } - -- if stream.is_null() { -- return; -+ if self.context.is_some() { -+ debug_assert!(self.error); -+ self.context_destroy(); - } - -- let o = unsafe { -- pa_stream_cork(stream, -- state.is_cork() as i32, -- Some(cork_success), -- self.mainloop as *mut _) -+ self.context = { -+ let name = match self.context_name.as_ref() { -+ Some(s) => Some(s.as_ref()), -+ None => None, -+ }; -+ pulse::Context::new(&self.mainloop.get_api(), name) - }; - -- if !o.is_null() { -- self.operation_wait(stream, o); -- unsafe { pa_operation_unref(o) }; -+ let context_ptr: *mut c_void = self as *mut _ as *mut _; -+ if self.context.is_none() { -+ return cubeb::ERROR; - } -- } - -- pub fn pulse_context_init(&mut self) -> i32 { -- unsafe extern "C" fn error_state(c: *mut pa_context, u: *mut c_void) { -- let mut ctx = &mut *(u as *mut Context); -- if !PA_CONTEXT_IS_GOOD(pa_context_get_state(c)) { -- ctx.error = true; -- } -- pa_threaded_mainloop_signal(ctx.mainloop, 0); -+ self.mainloop.lock(); -+ if let Some(ref context) = self.context { -+ context.set_state_callback(error_state, context_ptr); -+ let _ = context.connect(None, pulse::ContextFlags::empty(), ptr::null()); - } - -- if !self.context.is_null() { -- debug_assert!(self.error); -- unsafe { self.pulse_context_destroy() }; -+ if !self.wait_until_context_ready() { -+ self.mainloop.unlock(); -+ self.context_destroy(); -+ return cubeb::ERROR; - } - -- unsafe { -- self.context = pa_context_new(pa_threaded_mainloop_get_api(self.mainloop), -- self.context_name); -- -- if self.context.is_null() { -- return cubeb::ERROR; -- } -- -- pa_context_set_state_callback(self.context, Some(error_state), self as *mut _ as *mut _); -- -- pa_threaded_mainloop_lock(self.mainloop); -- pa_context_connect(self.context, ptr::null(), 0, ptr::null()); -- -- if !self.wait_until_context_ready() { -- pa_threaded_mainloop_unlock(self.mainloop); -- self.pulse_context_destroy(); -- assert!(self.context.is_null()); -- return cubeb::ERROR; -- } -+ self.mainloop.unlock(); - -- pa_threaded_mainloop_unlock(self.mainloop); -- } -- -- let version_str = unsafe { CStr::from_ptr(pa_get_library_version()) }; -- if let Ok(version) = semver::Version::parse(version_str.to_string_lossy().as_ref()) { -+ let version_str = unsafe { CStr::from_ptr(pulse::library_version()) }; -+ if let Ok(version) = semver::Version::parse(&version_str.to_string_lossy()) { - self.version_0_9_8 = version >= semver::Version::parse("0.9.8").expect("Failed to parse version"); - self.version_2_0_0 = version >= semver::Version::parse("2.0.0").expect("Failed to parse version"); - } -@@ -420,34 +546,42 @@ impl Context { - cubeb::OK - } - -- unsafe fn pulse_context_destroy(&mut self) { -- unsafe extern "C" fn drain_complete(_c: *mut pa_context, u: *mut c_void) { -- let mainloop = u as *mut pa_threaded_mainloop; -- pa_threaded_mainloop_signal(mainloop, 0); -- } -- -- pa_threaded_mainloop_lock(self.mainloop); -- let o = pa_context_drain(self.context, Some(drain_complete), self.mainloop as *mut _); -- if !o.is_null() { -- self.operation_wait(ptr::null_mut(), o); -- pa_operation_unref(o); -- } -- pa_context_set_state_callback(self.context, None, ptr::null_mut()); -- pa_context_disconnect(self.context); -- pa_context_unref(self.context); -- self.context = ptr::null_mut(); -- pa_threaded_mainloop_unlock(self.mainloop); -+ fn context_destroy(&mut self) { -+ fn drain_complete(_: &pulse::Context, u: *mut c_void) { -+ let ctx = unsafe { &*(u as *mut Context) }; -+ ctx.mainloop.signal(); -+ } -+ -+ let context_ptr: *mut c_void = self as *mut _ as *mut _; -+ match self.context.take() { -+ Some(ctx) => { -+ self.mainloop.lock(); -+ if let Ok(o) = ctx.drain(drain_complete, context_ptr) { -+ self.operation_wait(None, &o); -+ } -+ ctx.clear_state_callback(); -+ ctx.disconnect(); -+ ctx.unref(); -+ self.mainloop.unlock(); -+ }, -+ _ => {}, -+ } - } - -- pub fn operation_wait(&self, stream: *mut pa_stream, o: *mut pa_operation) -> bool { -- unsafe { -- while pa_operation_get_state(o) == PA_OPERATION_RUNNING { -- pa_threaded_mainloop_wait(self.mainloop); -- if !PA_CONTEXT_IS_GOOD(pa_context_get_state(self.context)) { -+ pub fn operation_wait<'a, S>(&self, s: S, o: &pulse::Operation) -> bool -+ where S: Into> -+ { -+ let stream = s.into(); -+ while o.get_state() == PA_OPERATION_RUNNING { -+ self.mainloop.wait(); -+ if let Some(ref context) = self.context { -+ if !context.get_state().is_good() { - return false; - } -+ } - -- if !stream.is_null() && !PA_STREAM_IS_GOOD(pa_stream_get_state(stream)) { -+ if let Some(stm) = stream { -+ if !stm.get_state().is_good() { - return false; - } - } -@@ -457,36 +591,23 @@ impl Context { - } - - pub fn wait_until_context_ready(&self) -> bool { -- loop { -- let state = unsafe { pa_context_get_state(self.context) }; -- if !PA_CONTEXT_IS_GOOD(state) { -- return false; -- } -- if state == PA_CONTEXT_READY { -- break; -- } -- unsafe { -- pa_threaded_mainloop_wait(self.mainloop); -+ if let Some(ref context) = self.context { -+ loop { -+ let state = context.get_state(); -+ if !state.is_good() { -+ return false; -+ } -+ if state == pulse::ContextState::Ready { -+ break; -+ } -+ self.mainloop.wait(); - } - } - - true - } - -- fn state_from_sink_port(&self, i: *const pa_port_info) -> cubeb::DeviceState { -- if !i.is_null() { -- let info = unsafe { *i }; -- if self.version_2_0_0 && info.available == PA_PORT_AVAILABLE_NO { -- cubeb::DeviceState::Unplugged -- } else { -- cubeb::DeviceState::Enabled -- } -- } else { -- cubeb::DeviceState::Enabled -- } -- } -- -- fn state_from_source_port(&self, i: *mut pa_port_info) -> cubeb::DeviceState { -+ fn state_from_port(&self, i: *const pa_port_info) -> cubeb::DeviceState { - if !i.is_null() { - let info = unsafe { *i }; - if self.version_2_0_0 && info.available == PA_PORT_AVAILABLE_NO { -@@ -500,62 +621,30 @@ impl Context { - } - } - --// Callbacks --unsafe extern "C" fn server_info_callback(context: *mut pa_context, info: *const pa_server_info, u: *mut c_void) { -- unsafe extern "C" fn sink_info_callback(_context: *mut pa_context, -- info: *const pa_sink_info, -- eol: i32, -- u: *mut c_void) { -- let mut ctx = &mut *(u as *mut Context); -- if eol == 0 { -- let info = *info; -- ctx.default_sink_info = Some(DefaultInfo { -- sample_spec: info.sample_spec, -- channel_map: info.channel_map, -- flags: info.flags, -- }); -- } -- pa_threaded_mainloop_signal(ctx.mainloop, 0); -- } -- -- let o = pa_context_get_sink_info_by_name(context, -- (*info).default_sink_name, -- Some(sink_info_callback), -- u); -- if !o.is_null() { -- pa_operation_unref(o); -- } --} -- --struct PulseDevListData { -- default_sink_name: *mut c_char, -- default_source_name: *mut c_char, -+struct PulseDevListData<'a> { -+ default_sink_name: CString, -+ default_source_name: CString, - devinfo: Vec, -- context: *mut Context, -+ context: &'a Context, - } - --impl Drop for PulseDevListData { -- fn drop(&mut self) { -- if !self.default_sink_name.is_null() { -- unsafe { -- pa_xfree(self.default_sink_name as *mut _); -- } -- } -- if !self.default_source_name.is_null() { -- unsafe { -- pa_xfree(self.default_source_name as *mut _); -- } -+impl<'a> PulseDevListData<'a> { -+ pub fn new<'b>(context: &'b Context) -> Self -+ where 'b: 'a -+ { -+ PulseDevListData { -+ default_sink_name: CString::default(), -+ default_source_name: CString::default(), -+ devinfo: Vec::new(), -+ context: context, - } - } - } - --impl Default for PulseDevListData { -- fn default() -> Self { -- PulseDevListData { -- default_sink_name: ptr::null_mut(), -- default_source_name: ptr::null_mut(), -- devinfo: Vec::new(), -- context: ptr::null_mut(), -+impl<'a> Drop for PulseDevListData<'a> { -+ fn drop(&mut self) { -+ for elem in &mut self.devinfo { -+ let _ = unsafe { Box::from_raw(elem) }; - } - } - } -@@ -566,192 +655,7 @@ fn pulse_format_to_cubeb_format(format: - PA_SAMPLE_S16BE => cubeb::DEVICE_FMT_S16BE, - PA_SAMPLE_FLOAT32LE => cubeb::DEVICE_FMT_F32LE, - PA_SAMPLE_FLOAT32BE => cubeb::DEVICE_FMT_F32BE, -- _ => { -- panic!("Invalid format"); -- }, -+ // Unsupported format, return F32NE -+ _ => cubeb::CUBEB_FMT_F32NE, - } - } -- --unsafe extern "C" fn pulse_sink_info_cb(_context: *mut pa_context, -- i: *const pa_sink_info, -- eol: i32, -- user_data: *mut c_void) { -- if eol != 0 || i.is_null() { -- return; -- } -- -- debug_assert!(!user_data.is_null()); -- -- let info = *i; -- let mut list_data = &mut *(user_data as *mut PulseDevListData); -- -- let device_id = pa_xstrdup(info.name); -- -- let group_id = { -- let prop = pa_proplist_gets(info.proplist, b"sysfs.path\0".as_ptr() as *const c_char); -- if !prop.is_null() { -- pa_xstrdup(prop) -- } else { -- ptr::null_mut() -- } -- }; -- -- let vendor_name = { -- let prop = pa_proplist_gets(info.proplist, -- b"device.vendor.name\0".as_ptr() as *const c_char); -- if !prop.is_null() { -- pa_xstrdup(prop) -- } else { -- ptr::null_mut() -- } -- }; -- -- let preferred = if strcmp(info.name, list_data.default_sink_name) == 0 { -- cubeb::DEVICE_PREF_ALL -- } else { -- cubeb::DevicePref::empty() -- }; -- -- let ctx = &(*list_data.context); -- -- let devinfo = cubeb::DeviceInfo { -- device_id: device_id, -- devid: device_id as cubeb::DeviceId, -- friendly_name: pa_xstrdup(info.description), -- group_id: group_id, -- vendor_name: vendor_name, -- devtype: cubeb::DEVICE_TYPE_OUTPUT, -- state: ctx.state_from_sink_port(info.active_port), -- preferred: preferred, -- format: cubeb::DeviceFmt::all(), -- default_format: pulse_format_to_cubeb_format(info.sample_spec.format), -- max_channels: info.channel_map.channels as u32, -- min_rate: 1, -- max_rate: PA_RATE_MAX, -- default_rate: info.sample_spec.rate, -- latency_lo: 0, -- latency_hi: 0, -- }; -- list_data.devinfo.push(devinfo); -- -- pa_threaded_mainloop_signal(ctx.mainloop, 0); --} -- --unsafe extern "C" fn pulse_source_info_cb(_context: *mut pa_context, -- i: *const pa_source_info, -- eol: i32, -- user_data: *mut c_void) { -- if eol != 0 || i.is_null() { -- return; -- } -- -- debug_assert!(!user_data.is_null()); -- -- let info = *i; -- let mut list_data = &mut *(user_data as *mut PulseDevListData); -- -- let device_id = pa_xstrdup(info.name); -- -- let group_id = { -- let prop = pa_proplist_gets(info.proplist, b"sysfs.path\0".as_ptr() as *mut c_char); -- if !prop.is_null() { -- pa_xstrdup(prop) -- } else { -- ptr::null_mut() -- } -- }; -- -- let vendor_name = { -- let prop = pa_proplist_gets(info.proplist, -- b"device.vendor.name\0".as_ptr() as *mut c_char); -- if !prop.is_null() { -- pa_xstrdup(prop) -- } else { -- ptr::null_mut() -- } -- }; -- -- let preferred = if strcmp(info.name, list_data.default_source_name) == 0 { -- cubeb::DEVICE_PREF_ALL -- } else { -- cubeb::DevicePref::empty() -- }; -- -- let ctx = &(*list_data.context); -- -- let devinfo = cubeb::DeviceInfo { -- device_id: device_id, -- devid: device_id as cubeb::DeviceId, -- friendly_name: pa_xstrdup(info.description), -- group_id: group_id, -- vendor_name: vendor_name, -- devtype: cubeb::DEVICE_TYPE_INPUT, -- state: ctx.state_from_source_port(info.active_port), -- preferred: preferred, -- format: cubeb::DeviceFmt::all(), -- default_format: pulse_format_to_cubeb_format(info.sample_spec.format), -- max_channels: info.channel_map.channels as u32, -- min_rate: 1, -- max_rate: PA_RATE_MAX, -- default_rate: info.sample_spec.rate, -- latency_lo: 0, -- latency_hi: 0, -- }; -- -- list_data.devinfo.push(devinfo); -- -- pa_threaded_mainloop_signal(ctx.mainloop, 0); --} -- --unsafe extern "C" fn pulse_server_info_cb(_context: *mut pa_context, -- i: *const pa_server_info, -- user_data: *mut c_void) { -- assert!(!i.is_null()); -- let info = *i; -- let list_data = &mut *(user_data as *mut PulseDevListData); -- -- dup_str!(list_data.default_sink_name, info.default_sink_name); -- dup_str!(list_data.default_source_name, info.default_source_name); -- -- pa_threaded_mainloop_signal((*list_data.context).mainloop, 0); --} -- --unsafe extern "C" fn pulse_subscribe_callback(_ctx: *mut pa_context, -- t: pa_subscription_event_type_t, -- index: u32, -- user_data: *mut c_void) { -- let mut ctx = &mut *(user_data as *mut Context); -- -- match t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK { -- PA_SUBSCRIPTION_EVENT_SOURCE | -- PA_SUBSCRIPTION_EVENT_SINK => { -- -- if cubeb::log_enabled() { -- if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE && -- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE { -- log!("Removing sink index %d", index); -- } else if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE && -- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW { -- log!("Adding sink index %d", index); -- } -- if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK && -- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE { -- log!("Removing source index %d", index); -- } else if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK && -- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW { -- log!("Adding source index %d", index); -- } -- } -- -- if (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE || -- (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW { -- ctx.collection_changed_callback.unwrap()(ctx as *mut _ as *mut _, ctx.collection_changed_user_ptr); -- } -- }, -- _ => {}, -- } --} -- --extern "C" { -- pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; --} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs 2017-08-04 13:37:46.386821731 +0200 -@@ -7,8 +7,16 @@ mod context; - mod cork_state; - mod stream; - -+use std::os::raw::c_char; -+use std::ffi::CStr; -+ - pub type Result = ::std::result::Result; - - pub use self::context::Context; - pub use self::stream::Device; - pub use self::stream::Stream; -+ -+// helper to convert *const c_char to Option -+fn try_cstr_from<'str>(s: *const c_char) -> Option<&'str CStr> { -+ if s.is_null() { None } else { Some(unsafe { CStr::from_ptr(s) }) } -+} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs 2017-08-04 13:37:46.387821728 +0200 -@@ -6,8 +6,10 @@ - use backend::*; - use backend::cork_state::CorkState; - use cubeb; -+use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, USecExt}; - use pulse_ffi::*; --use std::os::raw::{c_char, c_long, c_void}; -+use std::ffi::{CStr, CString}; -+use std::os::raw::{c_long, c_void}; - use std::ptr; - - const PULSE_NO_GAIN: f32 = -1.0; -@@ -36,15 +38,12 @@ fn cubeb_channel_to_pa_channel(channel: - MAP[idx as usize] - } - --fn layout_to_channel_map(layout: cubeb::ChannelLayout) -> pa_channel_map { -+fn layout_to_channel_map(layout: cubeb::ChannelLayout) -> pulse::ChannelMap { - assert_ne!(layout, cubeb::LAYOUT_UNDEFINED); - - let order = cubeb::mixer::channel_index_to_order(layout); - -- let mut cm: pa_channel_map = Default::default(); -- unsafe { -- pa_channel_map_init(&mut cm); -- } -+ let mut cm = pulse::ChannelMap::init(); - cm.channels = order.len() as u8; - for (s, d) in order.iter().zip(cm.map.iter_mut()) { - *d = cubeb_channel_to_pa_channel(*s); -@@ -57,24 +56,27 @@ pub struct Device(cubeb::Device); - impl Drop for Device { - fn drop(&mut self) { - unsafe { -- pa_xfree(self.0.input_name as *mut _); -- pa_xfree(self.0.output_name as *mut _); -+ if !self.0.input_name.is_null() { -+ let _ = CString::from_raw(self.0.input_name); -+ } -+ if !self.0.output_name.is_null() { -+ let _ = CString::from_raw(self.0.output_name); -+ } - } - } - } - -- - #[derive(Debug)] - pub struct Stream<'ctx> { - context: &'ctx Context, -- output_stream: *mut pa_stream, -- input_stream: *mut pa_stream, -+ output_stream: Option, -+ input_stream: Option, - data_callback: cubeb::DataCallback, - state_callback: cubeb::StateCallback, - user_ptr: *mut c_void, - drain_timer: *mut pa_time_event, -- output_sample_spec: pa_sample_spec, -- input_sample_spec: pa_sample_spec, -+ output_sample_spec: pulse::SampleSpec, -+ input_sample_spec: pulse::SampleSpec, - shutdown: bool, - volume: f32, - state: cubeb::State, -@@ -88,7 +90,7 @@ impl<'ctx> Drop for Stream<'ctx> { - - impl<'ctx> Stream<'ctx> { - pub fn new(context: &'ctx Context, -- stream_name: *const c_char, -+ stream_name: &CStr, - input_device: cubeb::DeviceId, - input_stream_params: Option, - output_device: cubeb::DeviceId, -@@ -99,83 +101,167 @@ impl<'ctx> Stream<'ctx> { - user_ptr: *mut c_void) - -> Result>> { - -+ fn check_error(s: &pulse::Stream, u: *mut c_void) { -+ let stm = unsafe { &mut *(u as *mut Stream) }; -+ if !s.get_state().is_good() { -+ stm.state_change_callback(cubeb::STATE_ERROR); -+ } -+ stm.context.mainloop.signal(); -+ } -+ -+ fn read_data(s: &pulse::Stream, nbytes: usize, u: *mut c_void) { -+ fn read_from_input(s: &pulse::Stream, buffer: *mut *const c_void, size: *mut usize) -> i32 { -+ let readable_size: i32 = s.readable_size() -+ .and_then(|s| Ok(s as i32)) -+ .unwrap_or(-1); -+ if readable_size > 0 { -+ if unsafe { s.peek(buffer, size).is_err() } { -+ return -1; -+ } -+ } -+ readable_size -+ } -+ -+ logv!("Input callback buffer size {}", nbytes); -+ let mut stm = unsafe { &mut *(u as *mut Stream) }; -+ if stm.shutdown { -+ return; -+ } -+ -+ let mut read_data: *const c_void = ptr::null(); -+ let mut read_size: usize = 0; -+ while read_from_input(s, &mut read_data, &mut read_size) > 0 { -+ /* read_data can be NULL in case of a hole. */ -+ if !read_data.is_null() { -+ let in_frame_size = stm.input_sample_spec.frame_size(); -+ let read_frames = read_size / in_frame_size; -+ -+ if stm.output_stream.is_some() { -+ // input/capture + output/playback operation -+ let out_frame_size = stm.output_sample_spec.frame_size(); -+ let write_size = read_frames * out_frame_size; -+ // Offer full duplex data for writing -+ stm.trigger_user_callback(read_data, write_size); -+ } else { -+ // input/capture only operation. Call callback directly -+ let got = unsafe { -+ stm.data_callback.unwrap()(stm as *mut _ as *mut _, -+ stm.user_ptr, -+ read_data, -+ ptr::null_mut(), -+ read_frames as c_long) -+ }; -+ -+ if got < 0 || got as usize != read_frames { -+ let _ = s.cancel_write(); -+ stm.shutdown = true; -+ break; -+ } -+ } -+ } -+ -+ if read_size > 0 { -+ let _ = s.drop(); -+ } -+ -+ if stm.shutdown { -+ return; -+ } -+ } -+ } -+ -+ fn write_data(_: &pulse::Stream, nbytes: usize, u: *mut c_void) { -+ logv!("Output callback to be written buffer size {}", nbytes); -+ let mut stm = unsafe { &mut *(u as *mut Stream) }; -+ if stm.shutdown || stm.state != cubeb::STATE_STARTED { -+ return; -+ } -+ -+ if stm.input_stream.is_none() { -+ // Output/playback only operation. -+ // Write directly to output -+ debug_assert!(stm.output_stream.is_some()); -+ stm.trigger_user_callback(ptr::null(), nbytes); -+ } -+ } -+ - let mut stm = Box::new(Stream { - context: context, -- output_stream: ptr::null_mut(), -- input_stream: ptr::null_mut(), -+ output_stream: None, -+ input_stream: None, - data_callback: data_callback, - state_callback: state_callback, - user_ptr: user_ptr, - drain_timer: ptr::null_mut(), -- output_sample_spec: pa_sample_spec::default(), -- input_sample_spec: pa_sample_spec::default(), -+ output_sample_spec: pulse::SampleSpec::default(), -+ input_sample_spec: pulse::SampleSpec::default(), - shutdown: false, - volume: PULSE_NO_GAIN, - state: cubeb::STATE_ERROR, - }); - -- unsafe { -- pa_threaded_mainloop_lock(stm.context.mainloop); -+ if let Some(ref context) = stm.context.context { -+ stm.context.mainloop.lock(); -+ -+ // Setup output stream - if let Some(ref stream_params) = output_stream_params { -- match stm.pulse_stream_init(stream_params, stream_name) { -- Ok(s) => stm.output_stream = s, -+ match Stream::stream_init(context, stream_params, stream_name) { -+ Ok(s) => { -+ stm.output_sample_spec = *s.get_sample_spec(); -+ -+ s.set_state_callback(check_error, stm.as_mut() as *mut _ as *mut _); -+ s.set_write_callback(write_data, stm.as_mut() as *mut _ as *mut _); -+ -+ let battr = set_buffering_attribute(latency_frames, &stm.output_sample_spec); -+ let device_name = super::try_cstr_from(output_device as *const _); -+ let _ = s.connect_playback(device_name, -+ &battr, -+ pulse::STREAM_AUTO_TIMING_UPDATE | pulse::STREAM_INTERPOLATE_TIMING | -+ pulse::STREAM_START_CORKED | -+ pulse::STREAM_ADJUST_LATENCY, -+ None, -+ None); -+ -+ stm.output_stream = Some(s); -+ }, - Err(e) => { -- pa_threaded_mainloop_unlock(stm.context.mainloop); -+ stm.context.mainloop.unlock(); - stm.destroy(); - return Err(e); - }, - } - -- stm.output_sample_spec = *pa_stream_get_sample_spec(stm.output_stream); -- -- pa_stream_set_state_callback(stm.output_stream, -- Some(stream_state_callback), -- stm.as_mut() as *mut _ as *mut _); -- pa_stream_set_write_callback(stm.output_stream, -- Some(stream_write_callback), -- stm.as_mut() as *mut _ as *mut _); -- -- let battr = set_buffering_attribute(latency_frames, &stm.output_sample_spec); -- pa_stream_connect_playback(stm.output_stream, -- output_device as *mut c_char, -- &battr, -- PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING | -- PA_STREAM_START_CORKED | -- PA_STREAM_ADJUST_LATENCY, -- ptr::null(), -- ptr::null_mut()); - } - - // Set up input stream - if let Some(ref stream_params) = input_stream_params { -- match stm.pulse_stream_init(stream_params, stream_name) { -- Ok(s) => stm.input_stream = s, -+ match Stream::stream_init(context, stream_params, stream_name) { -+ Ok(s) => { -+ stm.input_sample_spec = *s.get_sample_spec(); -+ -+ s.set_state_callback(check_error, stm.as_mut() as *mut _ as *mut _); -+ s.set_read_callback(read_data, stm.as_mut() as *mut _ as *mut _); -+ -+ let battr = set_buffering_attribute(latency_frames, &stm.input_sample_spec); -+ let device_name = super::try_cstr_from(input_device as *const _); -+ let _ = s.connect_record(device_name, -+ &battr, -+ pulse::STREAM_AUTO_TIMING_UPDATE | pulse::STREAM_INTERPOLATE_TIMING | -+ pulse::STREAM_START_CORKED | -+ pulse::STREAM_ADJUST_LATENCY); -+ -+ stm.input_stream = Some(s); -+ }, - Err(e) => { -- pa_threaded_mainloop_unlock(stm.context.mainloop); -+ stm.context.mainloop.unlock(); - stm.destroy(); - return Err(e); - }, - } - -- stm.input_sample_spec = *(pa_stream_get_sample_spec(stm.input_stream)); -- -- pa_stream_set_state_callback(stm.input_stream, -- Some(stream_state_callback), -- stm.as_mut() as *mut _ as *mut _); -- pa_stream_set_read_callback(stm.input_stream, -- Some(stream_read_callback), -- stm.as_mut() as *mut _ as *mut _); -- -- let battr = set_buffering_attribute(latency_frames, &stm.input_sample_spec); -- pa_stream_connect_record(stm.input_stream, -- input_device as *mut c_char, -- &battr, -- PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING | -- PA_STREAM_START_CORKED | -- PA_STREAM_ADJUST_LATENCY); - } - -- let r = if stm.wait_until_stream_ready() { -+ let r = if stm.wait_until_ready() { - /* force a timing update now, otherwise timing info does not become valid - until some point after initialization has completed. */ - stm.update_timing_info() -@@ -183,7 +269,7 @@ impl<'ctx> Stream<'ctx> { - false - }; - -- pa_threaded_mainloop_unlock(stm.context.mainloop); -+ stm.context.mainloop.unlock(); - - if !r { - stm.destroy(); -@@ -191,10 +277,10 @@ impl<'ctx> Stream<'ctx> { - } - - if cubeb::log_enabled() { -- if output_stream_params.is_some() { -- let output_att = *pa_stream_get_buffer_attr(stm.output_stream); -- log!("Output buffer attributes maxlength %u, tlength %u, \ -- prebuf %u, minreq %u, fragsize %u", -+ if let Some(ref output_stream) = stm.output_stream { -+ let output_att = output_stream.get_buffer_attr(); -+ log!("Output buffer attributes maxlength {}, tlength {}, \ -+ prebuf {}, minreq {}, fragsize {}", - output_att.maxlength, - output_att.tlength, - output_att.prebuf, -@@ -202,10 +288,10 @@ impl<'ctx> Stream<'ctx> { - output_att.fragsize); - } - -- if input_stream_params.is_some() { -- let input_att = *pa_stream_get_buffer_attr(stm.input_stream); -- log!("Input buffer attributes maxlength %u, tlength %u, \ -- prebuf %u, minreq %u, fragsize %u", -+ if let Some(ref input_stream) = stm.input_stream { -+ let input_att = input_stream.get_buffer_attr(); -+ log!("Input buffer attributes maxlength {}, tlength {}, \ -+ prebuf {}, minreq {}, fragsize {}", - input_att.maxlength, - input_att.tlength, - input_att.prebuf, -@@ -219,224 +305,250 @@ impl<'ctx> Stream<'ctx> { - } - - fn destroy(&mut self) { -- self.stream_cork(CorkState::cork()); -+ self.cork(CorkState::cork()); - -- unsafe { -- pa_threaded_mainloop_lock(self.context.mainloop); -- if !self.output_stream.is_null() { -- if !self.drain_timer.is_null() { -- /* there's no pa_rttime_free, so use this instead. */ -- let ma = pa_threaded_mainloop_get_api(self.context.mainloop); -- if !ma.is_null() { -- (*ma).time_free.unwrap()(self.drain_timer); -+ self.context.mainloop.lock(); -+ { -+ match self.output_stream.take() { -+ Some(stm) => { -+ if !self.drain_timer.is_null() { -+ /* there's no pa_rttime_free, so use this instead. */ -+ self.context -+ .mainloop -+ .get_api() -+ .time_free(self.drain_timer); - } -- } -- -- pa_stream_set_state_callback(self.output_stream, None, ptr::null_mut()); -- pa_stream_set_write_callback(self.output_stream, None, ptr::null_mut()); -- pa_stream_disconnect(self.output_stream); -- pa_stream_unref(self.output_stream); -+ stm.clear_state_callback(); -+ stm.clear_write_callback(); -+ let _ = stm.disconnect(); -+ stm.unref(); -+ }, -+ _ => {}, -+ } -+ -+ match self.input_stream.take() { -+ Some(stm) => { -+ stm.clear_state_callback(); -+ stm.clear_read_callback(); -+ let _ = stm.disconnect(); -+ stm.unref(); -+ }, -+ _ => {}, - } -- -- if !self.input_stream.is_null() { -- pa_stream_set_state_callback(self.input_stream, None, ptr::null_mut()); -- pa_stream_set_read_callback(self.input_stream, None, ptr::null_mut()); -- pa_stream_disconnect(self.input_stream); -- pa_stream_unref(self.input_stream); -- } -- pa_threaded_mainloop_unlock(self.context.mainloop); - } -+ self.context.mainloop.unlock(); - } - - pub fn start(&mut self) -> i32 { -+ fn output_preroll(_: &pulse::MainloopApi, u: *mut c_void) { -+ let mut stm = unsafe { &mut *(u as *mut Stream) }; -+ if !stm.shutdown { -+ let size = stm.output_stream -+ .as_ref() -+ .map_or(0, |s| s.writable_size().unwrap_or(0)); -+ stm.trigger_user_callback(ptr::null_mut(), size); -+ } -+ } -+ - self.shutdown = false; -- self.stream_cork(CorkState::uncork() | CorkState::notify()); -+ self.cork(CorkState::uncork() | CorkState::notify()); - -- if !self.output_stream.is_null() && self.input_stream.is_null() { -- unsafe { -- /* On output only case need to manually call user cb once in order to make -- * things roll. This is done via a defer event in order to execute it -- * from PA server thread. */ -- pa_threaded_mainloop_lock(self.context.mainloop); -- pa_mainloop_api_once(pa_threaded_mainloop_get_api(self.context.mainloop), -- Some(pulse_defer_event_cb), -- self as *mut _ as *mut _); -- pa_threaded_mainloop_unlock(self.context.mainloop); -- } -+ if self.output_stream.is_some() && self.input_stream.is_none() { -+ /* On output only case need to manually call user cb once in order to make -+ * things roll. This is done via a defer event in order to execute it -+ * from PA server thread. */ -+ self.context.mainloop.lock(); -+ self.context -+ .mainloop -+ .get_api() -+ .once(output_preroll, self as *mut _ as *mut _); -+ self.context.mainloop.unlock(); - } - - cubeb::OK - } - - pub fn stop(&mut self) -> i32 { -- unsafe { -- pa_threaded_mainloop_lock(self.context.mainloop); -+ { -+ self.context.mainloop.lock(); - self.shutdown = true; - // If draining is taking place wait to finish - while !self.drain_timer.is_null() { -- pa_threaded_mainloop_wait(self.context.mainloop); -+ self.context.mainloop.wait(); - } -- pa_threaded_mainloop_unlock(self.context.mainloop); -+ self.context.mainloop.unlock(); - } -- self.stream_cork(CorkState::cork() | CorkState::notify()); -+ self.cork(CorkState::cork() | CorkState::notify()); - - cubeb::OK - } - - pub fn position(&self) -> Result { -- if self.output_stream.is_null() { -- return Err(cubeb::ERROR); -- } -+ let in_thread = self.context.mainloop.in_thread(); - -- let position = unsafe { -- let in_thread = pa_threaded_mainloop_in_thread(self.context.mainloop); -- -- if in_thread == 0 { -- pa_threaded_mainloop_lock(self.context.mainloop); -- } -- -- let mut r_usec: pa_usec_t = Default::default(); -- let r = pa_stream_get_time(self.output_stream, &mut r_usec); -- if in_thread == 0 { -- pa_threaded_mainloop_unlock(self.context.mainloop); -- } -- -- if r != 0 { -- return Err(cubeb::ERROR); -- } -+ if !in_thread { -+ self.context.mainloop.lock(); -+ } - -- let bytes = pa_usec_to_bytes(r_usec, &self.output_sample_spec); -- (bytes / pa_frame_size(&self.output_sample_spec)) as u64 -+ let r = match self.output_stream { -+ None => Err(cubeb::ERROR), -+ Some(ref stm) => { -+ match stm.get_time() { -+ Ok(r_usec) => { -+ let bytes = r_usec.to_bytes(&self.output_sample_spec); -+ Ok((bytes / self.output_sample_spec.frame_size()) as u64) -+ }, -+ Err(_) => Err(cubeb::ERROR), -+ } -+ }, - }; -- Ok(position) -- } - -- pub fn latency(&self) -> Result { -- if self.output_stream.is_null() { -- return Err(cubeb::ERROR); -+ if !in_thread { -+ self.context.mainloop.unlock(); - } - -- let mut r_usec: pa_usec_t = 0; -- let mut negative: i32 = 0; -- let r = unsafe { pa_stream_get_latency(self.output_stream, &mut r_usec, &mut negative) }; -+ r -+ } - -- if r != 0 { -- return Err(cubeb::ERROR); -+ pub fn latency(&self) -> Result { -+ match self.output_stream { -+ None => Err(cubeb::ERROR), -+ Some(ref stm) => { -+ match stm.get_latency() { -+ Ok((r_usec, negative)) => { -+ debug_assert!(negative); -+ let latency = (r_usec * self.output_sample_spec.rate as pa_usec_t / PA_USEC_PER_SEC) as u32; -+ Ok(latency) -+ }, -+ Err(_) => Err(cubeb::ERROR), -+ } -+ }, - } -- -- debug_assert_eq!(negative, 0); -- let latency = (r_usec * self.output_sample_spec.rate as pa_usec_t / PA_USEC_PER_SEC) as u32; -- -- Ok(latency) - } - - pub fn set_volume(&mut self, volume: f32) -> i32 { -- if self.output_stream.is_null() { -- return cubeb::ERROR; -- } -- -- unsafe { -- pa_threaded_mainloop_lock(self.context.mainloop); -- -- while self.context.default_sink_info.is_none() { -- pa_threaded_mainloop_wait(self.context.mainloop); -- } -- -- let mut cvol: pa_cvolume = Default::default(); -- -- /* if the pulse daemon is configured to use flat volumes, -- * apply our own gain instead of changing the input volume on the sink. */ -- let flags = { -- match self.context.default_sink_info { -- Some(ref info) => info.flags, -- _ => 0, -- } -- }; -- -- if (flags & PA_SINK_FLAT_VOLUME) != 0 { -- self.volume = volume; -- } else { -- let ss = pa_stream_get_sample_spec(self.output_stream); -- let vol = pa_sw_volume_from_linear(volume as f64); -- pa_cvolume_set(&mut cvol, (*ss).channels as u32, vol); -- -- let index = pa_stream_get_index(self.output_stream); -+ match self.output_stream { -+ None => cubeb::ERROR, -+ Some(ref stm) => { -+ if let Some(ref context) = self.context.context { -+ self.context.mainloop.lock(); -+ -+ let mut cvol: pa_cvolume = Default::default(); -+ -+ /* if the pulse daemon is configured to use flat -+ * volumes, apply our own gain instead of changing -+ * the input volume on the sink. */ -+ let flags = { -+ match self.context.default_sink_info { -+ Some(ref info) => info.flags, -+ _ => pulse::SinkFlags::empty(), -+ } -+ }; -+ -+ if flags.contains(pulse::SINK_FLAT_VOLUME) { -+ self.volume = volume; -+ } else { -+ let channels = stm.get_sample_spec().channels; -+ let vol = pulse::sw_volume_from_linear(volume as f64); -+ cvol.set(channels as u32, vol); -+ -+ let index = stm.get_index(); -+ -+ let context_ptr = self.context as *const _ as *mut _; -+ if let Ok(o) = context.set_sink_input_volume(index, &cvol, context_success, context_ptr) { -+ self.context.operation_wait(stm, &o); -+ } -+ } - -- let op = pa_context_set_sink_input_volume(self.context.context, -- index, -- &cvol, -- Some(volume_success), -- self as *mut _ as *mut _); -- if !op.is_null() { -- self.context.operation_wait(self.output_stream, op); -- pa_operation_unref(op); -+ self.context.mainloop.unlock(); -+ cubeb::OK -+ } else { -+ cubeb::ERROR - } -- } -- -- pa_threaded_mainloop_unlock(self.context.mainloop); -+ }, - } -- cubeb::OK - } - - pub fn set_panning(&mut self, panning: f32) -> i32 { -- if self.output_stream.is_null() { -- return cubeb::ERROR; -- } -+ #[repr(C)] -+ struct SinkInputInfoResult<'a> { -+ pub cvol: pulse::CVolume, -+ pub mainloop: &'a pulse::ThreadedMainloop, -+ } -+ -+ fn get_input_volume(_: &pulse::Context, info: *const pulse::SinkInputInfo, eol: i32, u: *mut c_void) { -+ let mut r = unsafe { &mut *(u as *mut SinkInputInfoResult) }; -+ if eol == 0 { -+ let info = unsafe { *info }; -+ r.cvol = info.volume; -+ } -+ r.mainloop.signal(); -+ } -+ -+ match self.output_stream { -+ None => cubeb::ERROR, -+ Some(ref stm) => { -+ if let Some(ref context) = self.context.context { -+ self.context.mainloop.lock(); -+ -+ let map = stm.get_channel_map(); -+ if !map.can_balance() { -+ self.context.mainloop.unlock(); -+ return cubeb::ERROR; -+ } - -- unsafe { -- pa_threaded_mainloop_lock(self.context.mainloop); -+ let index = stm.get_index(); - -- let map = pa_stream_get_channel_map(self.output_stream); -- if pa_channel_map_can_balance(map) == 0 { -- pa_threaded_mainloop_unlock(self.context.mainloop); -- return cubeb::ERROR; -- } -+ let mut r = SinkInputInfoResult { -+ cvol: pulse::CVolume::default(), -+ mainloop: &self.context.mainloop, -+ }; - -- let index = pa_stream_get_index(self.output_stream); -+ if let Ok(o) = context.get_sink_input_info(index, get_input_volume, &mut r as *mut _ as *mut _) { -+ self.context.operation_wait(stm, &o); -+ } - -- let mut cvol: pa_cvolume = Default::default(); -- let mut r = SinkInputInfoResult { -- cvol: &mut cvol, -- mainloop: self.context.mainloop, -- }; -+ r.cvol.set_balance(map, panning); - -- let op = pa_context_get_sink_input_info(self.context.context, -- index, -- Some(sink_input_info_cb), -- &mut r as *mut _ as *mut _); -- if !op.is_null() { -- self.context.operation_wait(self.output_stream, op); -- pa_operation_unref(op); -- } -- -- pa_cvolume_set_balance(&mut cvol, map, panning); -- -- let op = pa_context_set_sink_input_volume(self.context.context, -- index, -- &cvol, -- Some(volume_success), -- self as *mut _ as *mut _); -- if !op.is_null() { -- self.context.operation_wait(self.output_stream, op); -- pa_operation_unref(op); -- } -+ let context_ptr = self.context as *const _ as *mut _; -+ if let Ok(o) = context.set_sink_input_volume(index, &r.cvol, context_success, context_ptr) { -+ self.context.operation_wait(stm, &o); -+ } - -- pa_threaded_mainloop_unlock(self.context.mainloop); -- } -+ self.context.mainloop.unlock(); - -- cubeb::OK -+ cubeb::OK -+ } else { -+ cubeb::ERROR -+ } -+ }, -+ } - } - - pub fn current_device(&self) -> Result> { - if self.context.version_0_9_8 { - let mut dev = Box::new(cubeb::Device::default()); - -- if !self.input_stream.is_null() { -- dev.input_name = unsafe { pa_xstrdup(pa_stream_get_device_name(self.input_stream)) }; -+ if self.input_stream.is_some() { -+ if let Some(ref stm) = self.input_stream { -+ dev.input_name = match stm.get_device_name() { -+ Ok(name) => name.to_owned().into_raw(), -+ Err(_) => { -+ return Err(cubeb::ERROR); -+ }, -+ } -+ } - } - -- if !self.output_stream.is_null() { -- dev.output_name = unsafe { pa_xstrdup(pa_stream_get_device_name(self.output_stream)) }; -+ if !self.output_stream.is_some() { -+ if let Some(ref stm) = self.output_stream { -+ dev.output_name = match stm.get_device_name() { -+ Ok(name) => name.to_owned().into_raw(), -+ Err(_) => { -+ return Err(cubeb::ERROR); -+ }, -+ } -+ } - } - - Ok(dev) -@@ -445,51 +557,62 @@ impl<'ctx> Stream<'ctx> { - } - } - -- fn pulse_stream_init(&mut self, -- stream_params: &cubeb::StreamParams, -- stream_name: *const c_char) -- -> Result<*mut pa_stream> { -+ fn stream_init(context: &pulse::Context, -+ stream_params: &cubeb::StreamParams, -+ stream_name: &CStr) -+ -> Result { - -- fn to_pulse_format(format: cubeb::SampleFormat) -> pa_sample_format_t { -+ fn to_pulse_format(format: cubeb::SampleFormat) -> pulse::SampleFormat { - match format { -- cubeb::SAMPLE_S16LE => PA_SAMPLE_S16LE, -- cubeb::SAMPLE_S16BE => PA_SAMPLE_S16BE, -- cubeb::SAMPLE_FLOAT32LE => PA_SAMPLE_FLOAT32LE, -- cubeb::SAMPLE_FLOAT32BE => PA_SAMPLE_FLOAT32BE, -- _ => panic!("Invalid format: {:?}", format), -+ cubeb::SAMPLE_S16LE => pulse::SampleFormat::Signed16LE, -+ cubeb::SAMPLE_S16BE => pulse::SampleFormat::Signed16BE, -+ cubeb::SAMPLE_FLOAT32LE => pulse::SampleFormat::Float32LE, -+ cubeb::SAMPLE_FLOAT32BE => pulse::SampleFormat::Float32BE, -+ _ => pulse::SampleFormat::Invalid, - } - } - - let fmt = to_pulse_format(stream_params.format); -- if fmt == PA_SAMPLE_INVALID { -+ if fmt == pulse::SampleFormat::Invalid { - return Err(cubeb::ERROR_INVALID_FORMAT); - } - -- let ss = pa_sample_spec { -+ let ss = pulse::SampleSpec { - channels: stream_params.channels as u8, -- format: fmt, -+ format: fmt.into(), - rate: stream_params.rate, - }; - -- let stream = if stream_params.layout == cubeb::LAYOUT_UNDEFINED { -- unsafe { pa_stream_new(self.context.context, stream_name, &ss, ptr::null_mut()) } -- } else { -- let cm = layout_to_channel_map(stream_params.layout); -- unsafe { pa_stream_new(self.context.context, stream_name, &ss, &cm) } -+ let cm: Option = match stream_params.layout { -+ cubeb::LAYOUT_UNDEFINED => None, -+ _ => Some(layout_to_channel_map(stream_params.layout)), - }; - -- if !stream.is_null() { -- Ok(stream) -- } else { -- Err(cubeb::ERROR) -+ let stream = pulse::Stream::new(context, stream_name, &ss, cm.as_ref()); -+ -+ match stream { -+ None => Err(cubeb::ERROR), -+ Some(stm) => Ok(stm), -+ } -+ } -+ -+ pub fn cork_stream(&self, stream: Option<&pulse::Stream>, state: CorkState) { -+ if let Some(stm) = stream { -+ if let Ok(o) = stm.cork(state.is_cork() as i32, -+ stream_success, -+ self as *const _ as *mut _) { -+ self.context.operation_wait(stream, &o); -+ } - } - } - -- fn stream_cork(&mut self, state: CorkState) { -- unsafe { pa_threaded_mainloop_lock(self.context.mainloop) }; -- self.context.pulse_stream_cork(self.output_stream, state); -- self.context.pulse_stream_cork(self.input_stream, state); -- unsafe { pa_threaded_mainloop_unlock(self.context.mainloop) }; -+ fn cork(&mut self, state: CorkState) { -+ { -+ self.context.mainloop.lock(); -+ self.cork_stream(self.output_stream.as_ref(), state); -+ self.cork_stream(self.input_stream.as_ref(), state); -+ self.context.mainloop.unlock() -+ } - - if state.is_notify() { - self.state_change_callback(if state.is_cork() { -@@ -503,18 +626,9 @@ impl<'ctx> Stream<'ctx> { - fn update_timing_info(&self) -> bool { - let mut r = false; - -- if !self.output_stream.is_null() { -- let o = unsafe { -- pa_stream_update_timing_info(self.output_stream, -- Some(stream_success_callback), -- self as *const _ as *mut _) -- }; -- -- if !o.is_null() { -- r = self.context.operation_wait(self.output_stream, o); -- unsafe { -- pa_operation_unref(o); -- } -+ if let Some(ref stm) = self.output_stream { -+ if let Ok(o) = stm.update_timing_info(stream_success, self as *const _ as *mut _) { -+ r = self.context.operation_wait(stm, &o); - } - - if !r { -@@ -522,18 +636,9 @@ impl<'ctx> Stream<'ctx> { - } - } - -- if !self.input_stream.is_null() { -- let o = unsafe { -- pa_stream_update_timing_info(self.input_stream, -- Some(stream_success_callback), -- self as *const _ as *mut _) -- }; -- -- if !o.is_null() { -- r = self.context.operation_wait(self.input_stream, o); -- unsafe { -- pa_operation_unref(o); -- } -+ if let Some(ref stm) = self.input_stream { -+ if let Ok(o) = stm.update_timing_info(stream_success, self as *const _ as *mut _) { -+ r = self.context.operation_wait(stm, &o); - } - } - -@@ -547,232 +652,162 @@ impl<'ctx> Stream<'ctx> { - } - } - -- fn wait_until_stream_ready(&self) -> bool { -- if !self.output_stream.is_null() && !wait_until_io_stream_ready(self.output_stream, self.context.mainloop) { -- return false; -- } -- -- if !self.input_stream.is_null() && !wait_until_io_stream_ready(self.input_stream, self.context.mainloop) { -- return false; -- } -- -- true -- } -- -- fn trigger_user_callback(&mut self, s: *mut pa_stream, input_data: *const c_void, nbytes: usize) { -- let frame_size = unsafe { pa_frame_size(&self.output_sample_spec) }; -- debug_assert_eq!(nbytes % frame_size, 0); -- -- let mut buffer: *mut c_void = ptr::null_mut(); -- let mut r: i32; -- -- let mut towrite = nbytes; -- let mut read_offset = 0usize; -- while towrite > 0 { -- let mut size = towrite; -- r = unsafe { pa_stream_begin_write(s, &mut buffer, &mut size) }; -- // Note: this has failed running under rr on occassion - needs investigation. -- debug_assert_eq!(r, 0); -- debug_assert!(size > 0); -- debug_assert_eq!(size % frame_size, 0); -- -- logv!("Trigger user callback with output buffer size={}, read_offset={}", -- size, -- read_offset); -- let read_ptr = unsafe { (input_data as *const u8).offset(read_offset as isize) }; -- let got = unsafe { -- self.data_callback.unwrap()(self as *const _ as *mut _, -- self.user_ptr, -- read_ptr as *const _ as *mut _, -- buffer, -- (size / frame_size) as c_long) -- }; -- if got < 0 { -- unsafe { -- pa_stream_cancel_write(s); -- } -- self.shutdown = true; -- return; -- } -- // If more iterations move offset of read buffer -- if !input_data.is_null() { -- let in_frame_size = unsafe { pa_frame_size(&self.input_sample_spec) }; -- read_offset += (size / frame_size) * in_frame_size; -+ fn wait_until_ready(&self) -> bool { -+ fn wait_until_io_stream_ready(stm: &pulse::Stream, mainloop: &pulse::ThreadedMainloop) -> bool { -+ if mainloop.is_null() { -+ return false; - } - -- if self.volume != PULSE_NO_GAIN { -- let samples = (self.output_sample_spec.channels as usize * size / frame_size) as isize; -- -- if self.output_sample_spec.format == PA_SAMPLE_S16BE || -- self.output_sample_spec.format == PA_SAMPLE_S16LE { -- let b = buffer as *mut i16; -- for i in 0..samples { -- unsafe { *b.offset(i) *= self.volume as i16 }; -- } -- } else { -- let b = buffer as *mut f32; -- for i in 0..samples { -- unsafe { *b.offset(i) *= self.volume }; -- } -+ loop { -+ let state = stm.get_state(); -+ if !state.is_good() { -+ return false; -+ } -+ if state == pulse::StreamState::Ready { -+ break; - } -+ mainloop.wait(); - } - -- r = unsafe { -- pa_stream_write(s, -- buffer, -- got as usize * frame_size, -- None, -- 0, -- PA_SEEK_RELATIVE) -- }; -- debug_assert_eq!(r, 0); -+ true -+ } - -- if (got as usize) < size / frame_size { -- let mut latency: pa_usec_t = 0; -- let rr: i32 = unsafe { pa_stream_get_latency(s, &mut latency, ptr::null_mut()) }; -- if rr == -(PA_ERR_NODATA as i32) { -- /* this needs a better guess. */ -- latency = 100 * PA_USEC_PER_MSEC; -- } -- debug_assert!(r == 0 || r == -(PA_ERR_NODATA as i32)); -- /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */ -- /* arbitrary safety margin: double the current latency. */ -- debug_assert!(self.drain_timer.is_null()); -- self.drain_timer = unsafe { -- pa_context_rttime_new(self.context.context, -- pa_rtclock_now() + 2 * latency, -- Some(stream_drain_callback), -- self as *const _ as *mut _) -- }; -- self.shutdown = true; -- return; -+ if let Some(ref stm) = self.output_stream { -+ if !wait_until_io_stream_ready(stm, &self.context.mainloop) { -+ return false; - } -- -- towrite -= size; - } - -- debug_assert_eq!(towrite, 0); -- } --} -- --unsafe extern "C" fn stream_success_callback(_s: *mut pa_stream, _success: i32, u: *mut c_void) { -- let stm = &*(u as *mut Stream); -- pa_threaded_mainloop_signal(stm.context.mainloop, 0); --} -- --unsafe extern "C" fn stream_drain_callback(a: *mut pa_mainloop_api, -- e: *mut pa_time_event, -- _tv: *const timeval, -- u: *mut c_void) { -- let mut stm = &mut *(u as *mut Stream); -- debug_assert_eq!(stm.drain_timer, e); -- stm.state_change_callback(cubeb::STATE_DRAINED); -- /* there's no pa_rttime_free, so use this instead. */ -- (*a).time_free.unwrap()(stm.drain_timer); -- stm.drain_timer = ptr::null_mut(); -- pa_threaded_mainloop_signal(stm.context.mainloop, 0); --} -- --unsafe extern "C" fn stream_state_callback(s: *mut pa_stream, u: *mut c_void) { -- let stm = &mut *(u as *mut Stream); -- if !PA_STREAM_IS_GOOD(pa_stream_get_state(s)) { -- stm.state_change_callback(cubeb::STATE_ERROR); -- } -- pa_threaded_mainloop_signal(stm.context.mainloop, 0); --} -- --fn read_from_input(s: *mut pa_stream, buffer: *mut *const c_void, size: *mut usize) -> i32 { -- let readable_size = unsafe { pa_stream_readable_size(s) }; -- if readable_size > 0 && unsafe { pa_stream_peek(s, buffer, size) } < 0 { -- return -1; -- } -- -- readable_size as i32 --} -+ if let Some(ref stm) = self.input_stream { -+ if !wait_until_io_stream_ready(stm, &self.context.mainloop) { -+ return false; -+ } -+ } - --unsafe extern "C" fn stream_write_callback(s: *mut pa_stream, nbytes: usize, u: *mut c_void) { -- logv!("Output callback to be written buffer size {}", nbytes); -- let mut stm = &mut *(u as *mut Stream); -- if stm.shutdown || stm.state != cubeb::STATE_STARTED { -- return; -+ true - } - -- if stm.input_stream.is_null() { -- // Output/playback only operation. -- // Write directly to output -- debug_assert!(!stm.output_stream.is_null()); -- stm.trigger_user_callback(s, ptr::null(), nbytes); -- } --} -+ fn trigger_user_callback(&mut self, input_data: *const c_void, nbytes: usize) { -+ fn drained_cb(a: &pulse::MainloopApi, e: *mut pa_time_event, _tv: &pulse::TimeVal, u: *mut c_void) { -+ let mut stm = unsafe { &mut *(u as *mut Stream) }; -+ debug_assert_eq!(stm.drain_timer, e); -+ stm.state_change_callback(cubeb::STATE_DRAINED); -+ /* there's no pa_rttime_free, so use this instead. */ -+ a.time_free(stm.drain_timer); -+ stm.drain_timer = ptr::null_mut(); -+ stm.context.mainloop.signal(); -+ } -+ -+ if let Some(ref stm) = self.output_stream { -+ -+ let frame_size = self.output_sample_spec.frame_size(); -+ debug_assert_eq!(nbytes % frame_size, 0); -+ -+ let mut towrite = nbytes; -+ let mut read_offset = 0usize; -+ while towrite > 0 { -+ match stm.begin_write(towrite) { -+ Err(e) => { -+ panic!("Failed to write data: {}", e); -+ }, -+ Ok((buffer, size)) => { -+ debug_assert!(size > 0); -+ debug_assert_eq!(size % frame_size, 0); -+ -+ logv!("Trigger user callback with output buffer size={}, read_offset={}", -+ size, -+ read_offset); -+ let read_ptr = unsafe { (input_data as *const u8).offset(read_offset as isize) }; -+ let got = unsafe { -+ self.data_callback.unwrap()(self as *const _ as *mut _, -+ self.user_ptr, -+ read_ptr as *const _ as *mut _, -+ buffer, -+ (size / frame_size) as c_long) -+ }; -+ if got < 0 { -+ let _ = stm.cancel_write(); -+ self.shutdown = true; -+ return; -+ } -+ -+ // If more iterations move offset of read buffer -+ if !input_data.is_null() { -+ let in_frame_size = self.input_sample_spec.frame_size(); -+ read_offset += (size / frame_size) * in_frame_size; -+ } -+ -+ if self.volume != PULSE_NO_GAIN { -+ let samples = (self.output_sample_spec.channels as usize * size / frame_size) as isize; -+ -+ if self.output_sample_spec.format == PA_SAMPLE_S16BE || -+ self.output_sample_spec.format == PA_SAMPLE_S16LE { -+ let b = buffer as *mut i16; -+ for i in 0..samples { -+ unsafe { *b.offset(i) *= self.volume as i16 }; -+ } -+ } else { -+ let b = buffer as *mut f32; -+ for i in 0..samples { -+ unsafe { *b.offset(i) *= self.volume }; -+ } -+ } -+ } -+ -+ let r = stm.write(buffer, -+ got as usize * frame_size, -+ 0, -+ pulse::SeekMode::Relative); -+ debug_assert!(r.is_ok()); -+ -+ if (got as usize) < size / frame_size { -+ let latency = match stm.get_latency() { -+ Ok((l, negative)) => { -+ assert_ne!(negative, true); -+ l -+ }, -+ Err(e) => { -+ debug_assert_eq!(e, pulse::ErrorCode::from_error_code(PA_ERR_NODATA)); -+ /* this needs a better guess. */ -+ 100 * PA_USEC_PER_MSEC -+ }, -+ }; -+ -+ /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */ -+ /* arbitrary safety margin: double the current latency. */ -+ debug_assert!(self.drain_timer.is_null()); -+ let stream_ptr = self as *const _ as *mut _; -+ if let Some(ref context) = self.context.context { -+ self.drain_timer = -+ context.rttime_new(pulse::rtclock_now() + 2 * latency, drained_cb, stream_ptr); -+ } -+ self.shutdown = true; -+ return; -+ } - --unsafe extern "C" fn stream_read_callback(s: *mut pa_stream, nbytes: usize, u: *mut c_void) { -- logv!("Input callback buffer size {}", nbytes); -- let mut stm = &mut *(u as *mut Stream); -- if stm.shutdown { -- return; -- } -- -- let mut read_data: *const c_void = ptr::null(); -- let mut read_size: usize = 0; -- while read_from_input(s, &mut read_data, &mut read_size) > 0 { -- /* read_data can be NULL in case of a hole. */ -- if !read_data.is_null() { -- let in_frame_size = pa_frame_size(&stm.input_sample_spec); -- let read_frames = read_size / in_frame_size; -- -- if !stm.output_stream.is_null() { -- // input/capture + output/playback operation -- let out_frame_size = pa_frame_size(&stm.output_sample_spec); -- let write_size = read_frames * out_frame_size; -- // Offer full duplex data for writing -- let stream = stm.output_stream; -- stm.trigger_user_callback(stream, read_data, write_size); -- } else { -- // input/capture only operation. Call callback directly -- let got = stm.data_callback.unwrap()(stm as *mut _ as *mut _, -- stm.user_ptr, -- read_data, -- ptr::null_mut(), -- read_frames as c_long); -- if got < 0 || got as usize != read_frames { -- pa_stream_cancel_write(s); -- stm.shutdown = true; -- break; -+ towrite -= size; -+ }, - } - } -- } -- -- if read_size > 0 { -- pa_stream_drop(s); -- } -- -- if stm.shutdown { -- return; -+ debug_assert_eq!(towrite, 0); - } - } - } - --fn wait_until_io_stream_ready(stream: *mut pa_stream, mainloop: *mut pa_threaded_mainloop) -> bool { -- if stream.is_null() || mainloop.is_null() { -- return false; -- } -- -- loop { -- let state = unsafe { pa_stream_get_state(stream) }; -- if !PA_STREAM_IS_GOOD(state) { -- return false; -- } -- if state == PA_STREAM_READY { -- break; -- } -- unsafe { pa_threaded_mainloop_wait(mainloop) }; -- } -+fn stream_success(_: &pulse::Stream, success: i32, u: *mut c_void) { -+ let stm = unsafe { &*(u as *mut Stream) }; -+ debug_assert_ne!(success, 0); -+ stm.context.mainloop.signal(); -+} - -- true -+fn context_success(_: &pulse::Context, success: i32, u: *mut c_void) { -+ let ctx = unsafe { &*(u as *mut Context) }; -+ debug_assert_ne!(success, 0); -+ ctx.mainloop.signal(); - } - - fn set_buffering_attribute(latency_frames: u32, sample_spec: &pa_sample_spec) -> pa_buffer_attr { -- let tlength = latency_frames * unsafe { pa_frame_size(sample_spec) } as u32; -+ let tlength = latency_frames * sample_spec.frame_size() as u32; - let minreq = tlength / 4; - let battr = pa_buffer_attr { - maxlength: u32::max_value(), -@@ -791,34 +826,3 @@ fn set_buffering_attribute(latency_frame - - battr - } -- --unsafe extern "C" fn pulse_defer_event_cb(_a: *mut pa_mainloop_api, u: *mut c_void) { -- let mut stm = &mut *(u as *mut Stream); -- if stm.shutdown { -- return; -- } -- let writable_size = pa_stream_writable_size(stm.output_stream); -- let stream = stm.output_stream; -- stm.trigger_user_callback(stream, ptr::null_mut(), writable_size); --} -- --#[repr(C)] --struct SinkInputInfoResult { -- pub cvol: *mut pa_cvolume, -- pub mainloop: *mut pa_threaded_mainloop, --} -- --unsafe extern "C" fn sink_input_info_cb(_c: *mut pa_context, i: *const pa_sink_input_info, eol: i32, u: *mut c_void) { -- let info = &*i; -- let mut r = &mut *(u as *mut SinkInputInfoResult); -- if eol == 0 { -- *r.cvol = info.volume; -- } -- pa_threaded_mainloop_signal(r.mainloop, 0); --} -- --unsafe extern "C" fn volume_success(_c: *mut pa_context, success: i32, u: *mut c_void) { -- let stm = &*(u as *mut Stream); -- debug_assert_ne!(success, 0); -- pa_threaded_mainloop_signal(stm.context.mainloop, 0); --} -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/capi.rs 2017-08-04 13:37:46.387821728 +0200 -@@ -5,6 +5,7 @@ - - use backend; - use cubeb; -+use std::ffi::CStr; - use std::os::raw::{c_char, c_void}; - - unsafe extern "C" fn capi_init(c: *mut *mut cubeb::Context, context_name: *const c_char) -> i32 { -@@ -114,21 +115,18 @@ unsafe extern "C" fn capi_stream_init(c: - state_callback: cubeb::StateCallback, - user_ptr: *mut c_void) - -> i32 { -+ fn try_stream_params_from(sp: *mut cubeb::StreamParams) -> Option { -+ if sp.is_null() { None } else { Some(unsafe { *sp }) } -+ } -+ - let mut ctx = &mut *(c as *mut backend::Context); -+ let stream_name = CStr::from_ptr(stream_name); - - match ctx.new_stream(stream_name, - input_device, -- if input_stream_params.is_null() { -- None -- } else { -- Some(*input_stream_params) -- }, -+ try_stream_params_from(input_stream_params), - output_device, -- if output_stream_params.is_null() { -- None -- } else { -- Some(*output_stream_params) -- }, -+ try_stream_params_from(output_stream_params), - latency_frames, - data_callback, - state_callback, -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/src/lib.rs 2017-08-04 13:37:46.387821728 +0200 -@@ -8,6 +8,7 @@ - #[macro_use] - extern crate cubeb_ffi as cubeb; - extern crate pulse_ffi; -+extern crate pulse; - extern crate semver; - - mod capi; -diff -up firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh.cubeb-pulse-arm firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh ---- firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh.cubeb-pulse-arm 2017-07-31 18:20:49.000000000 +0200 -+++ firefox-55.0/media/libcubeb/cubeb-pulse-rs/update.sh 2017-08-04 13:37:46.383821740 +0200 -@@ -13,6 +13,9 @@ cp -pr $1/cubeb-ffi/src/* cubeb-ffi/src/ - test -d pulse-ffi/src || mkdir -p pulse-ffi/src - cp -pr $1/pulse-ffi/Cargo.toml pulse-ffi/ - cp -pr $1/pulse-ffi/src/* pulse-ffi/src/ -+test -d pulse-rs/src || mkdir -p pulse-rs/src -+cp -pr $1/pulse-rs/Cargo.toml pulse-rs/ -+cp -pr $1/pulse-rs/src/* pulse-rs/src/ - - if [ -d $1/.git ]; then - rev=$(cd $1 && git rev-parse --verify HEAD) -diff -up firefox-55.0/toolkit/library/gtest/rust/Cargo.lock.cubeb-pulse-arm firefox-55.0/toolkit/library/gtest/rust/Cargo.lock ---- firefox-55.0/toolkit/library/gtest/rust/Cargo.lock.cubeb-pulse-arm 2017-08-04 13:37:46.388821725 +0200 -+++ firefox-55.0/toolkit/library/gtest/rust/Cargo.lock 2017-08-04 13:59:15.592940994 +0200 -@@ -252,6 +252,7 @@ name = "cubeb-pulse" - version = "0.0.1" - dependencies = [ - "cubeb-ffi 0.0.1", -+ "pulse 0.1.0", - "pulse-ffi 0.1.0", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - ] -@@ -660,6 +661,14 @@ version = "0.1.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - - [[package]] -+name = "pulse" -+version = "0.1.0" -+dependencies = [ -+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -+ "pulse-ffi 0.1.0", -+] -+ -+[[package]] - name = "pulse-ffi" - version = "0.1.0" - dependencies = [ -diff -up firefox-55.0/toolkit/library/rust/Cargo.lock.cubeb-pulse-arm firefox-55.0/toolkit/library/rust/Cargo.lock ---- firefox-55.0/toolkit/library/rust/Cargo.lock.cubeb-pulse-arm 2017-08-04 13:37:46.388821725 +0200 -+++ firefox-55.0/toolkit/library/rust/Cargo.lock 2017-08-04 13:52:24.551163669 +0200 -@@ -250,6 +250,7 @@ name = "cubeb-pulse" - version = "0.0.1" - dependencies = [ - "cubeb-ffi 0.0.1", -+ "pulse 0.1.0", - "pulse-ffi 0.1.0", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - ] -@@ -647,6 +648,14 @@ version = "0.1.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - - [[package]] -+name = "pulse" -+version = "0.1.0" -+dependencies = [ -+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -+ "pulse-ffi 0.1.0", -+] -+ -+[[package]] - name = "pulse-ffi" - version = "0.1.0" - dependencies = [ diff --git a/fedora-build.patch b/fedora-build.patch deleted file mode 100644 index 74127ec..0000000 --- a/fedora-build.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -up firefox-54.0/media/libyuv/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS.chromium.old firefox-54.0/media/libyuv/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS.chromium -diff -up firefox-54.0/media/mtransport/third_party/nICEr/nicer.gyp.old firefox-54.0/media/mtransport/third_party/nICEr/nicer.gyp ---- firefox-54.0/media/mtransport/third_party/nICEr/nicer.gyp.old 2017-06-08 14:59:08.786996664 +0200 -+++ firefox-54.0/media/mtransport/third_party/nICEr/nicer.gyp 2017-06-08 14:59:22.642946570 +0200 -@@ -211,7 +211,6 @@ - '-Wno-parentheses', - '-Wno-strict-prototypes', - '-Wmissing-prototypes', -- '-Wno-format', - ], - 'defines' : [ - 'LINUX', -diff -up firefox-54.0/media/mtransport/third_party/nrappkit/nrappkit.gyp.build firefox-54.0/media/mtransport/third_party/nrappkit/nrappkit.gyp ---- firefox-54.0/media/mtransport/third_party/nrappkit/nrappkit.gyp.build 2017-06-08 15:08:03.627063097 +0200 -+++ firefox-54.0/media/mtransport/third_party/nrappkit/nrappkit.gyp 2017-06-08 15:08:15.657019606 +0200 -@@ -206,7 +206,6 @@ - '-Wno-parentheses', - '-Wno-strict-prototypes', - '-Wmissing-prototypes', -- '-Wno-format', - ], - 'defines' : [ - 'LINUX', diff --git a/firefox-kde-webrender.patch b/firefox-kde-webrender.patch deleted file mode 100644 index f5f4ac7..0000000 --- a/firefox-kde-webrender.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff -up firefox-87.0/widget/GfxInfoX11.cpp.firefox-kde-webrender firefox-87.0/widget/GfxInfoX11.cpp ---- firefox-87.0/widget/GfxInfoX11.cpp.firefox-kde-webrender 2021-03-22 19:55:59.169952960 +0100 -+++ firefox-87.0/widget/GfxInfoX11.cpp 2021-03-22 20:04:35.332183657 +0100 -@@ -738,6 +738,14 @@ const nsTArray& GfxInfo:: - DRIVER_GREATER_THAN_OR_EQUAL, V(17, 0, 0, 0), - "FEATURE_ROLLOUT_INTEL_GNOME_WAYLAND_MESA", "Mesa 17.0.0.0"); - -+ APPEND_TO_DRIVER_BLOCKLIST_EXT( -+ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, -+ DesktopEnvironment::KDE, WindowProtocol::Wayland, -+ DriverVendor::MesaAll, DeviceFamily::IntelRolloutWebRender, -+ nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS, -+ DRIVER_GREATER_THAN_OR_EQUAL, V(17, 0, 0, 0), -+ "FEATURE_ROLLOUT_INTEL_GNOME_WAYLAND_MESA", "Mesa 17.0.0.0"); -+ - // ATI Mesa baseline, chosen arbitrarily. - APPEND_TO_DRIVER_BLOCKLIST_EXT( - OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, -@@ -754,6 +762,14 @@ const nsTArray& GfxInfo:: - DRIVER_GREATER_THAN_OR_EQUAL, V(17, 0, 0, 0), - "FEATURE_ROLLOUT_ATI_GNOME_WAYLAND_MESA", "Mesa 17.0.0.0"); - -+ APPEND_TO_DRIVER_BLOCKLIST_EXT( -+ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, -+ DesktopEnvironment::KDE, WindowProtocol::Wayland, -+ DriverVendor::MesaAll, DeviceFamily::AtiRolloutWebRender, -+ nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS, -+ DRIVER_GREATER_THAN_OR_EQUAL, V(17, 0, 0, 0), -+ "FEATURE_ROLLOUT_ATI_GNOME_WAYLAND_MESA", "Mesa 17.0.0.0"); -+ - #ifdef EARLY_BETA_OR_EARLIER - // Intel Mesa baseline, chosen arbitrarily. - APPEND_TO_DRIVER_BLOCKLIST_EXT( diff --git a/firefox.spec b/firefox.spec index f970fe1..221882a 100644 --- a/firefox.spec +++ b/firefox.spec @@ -1076,6 +1076,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : * Tue Aug 23 2022 Kalev Lember - 104.0-5 - Use constrain_build macro to simplify parallel make handling - Drop obsolete build conditionals +- Drop unused patches * Tue Aug 23 2022 Jan Horak - 104.0-4 - Rebuild due to ppc64le fixes diff --git a/mozilla-1640982.patch b/mozilla-1640982.patch deleted file mode 100644 index b63ba3b..0000000 --- a/mozilla-1640982.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/config/makefiles/rust.mk b/config/makefiles/rust.mk ---- a/config/makefiles/rust.mk -+++ b/config/makefiles/rust.mk -@@ -61,7 +61,11 @@ - # Enable link-time optimization for release builds, but not when linking - # gkrust_gtest. - ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE))) -+# Pass -Clto for older versions of rust, and CARGO_PROFILE_RELEASE_LTO=true -+# for newer ones that support it. Combining the latter with -Clto works, so -+# set both everywhere. - cargo_rustc_flags += -Clto -+export CARGO_PROFILE_RELEASE_LTO=true - endif - endif - endif - diff --git a/mozilla-1672139.patch b/mozilla-1672139.patch deleted file mode 100644 index efd40cb..0000000 --- a/mozilla-1672139.patch +++ /dev/null @@ -1,91 +0,0 @@ -diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp ---- a/gfx/layers/ipc/CompositorBridgeParent.cpp -+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp -@@ -2376,30 +2376,28 @@ - if (mWrBridge->PipelineId() == aPipelineId) { - mWrBridge->RemoveEpochDataPriorTo(aEpoch); - -- if (!mPaused) { -- if (mIsForcedFirstPaint) { -- uiController->NotifyFirstPaint(); -- mIsForcedFirstPaint = false; -- } -- -- std::pair key(aPipelineId, aEpoch); -- nsTArray payload = -- mWrBridge->TakePendingScrollPayload(key); -- if (!payload.IsEmpty()) { -- RecordCompositionPayloadsPresented(payload); -- } -- -- TransactionId transactionId = mWrBridge->FlushTransactionIdsForEpoch( -- aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, -- aCompositeEnd, uiController); -- Unused << SendDidComposite(LayersId{0}, transactionId, aCompositeStart, -- aCompositeEnd); -- -- nsTArray notifications; -- mWrBridge->ExtractImageCompositeNotifications(¬ifications); -- if (!notifications.IsEmpty()) { -- Unused << ImageBridgeParent::NotifyImageComposites(notifications); -- } -+ if (mIsForcedFirstPaint) { -+ uiController->NotifyFirstPaint(); -+ mIsForcedFirstPaint = false; -+ } -+ -+ std::pair key(aPipelineId, aEpoch); -+ nsTArray payload = -+ mWrBridge->TakePendingScrollPayload(key); -+ if (!payload.IsEmpty()) { -+ RecordCompositionPayloadsPresented(payload); -+ } -+ -+ TransactionId transactionId = mWrBridge->FlushTransactionIdsForEpoch( -+ aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, aCompositeEnd, -+ uiController); -+ Unused << SendDidComposite(LayersId{0}, transactionId, aCompositeStart, -+ aCompositeEnd); -+ -+ nsTArray notifications; -+ mWrBridge->ExtractImageCompositeNotifications(¬ifications); -+ if (!notifications.IsEmpty()) { -+ Unused << ImageBridgeParent::NotifyImageComposites(notifications); - } - return; - } -@@ -2408,21 +2406,19 @@ - if (wrBridge && wrBridge->GetCompositorBridge()) { - MOZ_ASSERT(!wrBridge->IsRootWebRenderBridgeParent()); - wrBridge->RemoveEpochDataPriorTo(aEpoch); -- if (!mPaused) { -- std::pair key(aPipelineId, aEpoch); -- nsTArray payload = -- wrBridge->TakePendingScrollPayload(key); -- if (!payload.IsEmpty()) { -- RecordCompositionPayloadsPresented(payload); -- } -- -- TransactionId transactionId = wrBridge->FlushTransactionIdsForEpoch( -- aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, -- aCompositeEnd, uiController, aStats, &stats); -- Unused << wrBridge->GetCompositorBridge()->SendDidComposite( -- wrBridge->GetLayersId(), transactionId, aCompositeStart, -- aCompositeEnd); -+ -+ std::pair key(aPipelineId, aEpoch); -+ nsTArray payload = -+ wrBridge->TakePendingScrollPayload(key); -+ if (!payload.IsEmpty()) { -+ RecordCompositionPayloadsPresented(payload); - } -+ -+ TransactionId transactionId = wrBridge->FlushTransactionIdsForEpoch( -+ aEpoch, aCompositeStartId, aCompositeStart, aRenderStart, aCompositeEnd, -+ uiController, aStats, &stats); -+ Unused << wrBridge->GetCompositorBridge()->SendDidComposite( -+ wrBridge->GetLayersId(), transactionId, aCompositeStart, aCompositeEnd); - } - - if (!stats.IsEmpty()) { - diff --git a/mozilla-1673313.patch b/mozilla-1673313.patch deleted file mode 100644 index 549243b..0000000 --- a/mozilla-1673313.patch +++ /dev/null @@ -1,351 +0,0 @@ -changeset: 556172:143b4ca96ec9 -tag: tip -parent: 556169:61c35792ca70 -user: stransky -date: Mon Oct 26 12:15:49 2020 +0100 -files: widget/gtk/WindowSurfaceWayland.cpp widget/gtk/WindowSurfaceWayland.h -description: -Bug 1673313 [Wayland] Don't fail when Shm allocation fails, r?jhorak - -- Make WaylandAllocateShmMemory() fallible. -- Implement WaylandReAllocateShmMemory() to re-allocate Shm pool. -- Remove WaylandShmPool::Resize() and use WaylandShmPool::Create() only. -- Implement and use WaylandShmPool::Release(). -- Make WindowSurfaceWayland::CreateWaylandBuffer() as fallible. - -Differential Revision: https://phabricator.services.mozilla.com/D94735 - - -diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp ---- a/widget/gtk/WindowSurfaceWayland.cpp -+++ b/widget/gtk/WindowSurfaceWayland.cpp -@@ -209,14 +209,23 @@ RefPtr WindowBackBuffe - } - - static int WaylandAllocateShmMemory(int aSize) { -- static int counter = 0; -- nsPrintfCString shmName("/wayland.mozilla.ipc.%d", counter++); -- int fd = shm_open(shmName.get(), O_CREAT | O_RDWR | O_EXCL, 0600); -- if (fd >= 0) { -- shm_unlink(shmName.get()); -- } else { -- printf_stderr("Unable to SHM memory segment\n"); -- MOZ_CRASH(); -+ int fd = -1; -+ do { -+ static int counter = 0; -+ nsPrintfCString shmName("/wayland.mozilla.ipc.%d", counter++); -+ fd = shm_open(shmName.get(), O_CREAT | O_RDWR | O_EXCL, 0600); -+ if (fd >= 0) { -+ // We don't want to use leaked file -+ if (shm_unlink(shmName.get()) != 0) { -+ NS_WARNING("shm_unlink failed"); -+ return -1; -+ } -+ } -+ } while (fd < 0 && errno == EEXIST); -+ -+ if (fd < 0) { -+ NS_WARNING(nsPrintfCString("shm_open failed: %s", strerror(errno)).get()); -+ return -1; - } - - int ret = 0; -@@ -225,59 +234,103 @@ static int WaylandAllocateShmMemory(int - ret = posix_fallocate(fd, 0, aSize); - } while (ret == EINTR); - if (ret != 0) { -+ NS_WARNING( -+ nsPrintfCString("posix_fallocate() fails to allocate shm memory: %s", -+ strerror(ret)) -+ .get()); - close(fd); -- MOZ_CRASH("posix_fallocate() fails to allocate shm memory"); -+ return -1; - } - #else - do { - ret = ftruncate(fd, aSize); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { -+ NS_WARNING(nsPrintfCString("ftruncate() fails to allocate shm memory: %s", -+ strerror(ret)) -+ .get()); - close(fd); -- MOZ_CRASH("ftruncate() fails to allocate shm memory"); -+ fd = -1; - } - #endif - - return fd; - } - --WaylandShmPool::WaylandShmPool(RefPtr aWaylandDisplay, -- int aSize) -- : mAllocatedSize(aSize) { -- mShmPoolFd = WaylandAllocateShmMemory(mAllocatedSize); -- mImageData = mmap(nullptr, mAllocatedSize, PROT_READ | PROT_WRITE, MAP_SHARED, -- mShmPoolFd, 0); -- MOZ_RELEASE_ASSERT(mImageData != MAP_FAILED, -- "Unable to map drawing surface!"); -+static bool WaylandReAllocateShmMemory(int aFd, int aSize) { -+ if (ftruncate(aFd, aSize) < 0) { -+ return false; -+ } -+#ifdef HAVE_POSIX_FALLOCATE -+ do { -+ errno = posix_fallocate(aFd, 0, aSize); -+ } while (errno == EINTR); -+ if (errno != 0) { -+ return false; -+ } -+#endif -+ return true; -+} - -- mShmPool = -- wl_shm_create_pool(aWaylandDisplay->GetShm(), mShmPoolFd, mAllocatedSize); -+WaylandShmPool::WaylandShmPool() -+ : mShmPool(nullptr), -+ mShmPoolFd(-1), -+ mAllocatedSize(0), -+ mImageData(MAP_FAILED){}; - -- // We set our queue to get mShmPool events at compositor thread. -- wl_proxy_set_queue((struct wl_proxy*)mShmPool, -- aWaylandDisplay->GetEventQueue()); -+void WaylandShmPool::Release() { -+ if (mImageData != MAP_FAILED) { -+ munmap(mImageData, mAllocatedSize); -+ mImageData = MAP_FAILED; -+ } -+ if (mShmPool) { -+ wl_shm_pool_destroy(mShmPool); -+ mShmPool = 0; -+ } -+ if (mShmPoolFd >= 0) { -+ close(mShmPoolFd); -+ mShmPoolFd = -1; -+ } - } - --bool WaylandShmPool::Resize(int aSize) { -+bool WaylandShmPool::Create(RefPtr aWaylandDisplay, -+ int aSize) { - // We do size increase only -- if (aSize <= mAllocatedSize) return true; -- -- if (ftruncate(mShmPoolFd, aSize) < 0) return false; -+ if (aSize <= mAllocatedSize) { -+ return true; -+ } - --#ifdef HAVE_POSIX_FALLOCATE -- do { -- errno = posix_fallocate(mShmPoolFd, 0, aSize); -- } while (errno == EINTR); -- if (errno != 0) return false; --#endif -+ if (mShmPoolFd < 0) { -+ mShmPoolFd = WaylandAllocateShmMemory(aSize); -+ if (mShmPoolFd < 0) { -+ return false; -+ } -+ } else { -+ if (!WaylandReAllocateShmMemory(mShmPoolFd, aSize)) { -+ Release(); -+ return false; -+ } -+ } - -- wl_shm_pool_resize(mShmPool, aSize); -- -- munmap(mImageData, mAllocatedSize); -- -+ if (mImageData != MAP_FAILED) { -+ munmap(mImageData, mAllocatedSize); -+ } - mImageData = - mmap(nullptr, aSize, PROT_READ | PROT_WRITE, MAP_SHARED, mShmPoolFd, 0); -- if (mImageData == MAP_FAILED) return false; -+ if (mImageData == MAP_FAILED) { -+ NS_WARNING("Unable to map drawing surface!"); -+ Release(); -+ return false; -+ } -+ -+ if (mShmPool) { -+ wl_shm_pool_resize(mShmPool, aSize); -+ } else { -+ mShmPool = wl_shm_create_pool(aWaylandDisplay->GetShm(), mShmPoolFd, aSize); -+ // We set our queue to get mShmPool events at compositor thread. -+ wl_proxy_set_queue((struct wl_proxy*)mShmPool, -+ aWaylandDisplay->GetEventQueue()); -+ } - - mAllocatedSize = aSize; - return true; -@@ -289,11 +342,7 @@ void WaylandShmPool::SetImageDataFromPoo - memcpy(mImageData, aSourcePool->GetImageData(), aImageDataSize); - } - --WaylandShmPool::~WaylandShmPool() { -- munmap(mImageData, mAllocatedSize); -- wl_shm_pool_destroy(mShmPool); -- close(mShmPoolFd); --} -+WaylandShmPool::~WaylandShmPool() { Release(); } - - static void buffer_release(void* data, wl_buffer* buffer) { - auto surface = reinterpret_cast(data); -@@ -302,14 +351,14 @@ static void buffer_release(void* data, w - - static const struct wl_buffer_listener buffer_listener = {buffer_release}; - --void WindowBackBufferShm::Create(int aWidth, int aHeight) { -+bool WindowBackBufferShm::Create(int aWidth, int aHeight) { - MOZ_ASSERT(!IsAttached(), "We can't create attached buffers."); -- MOZ_ASSERT(!mWLBuffer, "there is wl_buffer already!"); - -- int newBufferSize = aWidth * aHeight * BUFFER_BPP; -- if (!mShmPool.Resize(newBufferSize)) { -- mWLBuffer = nullptr; -- return; -+ ReleaseShmSurface(); -+ -+ int size = aWidth * aHeight * BUFFER_BPP; -+ if (!mShmPool.Create(GetWaylandDisplay(), size)) { -+ return false; - } - - mWLBuffer = -@@ -325,14 +374,16 @@ void WindowBackBufferShm::Create(int aWi - LOGWAYLAND(("WindowBackBufferShm::Create [%p] wl_buffer %p ID %d\n", - (void*)this, (void*)mWLBuffer, - mWLBuffer ? wl_proxy_get_id((struct wl_proxy*)mWLBuffer) : -1)); -+ return true; - } - - void WindowBackBufferShm::ReleaseShmSurface() { - LOGWAYLAND(("WindowBackBufferShm::Release [%p]\n", (void*)this)); -- -- wl_buffer_destroy(mWLBuffer); -+ if (mWLBuffer) { -+ wl_buffer_destroy(mWLBuffer); -+ mWLBuffer = nullptr; -+ } - mWidth = mHeight = 0; -- mWLBuffer = nullptr; - } - - void WindowBackBufferShm::Clear() { -@@ -340,16 +391,13 @@ void WindowBackBufferShm::Clear() { - } - - WindowBackBufferShm::WindowBackBufferShm( -- WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth, int aHeight) -+ WindowSurfaceWayland* aWindowSurfaceWayland) - : WindowBackBuffer(aWindowSurfaceWayland), -- mShmPool(aWindowSurfaceWayland->GetWaylandDisplay(), -- aWidth * aHeight * BUFFER_BPP), -+ mShmPool(), - mWLBuffer(nullptr), -- mWidth(aWidth), -- mHeight(aHeight), -- mAttached(false) { -- Create(aWidth, aHeight); --} -+ mWidth(0), -+ mHeight(0), -+ mAttached(false) {} - - WindowBackBufferShm::~WindowBackBufferShm() { ReleaseShmSurface(); } - -@@ -357,13 +405,9 @@ bool WindowBackBufferShm::Resize(int aWi - if (aWidth == mWidth && aHeight == mHeight) { - return true; - } -- - LOGWAYLAND(("WindowBackBufferShm::Resize [%p] %d %d\n", (void*)this, aWidth, - aHeight)); -- -- ReleaseShmSurface(); - Create(aWidth, aHeight); -- - return (mWLBuffer != nullptr); - } - -@@ -488,11 +532,13 @@ WindowBackBuffer* WindowSurfaceWayland:: - return nullptr; - } - -- WindowBackBuffer* buffer = new WindowBackBufferShm(this, aWidth, aHeight); -- if (buffer) { -- mShmBackupBuffer[availableBuffer] = buffer; -+ WindowBackBuffer* buffer = new WindowBackBufferShm(this); -+ if (!buffer->Create(aWidth, aHeight)) { -+ delete buffer; -+ return nullptr; - } - -+ mShmBackupBuffer[availableBuffer] = buffer; - return buffer; - } - -diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h ---- a/widget/gtk/WindowSurfaceWayland.h -+++ b/widget/gtk/WindowSurfaceWayland.h -@@ -25,14 +25,14 @@ class WindowSurfaceWayland; - // Allocates and owns shared memory for Wayland drawing surface - class WaylandShmPool { - public: -- WaylandShmPool(RefPtr aDisplay, int aSize); -- ~WaylandShmPool(); -- -- bool Resize(int aSize); -+ bool Create(RefPtr aWaylandDisplay, int aSize); -+ void Release(); - wl_shm_pool* GetShmPool() { return mShmPool; }; - void* GetImageData() { return mImageData; }; - void SetImageDataFromPool(class WaylandShmPool* aSourcePool, - int aImageDataSize); -+ WaylandShmPool(); -+ ~WaylandShmPool(); - - private: - wl_shm_pool* mShmPool; -@@ -53,6 +53,7 @@ class WindowBackBuffer { - virtual bool IsAttached() = 0; - - virtual void Clear() = 0; -+ virtual bool Create(int aWidth, int aHeight) = 0; - virtual bool Resize(int aWidth, int aHeight) = 0; - - virtual int GetWidth() = 0; -@@ -87,8 +88,7 @@ class WindowBackBuffer { - - class WindowBackBufferShm : public WindowBackBuffer { - public: -- WindowBackBufferShm(WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth, -- int aHeight); -+ WindowBackBufferShm(WindowSurfaceWayland* aWindowSurfaceWayland); - ~WindowBackBufferShm(); - - already_AddRefed Lock(); -@@ -100,6 +100,7 @@ class WindowBackBufferShm : public Windo - void SetAttached() { mAttached = true; }; - - void Clear(); -+ bool Create(int aWidth, int aHeight); - bool Resize(int aWidth, int aHeight); - bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer); - -@@ -109,7 +110,6 @@ class WindowBackBufferShm : public Windo - wl_buffer* GetWlBuffer() { return mWLBuffer; }; - - private: -- void Create(int aWidth, int aHeight); - void ReleaseShmSurface(); - - // WaylandShmPool provides actual shared memory we draw into - diff --git a/mozilla-1700520.patch b/mozilla-1700520.patch deleted file mode 100644 index c93cbe2..0000000 --- a/mozilla-1700520.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff --git a/gfx/wr/swgl/src/blend.h b/gfx/wr/swgl/src/blend.h ---- a/gfx/wr/swgl/src/blend.h -+++ b/gfx/wr/swgl/src/blend.h -@@ -405,7 +405,7 @@ - blend_key = BlendKey(AA_BLEND_KEY_NONE + blend_key); - } - --static ALWAYS_INLINE WideRGBA8 blend_pixels(uint32_t* buf, PackedRGBA8 pdst, -+static PREFER_INLINE WideRGBA8 blend_pixels(uint32_t* buf, PackedRGBA8 pdst, - WideRGBA8 src, int span = 4) { - WideRGBA8 dst = unpack(pdst); - const WideRGBA8 RGB_MASK = {0xFFFF, 0xFFFF, 0xFFFF, 0, 0xFFFF, 0xFFFF, -@@ -686,7 +686,7 @@ - // clang-format on - } - --static ALWAYS_INLINE WideR8 blend_pixels(uint8_t* buf, WideR8 dst, WideR8 src, -+static PREFER_INLINE WideR8 blend_pixels(uint8_t* buf, WideR8 dst, WideR8 src, - int span = 4) { - // clang-format off - #define BLEND_CASE_KEY(key) \ -diff --git a/gfx/wr/swgl/src/gl.cc b/gfx/wr/swgl/src/gl.cc ---- a/gfx/wr/swgl/src/gl.cc -+++ b/gfx/wr/swgl/src/gl.cc -@@ -58,10 +58,24 @@ - } - - #else --# define ALWAYS_INLINE __attribute__((always_inline)) inline -+// GCC is slower when dealing with always_inline, especially in debug builds. -+// When using Clang, use always_inline more aggressively. -+# if defined(__clang__) || defined(NDEBUG) -+# define ALWAYS_INLINE __attribute__((always_inline)) inline -+# else -+# define ALWAYS_INLINE inline -+# endif - # define NO_INLINE __attribute__((noinline)) - #endif - -+// Some functions may cause excessive binary bloat if inlined in debug or with -+// GCC builds, so use PREFER_INLINE on these instead of ALWAYS_INLINE. -+#if defined(__clang__) && defined(NDEBUG) -+# define PREFER_INLINE ALWAYS_INLINE -+#else -+# define PREFER_INLINE inline -+#endif -+ - #define UNREACHABLE __builtin_unreachable() - - #define UNUSED [[maybe_unused]] - diff --git a/mozilla-1701089.patch b/mozilla-1701089.patch deleted file mode 100644 index af431f2..0000000 --- a/mozilla-1701089.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp ---- a/dom/media/gmp/GMPParent.cpp -+++ b/dom/media/gmp/GMPParent.cpp -@@ -884,7 +884,7 @@ - // - // Google's code to parse manifests can be used as a reference for strings - // the manifest may contain -- // https://cs.chromium.org/chromium/src/chrome/common/media/cdm_manifest.cc?l=73&rcl=393e60bfc2299449db7ef374c0ef1c324716e562 -+ // https://source.chromium.org/chromium/chromium/src/+/master:components/cdm/common/cdm_manifest.cc;l=74;drc=775880ced8a989191281e93854c7f2201f25068f - // - // Gecko's internal strings can be found at - // https://searchfox.org/mozilla-central/rev/ea63a0888d406fae720cf24f4727d87569a8cab5/dom/media/eme/MediaKeySystemAccess.cpp#149-155 -@@ -892,7 +892,8 @@ - nsCString codec; - if (chromiumCodec.EqualsASCII("vp8")) { - codec = "vp8"_ns; -- } else if (chromiumCodec.EqualsASCII("vp9.0")) { -+ } else if (chromiumCodec.EqualsASCII("vp9.0") || // Legacy string. -+ chromiumCodec.EqualsASCII("vp09")) { - codec = "vp9"_ns; - } else if (chromiumCodec.EqualsASCII("avc1")) { - codec = "h264"_ns; - diff --git a/mozilla-1753402.patch b/mozilla-1753402.patch deleted file mode 100644 index e53e73b..0000000 --- a/mozilla-1753402.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/tools/profiler/rust-api/build.rs b/tools/profiler/rust-api/build.rs ---- a/tools/profiler/rust-api/build.rs -+++ b/tools/profiler/rust-api/build.rs -@@ -61,6 +61,7 @@ - let mut builder = Builder::default() - .enable_cxx_namespaces() - .with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS | CodegenConfig::FUNCTIONS) -+ .disable_untagged_union() - .size_t_is_usize(true); - - for dir in SEARCH_PATHS.iter() { - diff --git a/mozilla-1758948.patch b/mozilla-1758948.patch deleted file mode 100644 index 7bc99e4..0000000 --- a/mozilla-1758948.patch +++ /dev/null @@ -1,28 +0,0 @@ -changeset: 623785:a6b80ee8c35f -tag: tip -parent: 623782:b1ed2fa50612 -user: stransky -date: Wed Jun 15 14:54:19 2022 +0200 -files: dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -description: -Bug 1758948 [FFmpeg] Use AVFrame::pts instead of AVFrame::pkt_pts on ffmpeg 4.x r?alwu - -AVFrame::pkt_pts has been deprecated and gives us wrong values for AV1 VA-API. Let's use AVFrame::pts instead on ffmpeg 4.x -as well as we use on ffmpeg 5.0 where AVFrame::pkt_pts is removed. - -Differential Revision: https://phabricator.services.mozilla.com/D149386 - - -diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp ---- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp -@@ -774,7 +774,7 @@ void FFmpegVideoDecoder::Init - #endif - - static int64_t GetFramePts(AVFrame* aFrame) { --#if LIBAVCODEC_VERSION_MAJOR > 58 -+#if LIBAVCODEC_VERSION_MAJOR > 57 - return aFrame->pts; - #else - return aFrame->pkt_pts; - diff --git a/mozilla-1774271.patch b/mozilla-1774271.patch deleted file mode 100644 index 6029b22..0000000 --- a/mozilla-1774271.patch +++ /dev/null @@ -1,31 +0,0 @@ -changeset: 623945:6117c9ecd16b -tag: tip -parent: 623941:45e313943df5 -user: stransky -date: Fri Jun 17 12:36:38 2022 +0200 -files: gfx/thebes/gfxPlatform.cpp -description: -Bug 1774271 [Linux] Don't use EGL_MESA_image_dma_buf_export in Mesa/Intel due to https://gitlab.freedesktop.org/mesa/mesa/-/issues/6688 r?jgilbert - -Depends on https://phabricator.services.mozilla.com/D149238 - -Differential Revision: https://phabricator.services.mozilla.com/D149608 - - -diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp ---- a/gfx/thebes/gfxPlatform.cpp -+++ b/gfx/thebes/gfxPlatform.cpp -@@ -2871,6 +2871,12 @@ void gfxPlatform::InitWebGLConfig() { - adapterDriverVendor.Find("radeonsi") != -1) { - gfxVars::SetUseDMABufSurfaceExport(false); - } -+ // Disable EGL_MESA_image_dma_buf_export on mesa/iris due to -+ // https://gitlab.freedesktop.org/mesa/mesa/-/issues/6688 -+ if (adapterDriverVendor.Find("mesa") != -1 && -+ adapterDriverVendor.Find("iris") != -1) { -+ gfxVars::SetUseDMABufSurfaceExport(false); -+ } - } - } - - diff --git a/mozilla-1885133.patch b/mozilla-1885133.patch deleted file mode 100644 index a73503a..0000000 --- a/mozilla-1885133.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/browser/components/shell/nsGNOMEShellDBusHelper.cpp b/browser/components/shell/nsGNOMEShellDBusHelper.cpp ---- a/browser/components/shell/nsGNOMEShellDBusHelper.cpp -+++ b/browser/components/shell/nsGNOMEShellDBusHelper.cpp -@@ -29,7 +29,7 @@ static bool GetGnomeSearchTitle(const ch - } - - AutoTArray formatStrings; -- CopyASCIItoUTF16(nsCString(aSearchedTerm), *formatStrings.AppendElement()); -+ CopyUTF8toUTF16(nsCString(aSearchedTerm), *formatStrings.AppendElement()); - - nsAutoString gnomeSearchTitle; - bundle->FormatStringFromName("gnomeSearchProviderSearch", formatStrings, -@@ -41,7 +41,7 @@ static bool GetGnomeSearchTitle(const ch - static const char* introspect_template = - "\n" -+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" - "\n" - " \n" - " \n" diff --git a/mozilla-440908.patch b/mozilla-440908.patch deleted file mode 100644 index cce5248..0000000 --- a/mozilla-440908.patch +++ /dev/null @@ -1,111 +0,0 @@ -diff -up firefox-56.0/modules/libpref/prefapi.cpp.440908 firefox-56.0/modules/libpref/prefapi.cpp ---- firefox-56.0/modules/libpref/prefapi.cpp.440908 2017-09-14 22:15:52.000000000 +0200 -+++ firefox-56.0/modules/libpref/prefapi.cpp 2017-09-25 10:39:39.266572792 +0200 -@@ -1036,8 +1036,8 @@ void PREF_ReaderCallback(void *clo - PrefValue value, - PrefType type, - bool isDefault, -- bool isStickyDefault) -- -+ bool isStickyDefault, -+ bool isLocked) - { - uint32_t flags = 0; - if (isDefault) { -@@ -1049,4 +1049,6 @@ void PREF_ReaderCallback(void *clo - flags |= kPrefForceSet; - } - pref_HashPref(pref, value, type, flags); -+ if (isLocked) -+ PREF_LockPref(pref, true); - } -diff -up firefox-56.0/modules/libpref/prefapi.h.440908 firefox-56.0/modules/libpref/prefapi.h ---- firefox-56.0/modules/libpref/prefapi.h.440908 2017-07-31 18:20:51.000000000 +0200 -+++ firefox-56.0/modules/libpref/prefapi.h 2017-09-25 10:39:39.267572789 +0200 -@@ -246,8 +246,8 @@ void PREF_ReaderCallback( void *closure, - PrefValue value, - PrefType type, - bool isDefault, -- bool isStickyDefault); -- -+ bool isStickyDefault, -+ bool isLocked); - - /* - * Callback whenever we change a preference -diff -up firefox-56.0/modules/libpref/prefread.cpp.440908 firefox-56.0/modules/libpref/prefread.cpp ---- firefox-56.0/modules/libpref/prefread.cpp.440908 2017-09-14 22:15:52.000000000 +0200 -+++ firefox-56.0/modules/libpref/prefread.cpp 2017-09-25 10:39:39.267572789 +0200 -@@ -43,6 +43,7 @@ enum { - #define BITS_PER_HEX_DIGIT 4 - - static const char kUserPref[] = "user_pref"; -+static const char kLockPref[] = "lockPref"; - static const char kPref[] = "pref"; - static const char kPrefSticky[] = "sticky_pref"; - static const char kTrue[] = "true"; -@@ -146,7 +147,7 @@ pref_DoCallback(PrefParseState *ps) - break; - } - (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault, -- ps->fstickydefault); -+ ps->fstickydefault, ps->flock); - return true; - } - -@@ -215,6 +216,7 @@ PREF_ParseBuf(PrefParseState *ps, const - ps->vtype = PrefType::Invalid; - ps->fdefault = false; - ps->fstickydefault = false; -+ ps->flock = false; - } - switch (c) { - case '/': /* begin comment block or line? */ -@@ -225,11 +227,14 @@ PREF_ParseBuf(PrefParseState *ps, const - break; - case 'u': /* indicating user_pref */ - case 's': /* indicating sticky_pref */ -+ case 'l': /* indicating lockPref */ - case 'p': /* indicating pref */ - if (c == 'u') { - ps->smatch = kUserPref; - } else if (c == 's') { - ps->smatch = kPrefSticky; -+ } else if (c == 'l') { -+ ps->smatch = kLockPref; - } else { - ps->smatch = kPref; - } -@@ -277,8 +282,10 @@ PREF_ParseBuf(PrefParseState *ps, const - /* name parsing */ - case PREF_PARSE_UNTIL_NAME: - if (c == '\"' || c == '\'') { -- ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky); -+ ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky -+ || ps->smatch == kLockPref); - ps->fstickydefault = (ps->smatch == kPrefSticky); -+ ps->flock = (ps->smatch == kLockPref); - ps->quotechar = c; - ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */ - state = PREF_PARSE_QUOTED_STRING; -diff -up firefox-56.0/modules/libpref/prefread.h.440908 firefox-56.0/modules/libpref/prefread.h ---- firefox-56.0/modules/libpref/prefread.h.440908 2017-09-14 22:15:52.000000000 +0200 -+++ firefox-56.0/modules/libpref/prefread.h 2017-09-25 10:39:39.267572789 +0200 -@@ -34,7 +34,8 @@ typedef void (*PrefReader)(void *c - PrefValue val, - PrefType type, - bool defPref, -- bool stickyPref); -+ bool stickyPref, -+ bool lockPref); - - /** - * Report any errors or warnings we encounter during parsing. -@@ -62,6 +63,7 @@ typedef struct PrefParseState { - PrefType vtype; /* PREF_STRING,INT,BOOL */ - bool fdefault; /* true if (default) pref */ - bool fstickydefault; /* true if (sticky) pref */ -+ bool flock; /* true if pref to be locked */ - } PrefParseState; - - /** diff --git a/rhbz-1400293-fix-mozilla-1324096.patch b/rhbz-1400293-fix-mozilla-1324096.patch deleted file mode 100644 index 4a2691e..0000000 --- a/rhbz-1400293-fix-mozilla-1324096.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp ---- a/security/certverifier/CertVerifier.cpp -+++ b/security/certverifier/CertVerifier.cpp -@@ -120,16 +120,20 @@ IsCertChainRootBuiltInRoot(const UniqueC - } - CERTCertificate* root = rootNode->cert; - if (!root) { - return Result::FATAL_ERROR_LIBRARY_FAILURE; - } - return IsCertBuiltInRoot(root, result); - } - -+// The term "builtin root" traditionally refers to a root CA certificate that -+// has been added to the NSS trust store, because it has been approved -+// for inclusion according to the Mozilla CA policy, and might be accepted -+// by Mozilla applications as an issuer for certificates seen on the public web. - Result - IsCertBuiltInRoot(CERTCertificate* cert, bool& result) - { - result = false; - #ifdef DEBUG - nsCOMPtr component(do_GetService(PSM_COMPONENT_CONTRACTID)); - if (!component) { - return Result::FATAL_ERROR_LIBRARY_FAILURE; -@@ -142,25 +146,38 @@ IsCertBuiltInRoot(CERTCertificate* cert, - return Success; - } - #endif // DEBUG - AutoSECMODListReadLock lock; - for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list; - list = list->next) { - for (int i = 0; i < list->module->slotCount; i++) { - PK11SlotInfo* slot = list->module->slots[i]; -- // PK11_HasRootCerts should return true if and only if the given slot has -- // an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST, which -- // should be true only of the builtin root list. -- // If we can find a copy of the given certificate on the slot with the -- // builtin root list, that certificate must be a builtin. -- if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot) && -- PK11_FindCertInSlot(slot, cert, nullptr) != CK_INVALID_HANDLE) { -- result = true; -- return Success; -+ // We're searching for the "builtin root module", which is a module that -+ // contains an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST. -+ // We use PK11_HasRootCerts() to identify a module with that property. -+ // In the past, we exclusively used the PKCS#11 module named nssckbi, -+ // which is provided by the NSS library. -+ // Nowadays, some distributions use a replacement module, which contains -+ // the builtin roots, but which also contains additional CA certificates, -+ // such as CAs trusted in a local deployment. -+ // We want to be able to distinguish between these two categories, -+ // because a CA, which may issue certificates for the public web, -+ // is expected to comply with additional requirements. -+ // If the certificate has attribute CKA_NSS_MOZILLA_CA_POLICY set to true, -+ // then we treat it as a "builtin root". -+ if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) { -+ CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, cert, nullptr); -+ if (handle != CK_INVALID_HANDLE && -+ PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY, -+ false)) { -+ // Attribute was found, and is set to true -+ result = true; -+ break; -+ } - } - } - } - return Success; - } - - static Result - BuildCertChainForOneKeyUsage(NSSCertDBTrustDomain& trustDomain, Input certDER, diff --git a/rust-thirdparty-checksum-fix.patch b/rust-thirdparty-checksum-fix.patch deleted file mode 100644 index 8047ea8..0000000 --- a/rust-thirdparty-checksum-fix.patch +++ /dev/null @@ -1,6 +0,0 @@ -diff -up firefox-72.0/third_party/rust/backtrace-sys/.cargo-checksum.json.checksum-fix firefox-72.0/third_party/rust/backtrace-sys/.cargo-checksum.json ---- firefox-72.0/third_party/rust/backtrace-sys/.cargo-checksum.json.checksum-fix 2020-01-07 10:55:14.265047927 +0100 -+++ firefox-72.0/third_party/rust/backtrace-sys/.cargo-checksum.json 2020-01-07 10:55:18.109059804 +0100 -@@ -1 +1 @@ --{"files":{"Cargo.toml":"d7b29a5b7e31bc0ffb83473b2f78041527903740402c1a6394329857045174f7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","build.rs":"0fe1e551ab35e7589f96979cf1d366561b62925e9c7da6249c25f25684ce9ede","src/lib.rs":"cb45ba047240bceac6ea74da50c2f48ae81a965b578c833a766a3ea0db1075f3","src/libbacktrace/LICENSE":"ef8a9b3247488f8901ca60de9b17b745d7bd67e5ec1e622f80d62364572200d8","src/libbacktrace/Makefile.am":"5353e0ce3a4732b42ccf031c474f7234336992cb23ba76cbfda3aa5262e69988","src/libbacktrace/Makefile.in":"1802d55fa8ef616a407c69311b3fa4e579093d124a215c834149ab1c50b4f3ad","src/libbacktrace/Mark.Twain-Tom.Sawyer.txt":"461eb7cb2d57d293fc680c836464c9125e4382be3596f7d415093ae9db8fcb0e","src/libbacktrace/README.md":"3b27ca2f7ddaf464ad81366a278ed4d34ad513de3766b330a51464828fa3131f","src/libbacktrace/acinclude.m4":"7f1d64805039b0e41d4c4106265618a6f8921d3cf091d64ab31fa7b900dc892f","src/libbacktrace/aclocal.m4":"4899cfe70722ba1de2b42b4e9965c1db1b173b5d6d4522cdc785becd5a5c212c","src/libbacktrace/alloc.c":"33891bbaf755c050058f8fd7dd3708e6062ef65245a0717216af45b78bab0fd0","src/libbacktrace/atomic.c":"82fd23c7ee7154d1ce4fc823637ede9cfa0e469f4073f38fff4dd9081070f1aa","src/libbacktrace/backtrace-supported.h.in":"42277f3c383386b6cfa3d3d889336e92303fac0ae1a9fb8a6a56737245dfb8f3","src/libbacktrace/backtrace.c":"837ea7b781a737d1ed37e4d03c463bcbe1432b2dc3b79b37344b21013cdfcca4","src/libbacktrace/backtrace.h":"9f035b3830c1c6000259c8ecf0bf53144f7c2e6064dfc95975b89f7f612ebf0e","src/libbacktrace/btest.c":"41c774496d58177e408b1dc33d6a792d0940634885978eed73fb192f732cafc5","src/libbacktrace/config.guess":"9be3de218833c076786b919dc34aab691611f4cd73316e7705f2673e2c41921b","src/libbacktrace/config.h.in":"b5002d9f96f6a26f54317f9d23a5ffff71fa3ee520fd8993810891d43b9a9bf7","src/libbacktrace/config.sub":"c8e70ab53f04d2f2b0280aa0e8a5432e90a902bfa2af7b0854168eb1fb3a84c0","src/libbacktrace/config/libtool.m4":"644ce34d5e9fcc544f3ef5c707f4cb29add798bbfc24e29932b55fb251e50353","src/libbacktrace/config/ltoptions.m4":"9d294950c4d97e2c891d472933113f397d410ef2a8ed875d714f81761626bbd8","src/libbacktrace/config/ltsugar.m4":"2c6618a04aa6389a2a528cde2e69ed5de55acc6c50892b486ea3e56e4e5b2c3b","src/libbacktrace/config/ltversion.m4":"8d129a46367fadad9f202dac50e708696d4d628313d01745127388e9c736e996","src/libbacktrace/config/lt~obsolete.m4":"c6c668594337aafef7d59f585bce7010436153815fe341461d81301a2235b959","src/libbacktrace/configure":"59763fc255248b54fba5d0761d61093a73d51fa4cb400b0df1b5f339b9c2f48a","src/libbacktrace/configure.ac":"b9292548330eb4d2cb014e9d9e6cd4df656aed982917365896a8f2534e9732e5","src/libbacktrace/dwarf.c":"c2103af5f94dd135e5df2a98dfc28ef2cbe0f3d56783d21e1487b9f314bfcbbc","src/libbacktrace/edtest.c":"947b9878ae45f6ba95d3b949bb080e9feed4ffdb27536cf5602b81ce79556ccf","src/libbacktrace/edtest2.c":"964bb0bb510a19013fb1cb56552929ed15cf55787eba4369d5820b74be07d249","src/libbacktrace/elf.c":"fe3e10d33c0c0965f016381302128ce82d664071095ad5077932377e3a789679","src/libbacktrace/fileline.c":"7b3b92044648f45becc498d4ed41ddc8ec08f0d11f6491cc05cfccd8a4d7627a","src/libbacktrace/filenames.h":"2c23cde7dd12dd9e0343cb37b5066036112deca703b61178f07c01f3e01398c9","src/libbacktrace/filetype.awk":"aa38776487a77dc13c93efa2a861204b384c3c4333501ed9bdb4ccbde2a784c0","src/libbacktrace/install-sh":"e7064b5e01a8d173409749c337966698fa04661cde1e3ef1a93be250eec0d2c3","src/libbacktrace/internal.h":"88c63ad6acc7e68330df3028675be4d4e3374bd787255fe22dd3febbbbc438b6","src/libbacktrace/ltmain.sh":"873bdcbc8690bd90c0f3632aac40027e880fd95ea45fb5a02ed901fea4afa4fe","src/libbacktrace/macho.c":"9a8864901eede4c34305b05bb6e815b25b76f04b59caf74381ca9dfbe8f1a8c4","src/libbacktrace/missing":"300bea3fb273b763eca2e4bb1576c663605d9b49de385fd375f82be8d912f506","src/libbacktrace/mmap.c":"5be917f3e9eba1fe49eb1bb391e28609e8377b4ce4593cace6012bf17434a33c","src/libbacktrace/mmapio.c":"be5719c4f92e70045fe6014a0493a5b4adc165ecde42c20130ea6e9da1ce978f","src/libbacktrace/move-if-change":"689762b92d23003926ba729acf98b9a109abf46de0698c09ddfa0d20490d8af5","src/libbacktrace/nounwind.c":"5eee9cc7298b7d0d2aea68eef62175541f34f88acf17736e0612056c5bb7318d","src/libbacktrace/pecoff.c":"bb536ae71a1a1c4dad5508d26032e7e81860df6d8ddfc8d696378ebefbc513b1","src/libbacktrace/posix.c":"f5e0ff701a1a1e29a25462ea49f174b049dafc6c25e040ee0eb77dd189353277","src/libbacktrace/print.c":"2d446406c8e2d9a1258d46d119be1c563bd86b6a4039cbf773b6de09c541390d","src/libbacktrace/read.c":"d0d4007f681f265a6c31e27ded45f4007502c90464eefdb4e80b69e4ae2ede28","src/libbacktrace/simple.c":"b0f767d3740195015aeadaa67e84bf6eb255a730f258485ca86bdbe02b066eca","src/libbacktrace/sort.c":"a82f911fc826a353ea5616379748dfa318ad4e57e20791af7ead853f7e73583d","src/libbacktrace/state.c":"a45abbe4077a47d17fb9687057c40828e633df12d21b8ed40b71a78d86918100","src/libbacktrace/stest.c":"7443fe435f1ee5ce49a3e634faf81a4137d66a057577fe88a211cfa819ddb2e2","src/libbacktrace/testlib.c":"a7e096e895b36db7f997a6673ce48f92a032046876511e813a8a52de6079b29a","src/libbacktrace/testlib.h":"02e02404dc89dd4f3dd82635f794a927541dd78d490d777bedf8a5424e5033fc","src/libbacktrace/ttest.c":"380f3b2be164bd6770768181fa05f1778cee8f0322434896d19724ae7cd105df","src/libbacktrace/unknown.c":"d2d148ea045dcad96ba1c5528b7036b000eeb8439ae397bca01deb0d8b287972","src/libbacktrace/xcoff.c":"e70ed97743306f71ea6132a058d68f1bb7be1380a2d38725b5dc877f5e07905d","src/libbacktrace/ztest.c":"7ad8277664e596aecb6af25818b7671e199ef6002ec2c38d9288179c5cad2082","symbol-map":"c81ced08aa32f0edb1d0ed6e4aaf5d3d516f8c158417d2ba3fa36b45b6ae08fd"},"package":"c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"} -+{"files":{"Cargo.toml":"d7b29a5b7e31bc0ffb83473b2f78041527903740402c1a6394329857045174f7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","build.rs":"0fe1e551ab35e7589f96979cf1d366561b62925e9c7da6249c25f25684ce9ede","src/lib.rs":"cb45ba047240bceac6ea74da50c2f48ae81a965b578c833a766a3ea0db1075f3","src/libbacktrace/LICENSE":"ef8a9b3247488f8901ca60de9b17b745d7bd67e5ec1e622f80d62364572200d8","src/libbacktrace/Makefile.am":"5353e0ce3a4732b42ccf031c474f7234336992cb23ba76cbfda3aa5262e69988","src/libbacktrace/Makefile.in":"1802d55fa8ef616a407c69311b3fa4e579093d124a215c834149ab1c50b4f3ad","src/libbacktrace/Mark.Twain-Tom.Sawyer.txt":"461eb7cb2d57d293fc680c836464c9125e4382be3596f7d415093ae9db8fcb0e","src/libbacktrace/README.md":"3b27ca2f7ddaf464ad81366a278ed4d34ad513de3766b330a51464828fa3131f","src/libbacktrace/acinclude.m4":"7f1d64805039b0e41d4c4106265618a6f8921d3cf091d64ab31fa7b900dc892f","src/libbacktrace/aclocal.m4":"4899cfe70722ba1de2b42b4e9965c1db1b173b5d6d4522cdc785becd5a5c212c","src/libbacktrace/alloc.c":"33891bbaf755c050058f8fd7dd3708e6062ef65245a0717216af45b78bab0fd0","src/libbacktrace/atomic.c":"82fd23c7ee7154d1ce4fc823637ede9cfa0e469f4073f38fff4dd9081070f1aa","src/libbacktrace/backtrace-supported.h.in":"42277f3c383386b6cfa3d3d889336e92303fac0ae1a9fb8a6a56737245dfb8f3","src/libbacktrace/backtrace.c":"837ea7b781a737d1ed37e4d03c463bcbe1432b2dc3b79b37344b21013cdfcca4","src/libbacktrace/backtrace.h":"9f035b3830c1c6000259c8ecf0bf53144f7c2e6064dfc95975b89f7f612ebf0e","src/libbacktrace/btest.c":"41c774496d58177e408b1dc33d6a792d0940634885978eed73fb192f732cafc5","src/libbacktrace/config.guess":"0913c6ce799fbfca156ae5fb55fc2e5950808b4d1435e71c6a8b768e54424052","src/libbacktrace/config.h.in":"b5002d9f96f6a26f54317f9d23a5ffff71fa3ee520fd8993810891d43b9a9bf7","src/libbacktrace/config.sub":"c8e70ab53f04d2f2b0280aa0e8a5432e90a902bfa2af7b0854168eb1fb3a84c0","src/libbacktrace/config/libtool.m4":"644ce34d5e9fcc544f3ef5c707f4cb29add798bbfc24e29932b55fb251e50353","src/libbacktrace/config/ltoptions.m4":"9d294950c4d97e2c891d472933113f397d410ef2a8ed875d714f81761626bbd8","src/libbacktrace/config/ltsugar.m4":"2c6618a04aa6389a2a528cde2e69ed5de55acc6c50892b486ea3e56e4e5b2c3b","src/libbacktrace/config/ltversion.m4":"8d129a46367fadad9f202dac50e708696d4d628313d01745127388e9c736e996","src/libbacktrace/config/lt~obsolete.m4":"c6c668594337aafef7d59f585bce7010436153815fe341461d81301a2235b959","src/libbacktrace/configure":"59763fc255248b54fba5d0761d61093a73d51fa4cb400b0df1b5f339b9c2f48a","src/libbacktrace/configure.ac":"b9292548330eb4d2cb014e9d9e6cd4df656aed982917365896a8f2534e9732e5","src/libbacktrace/dwarf.c":"c2103af5f94dd135e5df2a98dfc28ef2cbe0f3d56783d21e1487b9f314bfcbbc","src/libbacktrace/edtest.c":"947b9878ae45f6ba95d3b949bb080e9feed4ffdb27536cf5602b81ce79556ccf","src/libbacktrace/edtest2.c":"964bb0bb510a19013fb1cb56552929ed15cf55787eba4369d5820b74be07d249","src/libbacktrace/elf.c":"fe3e10d33c0c0965f016381302128ce82d664071095ad5077932377e3a789679","src/libbacktrace/fileline.c":"7b3b92044648f45becc498d4ed41ddc8ec08f0d11f6491cc05cfccd8a4d7627a","src/libbacktrace/filenames.h":"2c23cde7dd12dd9e0343cb37b5066036112deca703b61178f07c01f3e01398c9","src/libbacktrace/filetype.awk":"aa38776487a77dc13c93efa2a861204b384c3c4333501ed9bdb4ccbde2a784c0","src/libbacktrace/install-sh":"e7064b5e01a8d173409749c337966698fa04661cde1e3ef1a93be250eec0d2c3","src/libbacktrace/internal.h":"88c63ad6acc7e68330df3028675be4d4e3374bd787255fe22dd3febbbbc438b6","src/libbacktrace/ltmain.sh":"873bdcbc8690bd90c0f3632aac40027e880fd95ea45fb5a02ed901fea4afa4fe","src/libbacktrace/macho.c":"9a8864901eede4c34305b05bb6e815b25b76f04b59caf74381ca9dfbe8f1a8c4","src/libbacktrace/missing":"300bea3fb273b763eca2e4bb1576c663605d9b49de385fd375f82be8d912f506","src/libbacktrace/mmap.c":"5be917f3e9eba1fe49eb1bb391e28609e8377b4ce4593cace6012bf17434a33c","src/libbacktrace/mmapio.c":"be5719c4f92e70045fe6014a0493a5b4adc165ecde42c20130ea6e9da1ce978f","src/libbacktrace/move-if-change":"689762b92d23003926ba729acf98b9a109abf46de0698c09ddfa0d20490d8af5","src/libbacktrace/nounwind.c":"5eee9cc7298b7d0d2aea68eef62175541f34f88acf17736e0612056c5bb7318d","src/libbacktrace/pecoff.c":"bb536ae71a1a1c4dad5508d26032e7e81860df6d8ddfc8d696378ebefbc513b1","src/libbacktrace/posix.c":"f5e0ff701a1a1e29a25462ea49f174b049dafc6c25e040ee0eb77dd189353277","src/libbacktrace/print.c":"2d446406c8e2d9a1258d46d119be1c563bd86b6a4039cbf773b6de09c541390d","src/libbacktrace/read.c":"d0d4007f681f265a6c31e27ded45f4007502c90464eefdb4e80b69e4ae2ede28","src/libbacktrace/simple.c":"b0f767d3740195015aeadaa67e84bf6eb255a730f258485ca86bdbe02b066eca","src/libbacktrace/sort.c":"a82f911fc826a353ea5616379748dfa318ad4e57e20791af7ead853f7e73583d","src/libbacktrace/state.c":"a45abbe4077a47d17fb9687057c40828e633df12d21b8ed40b71a78d86918100","src/libbacktrace/stest.c":"7443fe435f1ee5ce49a3e634faf81a4137d66a057577fe88a211cfa819ddb2e2","src/libbacktrace/testlib.c":"a7e096e895b36db7f997a6673ce48f92a032046876511e813a8a52de6079b29a","src/libbacktrace/testlib.h":"02e02404dc89dd4f3dd82635f794a927541dd78d490d777bedf8a5424e5033fc","src/libbacktrace/ttest.c":"380f3b2be164bd6770768181fa05f1778cee8f0322434896d19724ae7cd105df","src/libbacktrace/unknown.c":"d2d148ea045dcad96ba1c5528b7036b000eeb8439ae397bca01deb0d8b287972","src/libbacktrace/xcoff.c":"e70ed97743306f71ea6132a058d68f1bb7be1380a2d38725b5dc877f5e07905d","src/libbacktrace/ztest.c":"7ad8277664e596aecb6af25818b7671e199ef6002ec2c38d9288179c5cad2082","symbol-map":"c81ced08aa32f0edb1d0ed6e4aaf5d3d516f8c158417d2ba3fa36b45b6ae08fd"},"package":"c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"}