Source code

Revision control

Other Tools

/* -*- 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 */
#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
* 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 {
// Note that this constructor does NOT initialize the MPRIS Service but only
// this class. The method Open() is responsible for registering and MAY FAIL.
// 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.
MPRISServiceHandler() : mMimeType(IMAGE_PNG){};
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;
// 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;
GDBusNodeInfo* mIntrospectionData = nullptr;
GDBusConnection* mConnection = nullptr;
bool mInitialized = false;
nsAutoCString mIdentity;
nsAutoCString mDesktopEntry;
nsCString mMimeType;
// A bitmask indicating what keys are enabled
uint32_t mSupportedKeys = 0;
class MPRISMetadata : public dom::MediaMetadataBase {
MPRISMetadata() = default;
~MPRISMetadata() = default;
void UpdateFromMetadataBase(const dom::MediaMetadataBase& aMetadata) {
mTitle = aMetadata.mTitle;
mArtist = aMetadata.mArtist;
mAlbum = aMetadata.mAlbum;
mArtwork = aMetadata.mArtwork;
void Clear() {
nsCString mArtUrl;
MPRISMetadata mMPRISMetadata;
// The saved image file fetched from the URL
nsCOMPtr<nsIFile> mLocalImageFile;
nsCOMPtr<nsIFile> mLocalImageFolder;
mozilla::UniquePtr<mozilla::dom::FetchImageHelper> mImageFetcher;
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(mozilla::dom::MediaControlKey aKey,
bool aSupported) const;
bool EmitPropertiesChangedSignal(GVariant* aParameters) const;
void ClearMetadata();
} // namespace widget
} // namespace mozilla