diff options
Diffstat (limited to 'widget/gtk/MPRISServiceHandler.h')
-rw-r--r-- | widget/gtk/MPRISServiceHandler.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/widget/gtk/MPRISServiceHandler.h b/widget/gtk/MPRISServiceHandler.h new file mode 100644 index 0000000000..f2b171c87e --- /dev/null +++ b/widget/gtk/MPRISServiceHandler.h @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef WIDGET_GTK_MPRIS_SERVICE_HANDLER_H_ +#define WIDGET_GTK_MPRIS_SERVICE_HANDLER_H_ + +#include <gio/gio.h> +#include "mozilla/dom/FetchImageHelper.h" +#include "mozilla/dom/MediaControlKeySource.h" +#include "mozilla/Attributes.h" +#include "mozilla/UniquePtr.h" +#include "nsIFile.h" +#include "nsMimeTypes.h" +#include "nsString.h" + +#define DBUS_MPRIS_SERVICE_NAME "org.mpris.MediaPlayer2.firefox" +#define DBUS_MPRIS_OBJECT_PATH "/org/mpris/MediaPlayer2" +#define DBUS_MPRIS_INTERFACE "org.mpris.MediaPlayer2" +#define DBUS_MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player" +#define DBUS_MPRIS_TRACK_PATH "/org/mpris/MediaPlayer2/firefox" + +namespace mozilla { +namespace widget { + +/** + * This class implements the "MPRIS" D-Bus Service + * (https://specifications.freedesktop.org/mpris-spec/2.2), + * which is used to communicate with the Desktop Environment about the + * Multimedia playing in Gecko. + * Note that this interface requires many methods which may not be supported by + * Gecko, the interface + * however provides CanXYZ properties for these methods, so the method is + * defined but won't be executed. + * + * Also note that the following defines are for parts that the MPRIS Spec + * defines optional. The code won't + * compile with any of the defines set, yet, as those aren't implemented yet and + * probably never will be of + * use for gecko. For sake of completeness, they have been added until the + * decision about their implementation + * is finally made. + * + * The constexpr'ed methods are capabilities of the user agent known at compile + * time, e.g. we decided at + * compile time whether we ever want to support closing the user agent via MPRIS + * (Quit() and CanQuit()). + * + * Other properties like CanPlay() might depend on the runtime state (is there + * media available for playback?) + * and thus aren't a constexpr but merely a const method. + */ +class MPRISServiceHandler final : public dom::MediaControlKeySource { + NS_INLINE_DECL_REFCOUNTING(MPRISServiceHandler, override) + public: + // Note that this constructor does NOT initialize the MPRIS Service but only + // this class. The method Open() is responsible for registering and MAY FAIL. + + MPRISServiceHandler(); + bool Open() override; + void Close() override; + bool IsOpened() const override; + + // From the EventSource. + void SetPlaybackState(dom::MediaSessionPlaybackState aState) override; + + // GetPlaybackState returns dom::PlaybackState. GetPlaybackStatus returns this + // state converted into d-bus variants. + GVariant* GetPlaybackStatus() const; + + const char* Identity() const; + const char* DesktopEntry() const; + bool PressKey(dom::MediaControlKey aKey) const; + + void SetMediaMetadata(const dom::MediaMetadataBase& aMetadata) override; + GVariant* GetMetadataAsGVariant() const; + + void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override; + + bool IsMediaKeySupported(dom::MediaControlKey aKey) const; + + private: + ~MPRISServiceHandler(); + + // Note: Registration Ids for the D-Bus start with 1, so a value of 0 + // indicates an error (or an object which wasn't initialized yet) + + // a handle to our bus registration/ownership + guint mOwnerId = 0; + // This is for the interface org.mpris.MediaPlayer2 + guint mRootRegistrationId = 0; + // This is for the interface org.mpris.MediaPlayer2.Player + guint mPlayerRegistrationId = 0; + RefPtr<GDBusNodeInfo> mIntrospectionData; + GDBusConnection* mConnection = nullptr; + bool mInitialized = false; + nsAutoCString mIdentity; + nsAutoCString mDesktopEntry; + + // The image format used in MPRIS is based on the mMimeType here. Although + // IMAGE_JPEG or IMAGE_BMP are valid types as well but a png image with + // transparent background will be converted into a jpeg/bmp file with a + // colored background IMAGE_PNG format seems to be the best choice for now. + nsCString mMimeType{IMAGE_PNG}; + + // A bitmask indicating what keys are enabled + uint32_t mSupportedKeys = 0; + + class MPRISMetadata : public dom::MediaMetadataBase { + public: + MPRISMetadata() = default; + ~MPRISMetadata() = default; + + void UpdateFromMetadataBase(const dom::MediaMetadataBase& aMetadata) { + mTitle = aMetadata.mTitle; + mArtist = aMetadata.mArtist; + mAlbum = aMetadata.mAlbum; + mArtwork = aMetadata.mArtwork; + } + void Clear() { + UpdateFromMetadataBase(MediaMetadataBase::EmptyData()); + mArtUrl.Truncate(); + } + + nsCString mArtUrl; + }; + MPRISMetadata mMPRISMetadata; + + // The saved image file fetched from the URL + nsCOMPtr<nsIFile> mLocalImageFile; + nsCOMPtr<nsIFile> mLocalImageFolder; + + UniquePtr<dom::FetchImageHelper> mImageFetcher; + MozPromiseRequestHolder<dom::ImagePromise> mImageFetchRequest; + + nsString mFetchingUrl; + nsString mCurrentImageUrl; + + size_t mNextImageIndex = 0; + + // Load the image at index aIndex of the metadta's artwork to MPRIS + // asynchronously + void LoadImageAtIndex(const size_t aIndex); + bool SetImageToDisplay(const char* aImageData, uint32_t aDataSize); + + bool RenewLocalImageFile(const char* aImageData, uint32_t aDataSize); + bool InitLocalImageFile(); + bool InitLocalImageFolder(); + void RemoveAllLocalImages(); + bool LocalImageFolderExists(); + + // Queries nsAppInfo to get the branded browser name and vendor + void InitIdentity(); + + // non-public API, called from events + void OnNameAcquired(GDBusConnection* aConnection, const gchar* aName); + void OnNameLost(GDBusConnection* aConnection, const gchar* aName); + void OnBusAcquired(GDBusConnection* aConnection, const gchar* aName); + + static void OnNameAcquiredStatic(GDBusConnection* aConnection, + const gchar* aName, gpointer aUserData); + static void OnNameLostStatic(GDBusConnection* aConnection, const gchar* aName, + gpointer aUserData); + static void OnBusAcquiredStatic(GDBusConnection* aConnection, + const gchar* aName, gpointer aUserData); + + void EmitEvent(dom::MediaControlKey aKey) const; + + bool EmitMetadataChanged() const; + + void SetMediaMetadataInternal(const dom::MediaMetadataBase& aMetadata, + bool aClearArtUrl = true); + + bool EmitSupportedKeyChanged(dom::MediaControlKey aKey, + bool aSupported) const; + + bool EmitPropertiesChangedSignal(GVariant* aParameters) const; + + void ClearMetadata(); +}; + +} // namespace widget +} // namespace mozilla + +#endif // WIDGET_GTK_MPRIS_SERVICE_HANDLER_H_ |