mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Bug 1640998 - part7 : create MediaController
webidl. r=chunmin,smaug
This patch will - create a chrome-only webdil interface `MediaController` - expose supported keys via `MediaController` webidl interface The advantage of doing so are - to have a dedicated interface that is only used for MediaController that can be used for testing and our future plan (media hub) More Details : Currently, we access media controller's from `ChromeUtils` [1], but it causes a problem of creating a duplicated enum of the enum which we want to expose into Chrome JS. Instead, we should create a media controller interface to access all its attibutes, which is more easier and clean. In addition, we're planning to have a something like Chrome's media hub [2]. In order to do that, we have to expose some JS methods to allow us to control playback directly from Chrome JS. [1] https://searchfox.org/mozilla-central/rev/559b25eb41c1cbffcb90a34e008b8288312fcd25/dom/chrome-webidl/ChromeUtils.webidl#485-493 [2] https://blog.google/products/chrome/manage-audio-and-video-in-chrome/ Differential Revision: https://phabricator.services.mozilla.com/D77757
This commit is contained in:
parent
5aa603709c
commit
0d200dff8a
@ -148,6 +148,8 @@ interface CanonicalBrowsingContext : BrowsingContext {
|
||||
void loadURI(DOMString aURI, optional LoadURIOptions aOptions = {});
|
||||
|
||||
readonly attribute nsISHistory? sessionHistory;
|
||||
|
||||
readonly attribute MediaController? mediaController;
|
||||
};
|
||||
|
||||
[Exposed=Window, ChromeOnly]
|
||||
|
36
dom/chrome-webidl/MediaController.webidl
Normal file
36
dom/chrome-webidl/MediaController.webidl
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This enum lists all supported behaviors on the media controller.
|
||||
*/
|
||||
enum MediaControlKey {
|
||||
"focus",
|
||||
"play",
|
||||
"pause",
|
||||
"playpause",
|
||||
"previoustrack",
|
||||
"nexttrack",
|
||||
"seekbackward",
|
||||
"seekforward",
|
||||
"stop",
|
||||
};
|
||||
|
||||
/**
|
||||
* MediaController is used to control media playback for a tab, and each tab
|
||||
* would only have one media controller, which can be accessed from the
|
||||
* canonical browsing context.
|
||||
*/
|
||||
[Exposed=Window, ChromeOnly]
|
||||
interface MediaController : EventTarget {
|
||||
[Frozen, Cached, Pure]
|
||||
readonly attribute sequence<MediaControlKey> supportedKeys;
|
||||
|
||||
attribute EventHandler onsupportedkeyschange;
|
||||
|
||||
// TODO : expose other media controller methods to webidl in order to support
|
||||
// the plan of controlling media directly from the chrome JS.
|
||||
// eg. play(), pause().
|
||||
};
|
@ -56,6 +56,7 @@ WEBIDL_FILES = [
|
||||
'Localization.webidl',
|
||||
'MatchGlob.webidl',
|
||||
'MatchPattern.webidl',
|
||||
'MediaController.webidl',
|
||||
'MessageManager.webidl',
|
||||
'MozDocumentObserver.webidl',
|
||||
'MozSharedMap.webidl',
|
||||
|
@ -243,7 +243,7 @@ bool MediaControlService::ControllerManager::RemoveController(
|
||||
}
|
||||
// This is LinkedListElement's method which will remove controller from
|
||||
// `mController`.
|
||||
aController->remove();
|
||||
static_cast<LinkedListControllerPtr>(aController)->remove();
|
||||
// If main controller is removed from the list, the last controller in the
|
||||
// list would become the main controller. Or reset the main controller when
|
||||
// the list is already empty.
|
||||
@ -291,7 +291,7 @@ void MediaControlService::ControllerManager::ReorderGivenController(
|
||||
// controller would be B. But if we don't maintain the controller order when
|
||||
// main controller changes, we would pick C as the main controller because
|
||||
// the list is still [A, B, C].
|
||||
aController->remove();
|
||||
static_cast<LinkedListControllerPtr>(aController)->remove();
|
||||
return mControllers.insertBack(aController);
|
||||
}
|
||||
|
||||
@ -303,8 +303,9 @@ void MediaControlService::ControllerManager::ReorderGivenController(
|
||||
// a list [A, B, C, D, E] and E is the main controller. If we want to
|
||||
// reorder B to the front of E, then the list would become [A, C, D, B, E].
|
||||
MOZ_ASSERT(GetMainController() != aController);
|
||||
aController->remove();
|
||||
return GetMainController()->setPrevious(aController);
|
||||
static_cast<LinkedListControllerPtr>(aController)->remove();
|
||||
return static_cast<LinkedListControllerPtr>(GetMainController())
|
||||
->setPrevious(aController);
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,7 +381,14 @@ MediaController* MediaControlService::ControllerManager::GetMainController()
|
||||
}
|
||||
|
||||
uint64_t MediaControlService::ControllerManager::GetControllersNum() const {
|
||||
return mControllers.length();
|
||||
size_t length = 0;
|
||||
const auto* element =
|
||||
static_cast<ConstLinkedListControllerPtr>(mControllers.getFirst());
|
||||
while (element) {
|
||||
length++;
|
||||
element = element->getNext();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
bool MediaControlService::ControllerManager::Contains(
|
||||
|
@ -101,6 +101,9 @@ class MediaControlService final : public nsIObserver {
|
||||
~ControllerManager() = default;
|
||||
|
||||
using MediaKeysArray = nsTArray<MediaControlKeysEvent>;
|
||||
using LinkedListControllerPtr = LinkedListElement<RefPtr<MediaController>>*;
|
||||
using ConstLinkedListControllerPtr =
|
||||
const LinkedListElement<RefPtr<MediaController>>*;
|
||||
|
||||
bool AddController(MediaController* aController);
|
||||
bool RemoveController(MediaController* aController);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "MediaController.h"
|
||||
#include "MediaControlKeysEvent.h"
|
||||
#include "mozilla/dom/ChromeUtilsBinding.h"
|
||||
#include "mozilla/dom/MediaControllerBinding.h"
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
extern mozilla::LazyLogModule gMediaControlLog;
|
||||
@ -128,6 +129,32 @@ inline MediaSessionAction ConvertToMediaSessionAction(uint8_t aActionValue) {
|
||||
return static_cast<MediaSessionAction>(aActionValue);
|
||||
}
|
||||
|
||||
// TODO : merge `MediaControlKeysEvent` and `MediaControlKey`
|
||||
inline MediaControlKey ConvertToMediaControlKey(
|
||||
MediaControlKeysEvent aKeyEvent) {
|
||||
switch (aKeyEvent) {
|
||||
case MediaControlKeysEvent::eFocus:
|
||||
return MediaControlKey::Focus;
|
||||
case MediaControlKeysEvent::ePause:
|
||||
return MediaControlKey::Pause;
|
||||
case MediaControlKeysEvent::ePlay:
|
||||
return MediaControlKey::Play;
|
||||
case MediaControlKeysEvent::ePlayPause:
|
||||
return MediaControlKey::Playpause;
|
||||
case MediaControlKeysEvent::ePrevTrack:
|
||||
return MediaControlKey::Previoustrack;
|
||||
case MediaControlKeysEvent::eNextTrack:
|
||||
return MediaControlKey::Nexttrack;
|
||||
case MediaControlKeysEvent::eSeekBackward:
|
||||
return MediaControlKey::Seekbackward;
|
||||
case MediaControlKeysEvent::eSeekForward:
|
||||
return MediaControlKey::Seekforward;
|
||||
default:
|
||||
MOZ_ASSERT(aKeyEvent == MediaControlKeysEvent::eStop);
|
||||
return MediaControlKey::Stop;
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* ToMediaPlaybackStateStr(MediaPlaybackState aState) {
|
||||
switch (aState) {
|
||||
case MediaPlaybackState::eStarted:
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "MediaControlService.h"
|
||||
#include "MediaControlUtils.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
|
||||
@ -21,6 +22,32 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaController, DOMEventTargetHelper)
|
||||
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(MediaController,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MediaController,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
nsISupports* MediaController::GetParentObject() const {
|
||||
RefPtr<BrowsingContext> bc = BrowsingContext::Get(Id());
|
||||
return bc;
|
||||
}
|
||||
|
||||
JSObject* MediaController::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
return MediaController_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void MediaController::GetSupportedKeys(
|
||||
nsTArray<MediaControlKey>& aRetVal) const {
|
||||
aRetVal.Clear();
|
||||
for (const auto& key : mSupportedKeys) {
|
||||
// TODO : merge `MediaControlKey` and `MediaControlKeysEvent`.
|
||||
aRetVal.AppendElement(ConvertToMediaControlKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
static const MediaControlKeysEvent sDefaultSupportedKeys[] = {
|
||||
MediaControlKeysEvent::eFocus, MediaControlKeysEvent::ePlay,
|
||||
MediaControlKeysEvent::ePause, MediaControlKeysEvent::ePlayPause,
|
||||
@ -260,6 +287,10 @@ void MediaController::HandleSupportedMediaSessionActionsChanged(
|
||||
LOG("Supported keys changes");
|
||||
mSupportedKeys = newSupportedKeys;
|
||||
mSupportedKeysChangedEvent.Notify(mSupportedKeys);
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
|
||||
this, NS_LITERAL_STRING("supportedkeyschange"), CanBubble::eYes);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
MediaController_Binding::ClearCachedSupportedKeysValue(this);
|
||||
}
|
||||
|
||||
CopyableTArray<MediaControlKeysEvent> MediaController::GetSupportedMediaKeys()
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "MediaEventSource.h"
|
||||
#include "MediaPlaybackStatus.h"
|
||||
#include "MediaStatusManager.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/MediaControllerBinding.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
@ -66,15 +68,23 @@ class IMediaController {
|
||||
* tabs playing media at the same time, we can use the ID to query the specific
|
||||
* controller from `MediaControlService`.
|
||||
*/
|
||||
class MediaController final
|
||||
: public IMediaController,
|
||||
public MediaStatusManager,
|
||||
public LinkedListElement<RefPtr<MediaController>> {
|
||||
class MediaController final : public DOMEventTargetHelper,
|
||||
public IMediaController,
|
||||
public LinkedListElement<RefPtr<MediaController>>,
|
||||
public MediaStatusManager {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaController, override);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MediaController,
|
||||
DOMEventTargetHelper)
|
||||
explicit MediaController(uint64_t aBrowsingContextId);
|
||||
|
||||
// WebIDL methods
|
||||
nsISupports* GetParentObject() const;
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
void GetSupportedKeys(nsTArray<MediaControlKey>& aRetVal) const;
|
||||
IMPL_EVENT_HANDLER(supportedkeyschange);
|
||||
|
||||
// IMediaController's methods
|
||||
void Focus() override;
|
||||
void Play() override;
|
||||
|
@ -2380,6 +2380,9 @@ STATIC_ATOMS = [
|
||||
Atom("onmark", "onmark"),
|
||||
Atom("onboundary", "onboundary"),
|
||||
|
||||
# Media Controller
|
||||
Atom("onsupportedkeyschange", "onsupportedkeyschange"),
|
||||
|
||||
# Contextual Identity / Containers
|
||||
Atom("usercontextid", "usercontextid"),
|
||||
Atom("geckoViewSessionContextId", "geckoViewSessionContextId"),
|
||||
|
Loading…
Reference in New Issue
Block a user