1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef WIDGET_GTK_MPRIS_SERVICE_HANDLER_H_ 8 #define WIDGET_GTK_MPRIS_SERVICE_HANDLER_H_ 9 10 #include <gio/gio.h> 11 #include "mozilla/dom/FetchImageHelper.h" 12 #include "mozilla/dom/MediaControlKeySource.h" 13 #include "mozilla/Attributes.h" 14 #include "mozilla/UniquePtr.h" 15 #include "nsIFile.h" 16 #include "nsMimeTypes.h" 17 #include "nsString.h" 18 19 #define DBUS_MPRIS_SERVICE_NAME "org.mpris.MediaPlayer2.firefox" 20 #define DBUS_MPRIS_OBJECT_PATH "/org/mpris/MediaPlayer2" 21 #define DBUS_MPRIS_INTERFACE "org.mpris.MediaPlayer2" 22 #define DBUS_MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player" 23 #define DBUS_MPRIS_TRACK_PATH "/org/mpris/MediaPlayer2/firefox" 24 25 namespace mozilla { 26 namespace widget { 27 28 /** 29 * This class implements the "MPRIS" D-Bus Service 30 * (https://specifications.freedesktop.org/mpris-spec/2.2), 31 * which is used to communicate with the Desktop Environment about the 32 * Multimedia playing in Gecko. 33 * Note that this interface requires many methods which may not be supported by 34 * Gecko, the interface 35 * however provides CanXYZ properties for these methods, so the method is 36 * defined but won't be executed. 37 * 38 * Also note that the following defines are for parts that the MPRIS Spec 39 * defines optional. The code won't 40 * compile with any of the defines set, yet, as those aren't implemented yet and 41 * probably never will be of 42 * use for gecko. For sake of completeness, they have been added until the 43 * decision about their implementation 44 * is finally made. 45 * 46 * The constexpr'ed methods are capabilities of the user agent known at compile 47 * time, e.g. we decided at 48 * compile time whether we ever want to support closing the user agent via MPRIS 49 * (Quit() and CanQuit()). 50 * 51 * Other properties like CanPlay() might depend on the runtime state (is there 52 * media available for playback?) 53 * and thus aren't a constexpr but merely a const method. 54 */ 55 class MPRISServiceHandler final : public dom::MediaControlKeySource { NS_INLINE_DECL_REFCOUNTING(MPRISServiceHandler,override)56 NS_INLINE_DECL_REFCOUNTING(MPRISServiceHandler, override) 57 public: 58 // Note that this constructor does NOT initialize the MPRIS Service but only 59 // this class. The method Open() is responsible for registering and MAY FAIL. 60 61 // The image format used in MPRIS is based on the mMimeType here. Although 62 // IMAGE_JPEG or IMAGE_BMP are valid types as well but a png image with 63 // transparent background will be converted into a jpeg/bmp file with a 64 // colored background IMAGE_PNG format seems to be the best choice for now. 65 MPRISServiceHandler() : mMimeType(IMAGE_PNG){}; 66 bool Open() override; 67 void Close() override; 68 bool IsOpened() const override; 69 70 // From the EventSource. 71 void SetPlaybackState(dom::MediaSessionPlaybackState aState) override; 72 73 // GetPlaybackState returns dom::PlaybackState. GetPlaybackStatus returns this 74 // state converted into d-bus variants. 75 GVariant* GetPlaybackStatus() const; 76 77 const char* Identity() const; 78 const char* DesktopEntry() const; 79 bool PressKey(dom::MediaControlKey aKey) const; 80 81 void SetMediaMetadata(const dom::MediaMetadataBase& aMetadata) override; 82 GVariant* GetMetadataAsGVariant() const; 83 84 void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override; 85 86 bool IsMediaKeySupported(dom::MediaControlKey aKey) const; 87 88 private: 89 ~MPRISServiceHandler(); 90 91 // Note: Registration Ids for the D-Bus start with 1, so a value of 0 92 // indicates an error (or an object which wasn't initialized yet) 93 94 // a handle to our bus registration/ownership 95 guint mOwnerId = 0; 96 // This is for the interface org.mpris.MediaPlayer2 97 guint mRootRegistrationId = 0; 98 // This is for the interface org.mpris.MediaPlayer2.Player 99 guint mPlayerRegistrationId = 0; 100 GDBusNodeInfo* mIntrospectionData = nullptr; 101 GDBusConnection* mConnection = nullptr; 102 bool mInitialized = false; 103 nsAutoCString mIdentity; 104 nsAutoCString mDesktopEntry; 105 106 nsCString mMimeType; 107 108 // A bitmask indicating what keys are enabled 109 uint32_t mSupportedKeys = 0; 110 111 class MPRISMetadata : public dom::MediaMetadataBase { 112 public: 113 MPRISMetadata() = default; 114 ~MPRISMetadata() = default; 115 UpdateFromMetadataBase(const dom::MediaMetadataBase & aMetadata)116 void UpdateFromMetadataBase(const dom::MediaMetadataBase& aMetadata) { 117 mTitle = aMetadata.mTitle; 118 mArtist = aMetadata.mArtist; 119 mAlbum = aMetadata.mAlbum; 120 mArtwork = aMetadata.mArtwork; 121 } Clear()122 void Clear() { 123 UpdateFromMetadataBase(MediaMetadataBase::EmptyData()); 124 mArtUrl.Truncate(); 125 } 126 127 nsCString mArtUrl; 128 }; 129 MPRISMetadata mMPRISMetadata; 130 131 // The saved image file fetched from the URL 132 nsCOMPtr<nsIFile> mLocalImageFile; 133 nsCOMPtr<nsIFile> mLocalImageFolder; 134 135 mozilla::UniquePtr<mozilla::dom::FetchImageHelper> mImageFetcher; 136 mozilla::MozPromiseRequestHolder<mozilla::dom::ImagePromise> 137 mImageFetchRequest; 138 139 nsString mFetchingUrl; 140 nsString mCurrentImageUrl; 141 142 size_t mNextImageIndex = 0; 143 144 // Load the image at index aIndex of the metadta's artwork to MPRIS 145 // asynchronously 146 void LoadImageAtIndex(const size_t aIndex); 147 bool SetImageToDisplay(const char* aImageData, uint32_t aDataSize); 148 149 bool RenewLocalImageFile(const char* aImageData, uint32_t aDataSize); 150 bool InitLocalImageFile(); 151 bool InitLocalImageFolder(); 152 void RemoveAllLocalImages(); 153 bool LocalImageFolderExists(); 154 155 // Queries nsAppInfo to get the branded browser name and vendor 156 void InitIdentity(); 157 158 // non-public API, called from events 159 void OnNameAcquired(GDBusConnection* aConnection, const gchar* aName); 160 void OnNameLost(GDBusConnection* aConnection, const gchar* aName); 161 void OnBusAcquired(GDBusConnection* aConnection, const gchar* aName); 162 163 static void OnNameAcquiredStatic(GDBusConnection* aConnection, 164 const gchar* aName, gpointer aUserData); 165 static void OnNameLostStatic(GDBusConnection* aConnection, const gchar* aName, 166 gpointer aUserData); 167 static void OnBusAcquiredStatic(GDBusConnection* aConnection, 168 const gchar* aName, gpointer aUserData); 169 170 void EmitEvent(dom::MediaControlKey aKey) const; 171 172 bool EmitMetadataChanged() const; 173 174 void SetMediaMetadataInternal(const dom::MediaMetadataBase& aMetadata, 175 bool aClearArtUrl = true); 176 177 bool EmitSupportedKeyChanged(mozilla::dom::MediaControlKey aKey, 178 bool aSupported) const; 179 180 bool EmitPropertiesChangedSignal(GVariant* aParameters) const; 181 182 void ClearMetadata(); 183 }; 184 185 } // namespace widget 186 } // namespace mozilla 187 188 #endif // WIDGET_GTK_MPRIS_SERVICE_HANDLER_H_ 189