VulpesOS/gaia/dev_apps/music-oga/js/communications.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

189 lines
5.2 KiB
JavaScript
Executable file

/* exported MusicComms */
/* global Database, INTERRUPT_BEGIN, MediaRemoteControls, ModeManager,
MODE_PLAYER, PlaybackQueue, PlayerView, PLAYSTATUS_PLAYING,
PLAYSTATUS_STOPPED */
'use strict';
var MusicComms = {
commands: {
play: function(event) {
this.commands.playpause.call(this, event);
},
// For those bluetooth devices that do not keep, request or receive
// the play status, because the play status may not sync with the player,
// they will just send "play" or "playpause" when pressing the "playpause"
// button, so for the "play" and "playpause" commands, we will check
// the play status for the player then decide we should play or pause.
playpause: function(event) {
this._getPlayerReady(() => {
var isResumedBySCO = this.isSCOEnabled;
this.isSCOEnabled = event.detail.isSCOConnected;
// Check if it's resumed by the SCO disconnection, if so, we need to
// recover the player to the original status.
if (isResumedBySCO) {
if (this._statusBeforeSCO === PLAYSTATUS_PLAYING ||
this._statusBeforeSCO === INTERRUPT_BEGIN) {
PlayerView.play();
} else {
PlayerView.pause();
}
} else {
// Play in shuffle order if music app is launched remotely.
if (PlayerView.playStatus === PLAYSTATUS_STOPPED) {
Database.count('metadata.title', null, (count) => {
var info = {
key: 'metadata.title',
range: null,
direction: 'next',
option: 'title',
count: count
};
PlaybackQueue.shuffle = true;
PlayerView.activate(new PlaybackQueue.DynamicQueue(info));
PlayerView.start();
});
} else if (PlayerView.playStatus === PLAYSTATUS_PLAYING) {
PlayerView.pause();
} else {
PlayerView.play();
}
}
});
},
pause: function(event) {
this.isSCOEnabled = event.detail.isSCOConnected;
if (!this._isPlayerActivated()) {
return;
}
// Record the current play status so that we can recover the player to
// the original status after SCO is disconnected.
if (this.isSCOEnabled) {
this._statusBeforeSCO = PlayerView.playStatus;
}
PlayerView.pause();
},
stop: function(event) {
if (!this._isPlayerActivated()) {
return;
}
PlayerView.stop();
},
next: function(event) {
if (!this._isPlayerActivated()) {
return;
}
PlayerView.next();
},
previous: function(event) {
if (!this._isPlayerActivated()) {
return;
}
PlayerView.previous();
},
seekpress: function(event) {
if (!this._isPlayerActivated()) {
return;
}
if (!PlayerView.isTouching) {
PlayerView.startFastSeeking(event.detail.direction);
}
},
seekrelease: function(event) {
if (!this._isPlayerActivated()) {
return;
}
PlayerView.stopFastSeeking();
},
updatemetadata: function() {
// After A2DP is connected, some bluetooth devices will try to synchronize
// the playing metadata with the player, if the player is not ready, we
// have to initial the player to have the metadata, even the player is
// stopped.
this._getPlayerReady(function() {
PlayerView.updateRemoteMetadata();
});
},
updateplaystatus: function() {
// After A2DP is connected, some bluetooth devices will try to synchronize
// the playstatus with the player, if the player is not ready, we have to
// initial the player to have the play status.
this._getPlayerReady(function() {
PlayerView.updateRemotePlayStatus();
});
}
},
enabled: false,
isSCOEnabled: false,
_statusBeforeSCO: null,
init: function() {
// The Media Remote Controls object will handle the remote commands.
this.mrc = new MediaRemoteControls();
// Add command listeners base on what commands the MusicComms has.
for (var command in this.commands) {
this.mrc.addCommandListener(command, this.commands[command].bind(this));
}
// Update the SCO status after the mrc is ready, so that we can know the
// current SCO connection and reflect it to the player.
this.mrc.start(this.updateSCOStatus.bind(this));
this.mrc.notifyAppInfo({
origin: window.location.origin,
icon: window.location.origin + '/style/icons/default_84.png'
});
this.enabled = true;
},
_getPlayerReady: function(callback) {
ModeManager.waitForView(MODE_PLAYER, callback);
},
_isPlayerActivated: function() {
return (typeof PlayerView !== 'undefined' &&
PlayerView.playStatus !== PLAYSTATUS_STOPPED);
},
notifyMetadataChanged: function(metadata) {
if (this.enabled) {
this.mrc.notifyMetadataChanged(metadata);
}
},
notifyStatusChanged: function(info) {
if (this.enabled) {
this.mrc.notifyStatusChanged(info);
}
},
updateSCOStatus: function() {
if (this.enabled) {
this.mrc.getSCOStatus(function(status) {
this.isSCOEnabled = status;
}.bind(this));
}
}
};