Skip to content

Commit

Permalink
Fixed mpris duration and position on linux. Added duration and positi…
Browse files Browse the repository at this point in the history
…on for MediaSessionService
  • Loading branch information
m0ngr31 committed Aug 23, 2020
1 parent 91cd5bd commit 3ee13cb
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 37 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jellyamp",
"version": "0.9.7",
"version": "0.9.8",
"private": true,
"description": "Desktop client for listening to music from a Jellyfin server",
"license": "MIT",
Expand Down
29 changes: 19 additions & 10 deletions src/background.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { app, protocol, BrowserWindow, ipcMain, globalShortcut } from 'electron';
import { app, protocol, BrowserWindow, ipcMain } from 'electron';
import {
createProtocol,
installVueDevtools,
Expand All @@ -8,6 +8,7 @@ import path from 'path';
let player;
let Player;
let playerHandler;
let currentPlaytime = 0;

const isDevelopment = process.env.NODE_ENV !== 'production';
const isLinux = process.platform === 'linux';
Expand Down Expand Up @@ -109,14 +110,18 @@ const setupPlayer = ev => {

playerHandler = ev;

player.on('next', () => playerHandler.reply('skip'));
player.on('previous', () => playerHandler.reply('prev'));
player.on('pause', () => playerHandler.reply('playPause'));
player.on('playpause', () => playerHandler.reply('playPause'));
player.on('play', () => playerHandler.reply('playPause'));
player.on('stop', () => playerHandler.reply('stop'));
player.on('next', () => { currentPlaytime = 0; playerHandler.reply('skip'); });
player.on('previous', () => { currentPlaytime = 0; playerHandler.reply('prev'); });
player.on('pause', () => { currentPlaytime = 0; playerHandler.reply('playPause'); });
player.on('playpause', () => { currentPlaytime = 0; playerHandler.reply('playPause'); });
player.on('play', () => { currentPlaytime = 0; playerHandler.reply('playPause'); });
player.on('stop', () => { currentPlaytime = 0; playerHandler.reply('stop'); });
player.on('quit', () => app.quit());
player.on('raise', () => win.restore());

player.getPosition = () => {
return currentPlaytime;
}
}
};

Expand All @@ -128,7 +133,7 @@ if (isLinux) {

player.metadata = {
'mpris:trackid': player.objectPath('track/0'),
'mpris:length': 0,
'mpris:length': data.duration,
'mpris:artUrl': data.img,
'xesam:title': data.name,
'xesam:album': data.album,
Expand All @@ -138,21 +143,25 @@ if (isLinux) {
player.playbackStatus = Player.PLAYBACK_STATUS_PLAYING;
});

ipcMain.on('pause', () => {
ipcMain.on('pause', ev => {
if (!player) {
setupPlayer(ev);
}

player.playbackStatus = Player.PLAYBACK_STATUS_PAUSED;
});

ipcMain.on('stop', () => {
ipcMain.on('stop', ev => {
if (!player) {
setupPlayer(ev);
}

player.playbackStatus = Player.PLAYBACK_STATUS_STOPPED;
});

ipcMain.on('updateTime', (_ev, data) => {
currentPlaytime = data;
});
}

// Exit cleanly on request from parent process in development mode.
Expand Down
74 changes: 49 additions & 25 deletions src/services/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import JellyfinService from './jellyfin';

import placeholderImg from '../assets/logo.png';

const ticksInSecond = 10000000;
const microSecondsinSecond = 1000000;
const ticksInMs = 10;

Vue.filter('duration', value => {
if (!value) {
value = 0;
Expand All @@ -30,7 +34,7 @@ class Player {
updateProgress = _.throttle(ticks => {
const data = {
IsPaused: false,
PositionTicks: ticks, // Convert to ticks/ns
PositionTicks: ticks,
PlayMethod: 'Transcode',
PlaySessionId: this.queue[this.index].params.PlaySessionId,
ItemId: this.queue[this.index].Id,
Expand All @@ -40,11 +44,22 @@ class Player {
JellyfinService.updateProgress(data);
}, 10000);

updateProgressMpris = _.throttle(ticks => {
updateProgressMpris = _.throttle(seconds => {
if (window.ipcRenderer) {
window.ipcRenderer.send('updateTime', Math.floor(ticks / 1000)); // nanoseconds to microseconds
window.ipcRenderer.send('updateTime', seconds * microSecondsinSecond); // seconds to microseconds
}

if ('mediaSession' in navigator && 'setPositionState' in navigator.mediaSession) {
// Sometimes there is a race condition on skip where the position is greater than the duration
try {
navigator.mediaSession.setPositionState({
duration: this.player.duration(),
playbackRate: 1,
position: seconds,
});
} catch {}
}
}, 1000);
}, 1000, {leading: false, trailing: true});

// Make it a singleton
constructor() {
Expand Down Expand Up @@ -169,23 +184,27 @@ class Player {
artist: item.Artists,
album: item.Album,
img: item.thumbnailImage,
duration: Math.floor(item.RunTimeTicks / 1000), // nanoseconds to microseconds
duration: Math.floor(item.RunTimeTicks / ticksInMs), // nanoseconds to microseconds
};

window.ipcRenderer.send('play', data);
}

if ('mediaSession' in navigator) {
setTimeout(() => {
navigator.mediaSession.playbackState = 'playing';
});

navigator.mediaSession.metadata = new MediaMetadata({
title: item.Name,
artist: item.Artists,
album: item.Album,
artwork: [{ src: item.thumbnailImage }],
});

navigator.mediaSession.playbackState = 'playing';

if ('setPositionState' in navigator.mediaSession) {
navigator.mediaSession.setPositionState({
duration: Math.floor(item.RunTimeTicks / ticksInSecond),
});
}
}
},
onend: () => {
Expand Down Expand Up @@ -219,6 +238,10 @@ class Player {
window.ipcRenderer.send('stop');
}

if ('mediaSession' in navigator) {
navigator.mediaSession.playbackState = 'none';
}

JellyfinService.stopPlaying({
IsPaused: false,
PlayMethod: 'Transcode',
Expand Down Expand Up @@ -321,11 +344,11 @@ class Player {
// requestAnimationFrame(() => this.step()); // This binds up the CPU
setTimeout(() => this.step(), 250);

const ticks = Math.round(seek * 10000000);
const ticks = Math.round(seek * ticksInSecond);

this.queue[this.index].progressInTicks = ticks;
this.updateProgress(ticks);
this.updateProgressMpris(ticks);
this.updateProgressMpris(seek);
}
}

Expand Down Expand Up @@ -398,21 +421,22 @@ if (window.ipcRenderer) {
if ('mediaSession' in navigator) {
navigator.mediaSession.playbackState = 'none';

navigator.mediaSession.setActionHandler('play', () => {
PlayerService.playPause();
});

navigator.mediaSession.setActionHandler('pause', () => {
PlayerService.playPause();
});

navigator.mediaSession.setActionHandler('previoustrack', () => {
PlayerService.handleBack();
});
const actionHandlers = [
['play', () => PlayerService.playPause()],
['pause', () => PlayerService.playPause()],
['previoustrack', () => PlayerService.handleBack()],
['nexttrack', () => PlayerService.skip('next')],
['stop', () => PlayerService.stop()],
// ['seekto', (details) => { /* ... */ }],
];

navigator.mediaSession.setActionHandler('nexttrack', () => {
PlayerService.skip('next');
});
for (const [action, handler] of actionHandlers) {
try {
navigator.mediaSession.setActionHandler(action, handler);
} catch (error) {
console.log(`The media session action "${action}" is not supported yet.`);
}
}
}


Expand Down

0 comments on commit 3ee13cb

Please sign in to comment.