Bug 1623486 - part2 : update main controller when controller starts being used in Picture-in-Picture mode. r=chunmin

We would like to ensure that the controller being used in Picture-in-Picture mode can always be the main controller, which means even if there are other controllers starting later than PIP video, they are not able to become the main controller, but we would still maintain a correct order of controllers that can ensure that the main controller can be selected correctly after current main controller get destroyed.

For example, we have a list `[A, B, C]` and `C` is the main controller. And `D` is new coming controller, then the list would become `[A, B, D, C]` and `C` is still the main controller. But if `C` gets destroyed, the list would become `[A, B, D]` and `D` is the main controller.

Differential Revision: https://phabricator.services.mozilla.com/D67710

--HG--
extra : moz-landing-system : lando
This commit is contained in:
alwu 2020-03-26 23:35:50 +00:00
Родитель f9aaf98cd6
Коммит 9ec32fbe45
3 изменённых файлов: 92 добавлений и 19 удалений

Просмотреть файл

@ -150,10 +150,23 @@ void MediaControlService::NotifyControllerPlaybackStateChanged(
// be playing at the time.
if (GetMainController() != aController &&
aController->GetState() == MediaSessionPlaybackState::Playing) {
mControllerManager->UpdateMainController(aController);
mControllerManager->UpdateMainControllerIfNeeded(aController);
}
}
void MediaControlService::NotifyControllerBeingUsedInPictureInPictureMode(
MediaController* aController) {
MOZ_DIAGNOSTIC_ASSERT(aController);
MOZ_DIAGNOSTIC_ASSERT(
mControllerManager,
"using controller in PIP mode before initializing service");
// The controller is not an active controller.
if (!mControllerManager->Contains(aController)) {
return;
}
mControllerManager->UpdateMainControllerIfNeeded(aController);
}
uint64_t MediaControlService::GetActiveControllersNum() const {
MOZ_DIAGNOSTIC_ASSERT(mControllerManager);
return mControllerManager->GetControllersNum();
@ -204,7 +217,7 @@ bool MediaControlService::ControllerManager::AddController(
return false;
}
mControllers.insertBack(aController);
UpdateMainControllerInternal(aController);
UpdateMainControllerIfNeeded(aController);
return true;
}
@ -217,29 +230,68 @@ bool MediaControlService::ControllerManager::RemoveController(
// This is LinkedListElement's method which will remove controller from
// `mController`.
aController->remove();
UpdateMainControllerInternal(mControllers.isEmpty() ? nullptr
: mControllers.getLast());
// 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.
if (GetMainController() == aController) {
UpdateMainControllerInternal(
mControllers.isEmpty() ? nullptr : mControllers.getLast());
}
return true;
}
void MediaControlService::ControllerManager::UpdateMainController(
void MediaControlService::ControllerManager::UpdateMainControllerIfNeeded(
MediaController* aController) {
MOZ_DIAGNOSTIC_ASSERT(aController);
if (GetMainController() == aController) {
LOG_MAINCONTROLLER("This controller is alreay the main controller");
return;
}
if (GetMainController() && GetMainController()->IsInPictureInPictureMode() &&
!aController->IsInPictureInPictureMode()) {
LOG_MAINCONTROLLER(
"Main controller is being used in PIP mode, so we won't replace it "
"with non-PIP controller");
return ReorderGivenController(aController,
InsertOptions::eInsertBeforeTail);
}
ReorderGivenController(aController, InsertOptions::eInsertToTail);
UpdateMainControllerInternal(aController);
}
void MediaControlService::ControllerManager::ReorderGivenController(
MediaController* aController, InsertOptions aOption) {
MOZ_DIAGNOSTIC_ASSERT(aController);
MOZ_DIAGNOSTIC_ASSERT(mControllers.contains(aController));
// Make the main controller as the last element in the list to maintain the
// order of controllers because we always use the last controller in the list
// as the next main controller when removing current main controller from the
// list.
// Eg. If the list contains [A, B, C], and now the last element C is the main
// controller. When B becomes main controller later, the list would become
// [A, C, B]. And if A becomes main controller, list would become [C, B, A].
// Then, if we remove A from the list, the next main 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();
mControllers.insertBack(aController);
UpdateMainControllerInternal(aController);
if (aOption == InsertOptions::eInsertToTail) {
// Make the main controller as the last element in the list to maintain the
// order of controllers because we always use the last controller in the
// list as the next main controller when removing current main controller
// from the list. Eg. If the list contains [A, B, C], and now the last
// element C is the main controller. When B becomes main controller later,
// the list would become [A, C, B]. And if A becomes main controller, list
// would become [C, B, A]. Then, if we remove A from the list, the next main
// 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();
return mControllers.insertBack(aController);
}
if (aOption == InsertOptions::eInsertBeforeTail) {
// This happens when the latest playing controller can't become the main
// controller because we have already had other controller being used in
// PIP mode, which would always be regarded as the main controller.
// However, we would still like to adjust its order in the list. Eg, we have
// 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);
}
}
void MediaControlService::ControllerManager::Shutdown() {

Просмотреть файл

@ -51,6 +51,11 @@ class MediaControlService final : public nsIObserver {
// This method would be called when the controller changes its playback state.
void NotifyControllerPlaybackStateChanged(MediaController* aController);
// This method would be called when the controller starts to being used in the
// picture-in-picture mode.
void NotifyControllerBeingUsedInPictureInPictureMode(
MediaController* aController);
// The main controller is the controller which can receive the media control
// key events and would show its metadata to virtual controller interface.
MediaController* GetMainController() const;
@ -97,7 +102,7 @@ class MediaControlService final : public nsIObserver {
bool AddController(MediaController* aController);
bool RemoveController(MediaController* aController);
void UpdateMainController(MediaController* aController);
void UpdateMainControllerIfNeeded(MediaController* aController);
void Shutdown();
@ -111,6 +116,18 @@ class MediaControlService final : public nsIObserver {
void MainControllerMetadataChanged(const MediaMetadataBase& aMetadata);
private:
// Assume that we have a list [A, B, C, D], and we want to reorder B.
// When applying `eInsertToTail`, list would become [A, C, D, B].
// When applying `eInsertBeforeTail`, list would become [A, C, B, D].
enum class InsertOptions {
eInsertToTail,
eInsertBeforeTail,
};
// Adjust the given controller's order by the insert option.
void ReorderGivenController(MediaController* aController,
InsertOptions aOption);
void UpdateMainControllerInternal(MediaController* aController);
void ConnectToMainControllerEvents();
void DisconnectMainControllerEvents();

Просмотреть файл

@ -254,6 +254,10 @@ void MediaController::SetIsInPictureInPictureMode(
LOG("Set IsInPictureInPictureMode to %s",
aIsInPictureInPictureMode ? "true" : "false");
mIsInPictureInPictureMode = aIsInPictureInPictureMode;
if (RefPtr<MediaControlService> service = MediaControlService::GetService();
service && mIsInPictureInPictureMode) {
service->NotifyControllerBeingUsedInPictureInPictureMode(this);
}
}
bool MediaController::IsInPictureInPictureMode() const {