summaryrefslogtreecommitdiffstats
path: root/dom/media/mediacontrol/tests/gtest
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /dom/media/mediacontrol/tests/gtest
parentInitial commit. (diff)
downloadfirefox-esr-upstream/115.8.0esr.tar.xz
firefox-esr-upstream/115.8.0esr.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/mediacontrol/tests/gtest')
-rw-r--r--dom/media/mediacontrol/tests/gtest/MediaKeyListenerTest.h39
-rw-r--r--dom/media/mediacontrol/tests/gtest/TestAudioFocusManager.cpp163
-rw-r--r--dom/media/mediacontrol/tests/gtest/TestMediaControlService.cpp64
-rw-r--r--dom/media/mediacontrol/tests/gtest/TestMediaController.cpp204
-rw-r--r--dom/media/mediacontrol/tests/gtest/TestMediaKeysEvent.cpp49
-rw-r--r--dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMac.mm136
-rw-r--r--dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMediaCenter.mm166
-rw-r--r--dom/media/mediacontrol/tests/gtest/moz.build23
8 files changed, 844 insertions, 0 deletions
diff --git a/dom/media/mediacontrol/tests/gtest/MediaKeyListenerTest.h b/dom/media/mediacontrol/tests/gtest/MediaKeyListenerTest.h
new file mode 100644
index 0000000000..5145eb7dbb
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/MediaKeyListenerTest.h
@@ -0,0 +1,39 @@
+/* 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 DOM_MEDIA_MEDIAKEYLISTENERTEST_H_
+#define DOM_MEDIA_MEDIAKEYLISTENERTEST_H_
+
+#include "MediaControlKeySource.h"
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+namespace dom {
+
+class MediaKeyListenerTest : public MediaControlKeyListener {
+ public:
+ NS_INLINE_DECL_REFCOUNTING(MediaKeyListenerTest, override)
+
+ void Clear() { mReceivedKey = mozilla::Nothing(); }
+
+ void OnActionPerformed(const MediaControlAction& aAction) override {
+ mReceivedKey = mozilla::Some(aAction.mKey);
+ }
+ bool IsResultEqualTo(MediaControlKey aResult) const {
+ if (mReceivedKey) {
+ return *mReceivedKey == aResult;
+ }
+ return false;
+ }
+ bool IsReceivedResult() const { return mReceivedKey.isSome(); }
+
+ private:
+ ~MediaKeyListenerTest() = default;
+ mozilla::Maybe<MediaControlKey> mReceivedKey;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // DOM_MEDIA_MEDIAKEYLISTENERTEST_H_
diff --git a/dom/media/mediacontrol/tests/gtest/TestAudioFocusManager.cpp b/dom/media/mediacontrol/tests/gtest/TestAudioFocusManager.cpp
new file mode 100644
index 0000000000..df1bb288a4
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/TestAudioFocusManager.cpp
@@ -0,0 +1,163 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "AudioFocusManager.h"
+#include "MediaControlService.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla::dom;
+
+#define FIRST_CONTROLLER_ID 0
+#define SECOND_CONTROLLER_ID 1
+
+// This RAII class is used to set the audio focus management pref within a test
+// and automatically revert the change when a test ends, in order not to
+// interfere other tests unexpectedly.
+class AudioFocusManagmentPrefSetterRAII {
+ public:
+ explicit AudioFocusManagmentPrefSetterRAII(bool aPrefValue) {
+ mOriginalValue = mozilla::Preferences::GetBool(mPrefName, false);
+ mozilla::Preferences::SetBool(mPrefName, aPrefValue);
+ }
+ ~AudioFocusManagmentPrefSetterRAII() {
+ mozilla::Preferences::SetBool(mPrefName, mOriginalValue);
+ }
+
+ private:
+ const char* mPrefName = "media.audioFocus.management";
+ bool mOriginalValue;
+};
+
+TEST(AudioFocusManager, TestRequestAudioFocus)
+{
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller = new MediaController(FIRST_CONTROLLER_ID);
+
+ manager.RequestAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RevokeAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+}
+
+TEST(AudioFocusManager, TestAudioFocusNumsWhenEnableAudioFocusManagement)
+{
+ // When enabling audio focus management, we only allow one controller owing
+ // audio focus at a time when the audio competing occurs. As the mechanism of
+ // handling the audio competing involves multiple components, we can't test it
+ // simply by using the APIs from AudioFocusManager.
+ AudioFocusManagmentPrefSetterRAII prefSetter(true);
+
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller1 =
+ new MediaController(FIRST_CONTROLLER_ID);
+
+ RefPtr<MediaController> controller2 =
+ new MediaController(SECOND_CONTROLLER_ID);
+
+ manager.RequestAudioFocus(controller1);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ // When controller2 starts, it would win the audio focus from controller1. So
+ // only one audio focus would exist.
+ manager.RequestAudioFocus(controller2);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RevokeAudioFocus(controller2);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+}
+
+TEST(AudioFocusManager, TestAudioFocusNumsWhenDisableAudioFocusManagement)
+{
+ // When disabling audio focus management, we won't handle the audio competing,
+ // so we allow multiple audio focus existing at the same time.
+ AudioFocusManagmentPrefSetterRAII prefSetter(false);
+
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller1 =
+ new MediaController(FIRST_CONTROLLER_ID);
+
+ RefPtr<MediaController> controller2 =
+ new MediaController(SECOND_CONTROLLER_ID);
+
+ manager.RequestAudioFocus(controller1);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RequestAudioFocus(controller2);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 2);
+
+ manager.RevokeAudioFocus(controller1);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RevokeAudioFocus(controller2);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+}
+
+TEST(AudioFocusManager, TestRequestAudioFocusRepeatedly)
+{
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller = new MediaController(FIRST_CONTROLLER_ID);
+
+ manager.RequestAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RequestAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+}
+
+TEST(AudioFocusManager, TestRevokeAudioFocusRepeatedly)
+{
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller = new MediaController(FIRST_CONTROLLER_ID);
+
+ manager.RequestAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RevokeAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ manager.RevokeAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+}
+
+TEST(AudioFocusManager, TestRevokeAudioFocusWithoutRequestAudioFocus)
+{
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller = new MediaController(FIRST_CONTROLLER_ID);
+
+ manager.RevokeAudioFocus(controller);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+}
+
+TEST(AudioFocusManager,
+ TestRevokeAudioFocusForControllerWithoutOwningAudioFocus)
+{
+ AudioFocusManager manager;
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 0);
+
+ RefPtr<MediaController> controller1 =
+ new MediaController(FIRST_CONTROLLER_ID);
+
+ RefPtr<MediaController> controller2 =
+ new MediaController(SECOND_CONTROLLER_ID);
+
+ manager.RequestAudioFocus(controller1);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+
+ manager.RevokeAudioFocus(controller2);
+ ASSERT_TRUE(manager.GetAudioFocusNums() == 1);
+}
diff --git a/dom/media/mediacontrol/tests/gtest/TestMediaControlService.cpp b/dom/media/mediacontrol/tests/gtest/TestMediaControlService.cpp
new file mode 100644
index 0000000000..ab5b0cb8c7
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/TestMediaControlService.cpp
@@ -0,0 +1,64 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "MediaControlService.h"
+#include "MediaController.h"
+
+using namespace mozilla::dom;
+
+#define FIRST_CONTROLLER_ID 0
+#define SECOND_CONTROLLER_ID 1
+
+TEST(MediaControlService, TestAddOrRemoveControllers)
+{
+ RefPtr<MediaControlService> service = MediaControlService::GetService();
+ ASSERT_TRUE(service->GetActiveControllersNum() == 0);
+
+ RefPtr<MediaController> controller1 =
+ new MediaController(FIRST_CONTROLLER_ID);
+ RefPtr<MediaController> controller2 =
+ new MediaController(SECOND_CONTROLLER_ID);
+
+ service->RegisterActiveMediaController(controller1);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 1);
+
+ service->RegisterActiveMediaController(controller2);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 2);
+
+ service->UnregisterActiveMediaController(controller1);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 1);
+
+ service->UnregisterActiveMediaController(controller2);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 0);
+}
+
+TEST(MediaControlService, TestMainController)
+{
+ RefPtr<MediaControlService> service = MediaControlService::GetService();
+ ASSERT_TRUE(service->GetActiveControllersNum() == 0);
+
+ RefPtr<MediaController> controller1 =
+ new MediaController(FIRST_CONTROLLER_ID);
+ service->RegisterActiveMediaController(controller1);
+
+ RefPtr<MediaController> mainController = service->GetMainController();
+ ASSERT_TRUE(mainController->Id() == FIRST_CONTROLLER_ID);
+
+ RefPtr<MediaController> controller2 =
+ new MediaController(SECOND_CONTROLLER_ID);
+ service->RegisterActiveMediaController(controller2);
+
+ mainController = service->GetMainController();
+ ASSERT_TRUE(mainController->Id() == SECOND_CONTROLLER_ID);
+
+ service->UnregisterActiveMediaController(controller2);
+ mainController = service->GetMainController();
+ ASSERT_TRUE(mainController->Id() == FIRST_CONTROLLER_ID);
+
+ service->UnregisterActiveMediaController(controller1);
+ mainController = service->GetMainController();
+ ASSERT_TRUE(service->GetActiveControllersNum() == 0);
+ ASSERT_TRUE(!mainController);
+}
diff --git a/dom/media/mediacontrol/tests/gtest/TestMediaController.cpp b/dom/media/mediacontrol/tests/gtest/TestMediaController.cpp
new file mode 100644
index 0000000000..5ba8d2a7d5
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/TestMediaController.cpp
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "MediaControlService.h"
+#include "MediaController.h"
+#include "mozilla/dom/MediaSessionBinding.h"
+
+using namespace mozilla::dom;
+
+#define CONTROLLER_ID 0
+#define FAKE_CONTEXT_ID 0
+
+#define FIRST_CONTROLLER_ID 0
+
+TEST(MediaController, DefaultValueCheck)
+{
+ RefPtr<MediaController> controller = new MediaController(CONTROLLER_ID);
+ ASSERT_TRUE(!controller->IsAnyMediaBeingControlled());
+ ASSERT_TRUE(controller->Id() == CONTROLLER_ID);
+ ASSERT_TRUE(controller->PlaybackState() == MediaSessionPlaybackState::None);
+ ASSERT_TRUE(!controller->IsAudible());
+}
+
+TEST(MediaController, IsAnyMediaBeingControlled)
+{
+ RefPtr<MediaController> controller = new MediaController(CONTROLLER_ID);
+ ASSERT_TRUE(!controller->IsAnyMediaBeingControlled());
+
+ controller->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::eStarted);
+ ASSERT_TRUE(controller->IsAnyMediaBeingControlled());
+
+ controller->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::eStarted);
+ ASSERT_TRUE(controller->IsAnyMediaBeingControlled());
+
+ controller->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::eStopped);
+ ASSERT_TRUE(controller->IsAnyMediaBeingControlled());
+
+ controller->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::eStopped);
+ ASSERT_TRUE(!controller->IsAnyMediaBeingControlled());
+}
+
+class FakeControlledMedia final {
+ public:
+ explicit FakeControlledMedia(MediaController* aController)
+ : mController(aController) {
+ mController->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::eStarted);
+ }
+
+ void SetPlaying(MediaPlaybackState aState) {
+ if (mPlaybackState == aState) {
+ return;
+ }
+ mController->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID, aState);
+ mPlaybackState = aState;
+ }
+
+ void SetAudible(MediaAudibleState aState) {
+ if (mAudibleState == aState) {
+ return;
+ }
+ mController->NotifyMediaAudibleChanged(FAKE_CONTEXT_ID, aState);
+ mAudibleState = aState;
+ }
+
+ ~FakeControlledMedia() {
+ if (mPlaybackState == MediaPlaybackState::ePlayed) {
+ mController->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::ePaused);
+ }
+ mController->NotifyMediaPlaybackChanged(FAKE_CONTEXT_ID,
+ MediaPlaybackState::eStopped);
+ }
+
+ private:
+ MediaPlaybackState mPlaybackState = MediaPlaybackState::eStopped;
+ MediaAudibleState mAudibleState = MediaAudibleState::eInaudible;
+ RefPtr<MediaController> mController;
+};
+
+TEST(MediaController, ActiveAndDeactiveController)
+{
+ RefPtr<MediaControlService> service = MediaControlService::GetService();
+ ASSERT_TRUE(service->GetActiveControllersNum() == 0);
+
+ RefPtr<MediaController> controller = new MediaController(FIRST_CONTROLLER_ID);
+
+ // In order to check active control number after FakeControlledMedia
+ // destroyed.
+ {
+ FakeControlledMedia fakeMedia(controller);
+ fakeMedia.SetPlaying(MediaPlaybackState::ePlayed);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 1);
+
+ fakeMedia.SetAudible(MediaAudibleState::eAudible);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 1);
+
+ fakeMedia.SetAudible(MediaAudibleState::eInaudible);
+ ASSERT_TRUE(service->GetActiveControllersNum() == 1);
+ }
+
+ ASSERT_TRUE(service->GetActiveControllersNum() == 0);
+}
+
+TEST(MediaController, AudibleChanged)
+{
+ RefPtr<MediaController> controller = new MediaController(CONTROLLER_ID);
+
+ FakeControlledMedia fakeMedia(controller);
+ fakeMedia.SetPlaying(MediaPlaybackState::ePlayed);
+ ASSERT_TRUE(!controller->IsAudible());
+
+ fakeMedia.SetAudible(MediaAudibleState::eAudible);
+ ASSERT_TRUE(controller->IsAudible());
+
+ fakeMedia.SetAudible(MediaAudibleState::eInaudible);
+ ASSERT_TRUE(!controller->IsAudible());
+}
+
+TEST(MediaController, PlayingStateChangeViaControlledMedia)
+{
+ RefPtr<MediaController> controller = new MediaController(CONTROLLER_ID);
+
+ // In order to check playing state after FakeControlledMedia destroyed.
+ {
+ FakeControlledMedia foo(controller);
+ ASSERT_TRUE(controller->PlaybackState() == MediaSessionPlaybackState::None);
+
+ foo.SetPlaying(MediaPlaybackState::ePlayed);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Playing);
+
+ foo.SetPlaying(MediaPlaybackState::ePaused);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Paused);
+
+ foo.SetPlaying(MediaPlaybackState::ePlayed);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Playing);
+ }
+
+ // FakeControlledMedia has been destroyed, no playing media exists.
+ ASSERT_TRUE(controller->PlaybackState() == MediaSessionPlaybackState::Paused);
+}
+
+TEST(MediaController, ControllerShouldRemainPlayingIfAnyPlayingMediaExists)
+{
+ RefPtr<MediaController> controller = new MediaController(CONTROLLER_ID);
+
+ {
+ FakeControlledMedia foo(controller);
+ ASSERT_TRUE(controller->PlaybackState() == MediaSessionPlaybackState::None);
+
+ foo.SetPlaying(MediaPlaybackState::ePlayed);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Playing);
+
+ // foo is playing, so controller is in `playing` state.
+ FakeControlledMedia bar(controller);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Playing);
+
+ bar.SetPlaying(MediaPlaybackState::ePlayed);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Playing);
+
+ // Although we paused bar, but foo is still playing, so the controller would
+ // still be in `playing`.
+ bar.SetPlaying(MediaPlaybackState::ePaused);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Playing);
+
+ foo.SetPlaying(MediaPlaybackState::ePaused);
+ ASSERT_TRUE(controller->PlaybackState() ==
+ MediaSessionPlaybackState::Paused);
+ }
+
+ // both foo and bar have been destroyed, no playing media exists.
+ ASSERT_TRUE(controller->PlaybackState() == MediaSessionPlaybackState::Paused);
+}
+
+TEST(MediaController, PictureInPictureModeOrFullscreen)
+{
+ RefPtr<MediaController> controller = new MediaController(CONTROLLER_ID);
+ ASSERT_TRUE(!controller->IsBeingUsedInPIPModeOrFullscreen());
+
+ controller->SetIsInPictureInPictureMode(FAKE_CONTEXT_ID, true);
+ ASSERT_TRUE(controller->IsBeingUsedInPIPModeOrFullscreen());
+
+ controller->SetIsInPictureInPictureMode(FAKE_CONTEXT_ID, false);
+ ASSERT_TRUE(!controller->IsBeingUsedInPIPModeOrFullscreen());
+
+ controller->NotifyMediaFullScreenState(FAKE_CONTEXT_ID, true);
+ ASSERT_TRUE(controller->IsBeingUsedInPIPModeOrFullscreen());
+
+ controller->NotifyMediaFullScreenState(FAKE_CONTEXT_ID, false);
+ ASSERT_TRUE(!controller->IsBeingUsedInPIPModeOrFullscreen());
+}
diff --git a/dom/media/mediacontrol/tests/gtest/TestMediaKeysEvent.cpp b/dom/media/mediacontrol/tests/gtest/TestMediaKeysEvent.cpp
new file mode 100644
index 0000000000..a73ceb8592
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/TestMediaKeysEvent.cpp
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "MediaController.h"
+#include "MediaControlKeySource.h"
+
+using namespace mozilla::dom;
+
+class MediaControlKeySourceTestImpl : public MediaControlKeySource {
+ public:
+ NS_INLINE_DECL_REFCOUNTING(MediaControlKeySourceTestImpl, override)
+ bool Open() override { return true; }
+ bool IsOpened() const override { return true; }
+ void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override {}
+
+ private:
+ ~MediaControlKeySourceTestImpl() = default;
+};
+
+TEST(MediaControlKey, TestAddOrRemoveListener)
+{
+ RefPtr<MediaControlKeySource> source = new MediaControlKeySourceTestImpl();
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaControlKeyListener> listener = new MediaControlKeyHandler();
+
+ source->AddListener(listener);
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+
+ source->RemoveListener(listener);
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+}
+
+TEST(MediaControlKey, SetSourcePlaybackState)
+{
+ RefPtr<MediaControlKeySource> source = new MediaControlKeySourceTestImpl();
+ ASSERT_TRUE(source->GetPlaybackState() == MediaSessionPlaybackState::None);
+
+ source->SetPlaybackState(MediaSessionPlaybackState::Playing);
+ ASSERT_TRUE(source->GetPlaybackState() == MediaSessionPlaybackState::Playing);
+
+ source->SetPlaybackState(MediaSessionPlaybackState::Paused);
+ ASSERT_TRUE(source->GetPlaybackState() == MediaSessionPlaybackState::Paused);
+
+ source->SetPlaybackState(MediaSessionPlaybackState::None);
+ ASSERT_TRUE(source->GetPlaybackState() == MediaSessionPlaybackState::None);
+}
diff --git a/dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMac.mm b/dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMac.mm
new file mode 100644
index 0000000000..3c8ce8cd9e
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMac.mm
@@ -0,0 +1,136 @@
+/* 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/. */
+
+#import <AppKit/AppKit.h>
+#import <AppKit/NSEvent.h>
+#import <ApplicationServices/ApplicationServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <IOKit/hidsystem/ev_keymap.h>
+
+#include "gtest/gtest.h"
+#include "MediaHardwareKeysEventSourceMac.h"
+#include "MediaKeyListenerTest.h"
+#include "mozilla/Maybe.h"
+
+using namespace mozilla::dom;
+using namespace mozilla::widget;
+
+static const int kSystemDefinedEventMediaKeysSubtype = 8;
+
+static void SendFakeEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource, int aKeyData) {
+ NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined
+ location:NSZeroPoint
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ subtype:kSystemDefinedEventMediaKeysSubtype
+ data1:aKeyData
+ data2:0];
+ aSource->EventTapCallback(nullptr, static_cast<CGEventType>(0), [event CGEvent], aSource.get());
+}
+
+static void NotifyFakeNonMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
+ bool aIsKeyPressed) {
+ int keyData = 0 | ((aIsKeyPressed ? 0xA : 0xB) << 8);
+ SendFakeEvent(aSource, keyData);
+}
+
+static void NotifyFakeMediaControlKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
+ MediaControlKey aEvent, bool aIsKeyPressed) {
+ int keyData = 0;
+ if (aEvent == MediaControlKey::Playpause) {
+ keyData = NX_KEYTYPE_PLAY << 16;
+ } else if (aEvent == MediaControlKey::Nexttrack) {
+ keyData = NX_KEYTYPE_NEXT << 16;
+ } else if (aEvent == MediaControlKey::Previoustrack) {
+ keyData = NX_KEYTYPE_PREVIOUS << 16;
+ }
+ keyData |= ((aIsKeyPressed ? 0xA : 0xB) << 8);
+ SendFakeEvent(aSource, keyData);
+}
+
+static void NotifyKeyPressedMediaKey(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
+ MediaControlKey aEvent) {
+ NotifyFakeMediaControlKey(aSource, aEvent, true /* key pressed */);
+}
+
+static void NotifyKeyReleasedMediaKeysEvent(RefPtr<MediaHardwareKeysEventSourceMac>& aSource,
+ MediaControlKey aEvent) {
+ NotifyFakeMediaControlKey(aSource, aEvent, false /* key released */);
+}
+
+static void NotifyKeyPressedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
+ NotifyFakeNonMediaKey(aSource, true /* key pressed */);
+}
+
+static void NotifyKeyReleasedNonMediaKeysEvents(RefPtr<MediaHardwareKeysEventSourceMac>& aSource) {
+ NotifyFakeNonMediaKey(aSource, false /* key released */);
+}
+
+TEST(MediaHardwareKeysEventSourceMac, TestKeyPressedMediaKeysEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+ source->AddListener(listener.get());
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ NotifyKeyPressedMediaKey(source, MediaControlKey::Playpause);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Playpause));
+
+ NotifyKeyPressedMediaKey(source, MediaControlKey::Nexttrack);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack));
+
+ NotifyKeyPressedMediaKey(source, MediaControlKey::Previoustrack);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Previoustrack));
+
+ source->RemoveListener(listener);
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+}
+
+TEST(MediaHardwareKeysEventSourceMac, TestKeyReleasedMediaKeysEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+ source->AddListener(listener.get());
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ NotifyKeyReleasedMediaKeysEvent(source, MediaControlKey::Playpause);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ NotifyKeyReleasedMediaKeysEvent(source, MediaControlKey::Nexttrack);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ NotifyKeyReleasedMediaKeysEvent(source, MediaControlKey::Previoustrack);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ source->RemoveListener(listener);
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+}
+
+TEST(MediaHardwareKeysEventSourceMac, TestNonMediaKeysEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMac> source = new MediaHardwareKeysEventSourceMac();
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+ source->AddListener(listener.get());
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ NotifyKeyPressedNonMediaKeysEvents(source);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ NotifyKeyReleasedNonMediaKeysEvents(source);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+
+ source->RemoveListener(listener);
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+}
diff --git a/dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMediaCenter.mm b/dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMediaCenter.mm
new file mode 100644
index 0000000000..1d32960d2f
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/TestMediaKeysEventMediaCenter.mm
@@ -0,0 +1,166 @@
+/* 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/. */
+#import <MediaPlayer/MediaPlayer.h>
+
+#include "gtest/gtest.h"
+#include "MediaHardwareKeysEventSourceMacMediaCenter.h"
+#include "MediaKeyListenerTest.h"
+#include "nsCocoaFeatures.h"
+#include "nsCocoaUtils.h"
+#include "prinrval.h"
+#include "prthread.h"
+
+using namespace mozilla::dom;
+using namespace mozilla::widget;
+
+NS_ASSUME_NONNULL_BEGIN
+
+TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPlayPauseEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMacMediaCenter> source =
+ new MediaHardwareKeysEventSourceMacMediaCenter();
+
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+
+ MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
+
+ source->AddListener(listener.get());
+
+ ASSERT_TRUE(source->Open());
+
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePlaying);
+
+ MediaCenterEventHandler playPauseHandler = source->CreatePlayPauseHandler();
+ playPauseHandler(nil);
+
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePaused);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Playpause));
+
+ listener->Clear(); // Reset stored media key
+
+ playPauseHandler(nil);
+
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePlaying);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Playpause));
+}
+
+TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPlayEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMacMediaCenter> source =
+ new MediaHardwareKeysEventSourceMacMediaCenter();
+
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+
+ MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
+
+ source->AddListener(listener.get());
+
+ ASSERT_TRUE(source->Open());
+
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePlaying);
+
+ MediaCenterEventHandler playHandler = source->CreatePlayHandler();
+
+ center.playbackState = MPNowPlayingPlaybackStatePaused;
+
+ playHandler(nil);
+
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePlaying);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Play));
+}
+
+TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPauseEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMacMediaCenter> source =
+ new MediaHardwareKeysEventSourceMacMediaCenter();
+
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+
+ MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
+
+ source->AddListener(listener.get());
+
+ ASSERT_TRUE(source->Open());
+
+ ASSERT_TRUE(source->GetListenersNum() == 1);
+ ASSERT_TRUE(!listener->IsReceivedResult());
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePlaying);
+
+ MediaCenterEventHandler pauseHandler = source->CreatePauseHandler();
+
+ pauseHandler(nil);
+
+ ASSERT_TRUE(center.playbackState == MPNowPlayingPlaybackStatePaused);
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Pause));
+}
+
+TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestMediaCenterPrevNextEvent)
+{
+ RefPtr<MediaHardwareKeysEventSourceMacMediaCenter> source =
+ new MediaHardwareKeysEventSourceMacMediaCenter();
+
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+
+ source->AddListener(listener.get());
+
+ ASSERT_TRUE(source->Open());
+
+ MediaCenterEventHandler nextHandler = source->CreateNextTrackHandler();
+
+ nextHandler(nil);
+
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Nexttrack));
+
+ MediaCenterEventHandler previousHandler = source->CreatePreviousTrackHandler();
+
+ previousHandler(nil);
+
+ ASSERT_TRUE(listener->IsResultEqualTo(MediaControlKey::Previoustrack));
+}
+
+TEST(MediaHardwareKeysEventSourceMacMediaCenter, TestSetMetadata)
+{
+ RefPtr<MediaHardwareKeysEventSourceMacMediaCenter> source =
+ new MediaHardwareKeysEventSourceMacMediaCenter();
+
+ ASSERT_TRUE(source->GetListenersNum() == 0);
+
+ RefPtr<MediaKeyListenerTest> listener = new MediaKeyListenerTest();
+
+ source->AddListener(listener.get());
+
+ ASSERT_TRUE(source->Open());
+
+ MediaMetadataBase metadata;
+ metadata.mTitle = u"MediaPlayback";
+ metadata.mArtist = u"Firefox";
+ metadata.mAlbum = u"Mozilla";
+ source->SetMediaMetadata(metadata);
+
+ // The update procedure of nowPlayingInfo is async, so wait for a second
+ // before checking the result.
+ PR_Sleep(PR_SecondsToInterval(1));
+ MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
+ ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyTitle] isEqualToString:@"MediaPlayback"]);
+ ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyArtist] isEqualToString:@"Firefox"]);
+ ASSERT_TRUE([center.nowPlayingInfo[MPMediaItemPropertyAlbumTitle] isEqualToString:@"Mozilla"]);
+
+ source->Close();
+ PR_Sleep(PR_SecondsToInterval(1));
+ ASSERT_TRUE(center.nowPlayingInfo == nil);
+}
+
+NS_ASSUME_NONNULL_END
diff --git a/dom/media/mediacontrol/tests/gtest/moz.build b/dom/media/mediacontrol/tests/gtest/moz.build
new file mode 100644
index 0000000000..7043bfcd5e
--- /dev/null
+++ b/dom/media/mediacontrol/tests/gtest/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ "TestAudioFocusManager.cpp",
+ "TestMediaController.cpp",
+ "TestMediaControlService.cpp",
+ "TestMediaKeysEvent.cpp",
+]
+
+if CONFIG["MOZ_APPLEMEDIA"]:
+ UNIFIED_SOURCES += ["TestMediaKeysEventMac.mm", "TestMediaKeysEventMediaCenter.mm"]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+LOCAL_INCLUDES += [
+ "/dom/media/mediacontrol",
+]
+
+FINAL_LIBRARY = "xul-gtest"