Skip to content

Commit 4e03ad7

Browse files
Import mpris plugin
1 parent 03f073c commit 4e03ad7

10 files changed

Lines changed: 1284 additions & 4 deletions

File tree

configure.ac

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,7 @@ AS_IF([test "${enable_gtk2}" = "yes" -o "${enable_gtk3}" = "yes" -o "${enable_sh
266266
])
267267
])
268268

269-
AS_IF([test "${enable_staticlink}" != "no"], [
270-
], [
269+
AS_IF([test "${enable_staticlink}" != "no"], [], [
271270
AC_CHECK_LIB([dispatch], [main], [HAVE_DISPATCH=yes])
272271
])
273272

@@ -744,6 +743,19 @@ AS_IF([test "${enable_gme}" != "no" -a "${HAVE_ZLIB}" = "yes"], [
744743
HAVE_GME=yes
745744
])
746745

746+
dnl mpris plugin
747+
AS_IF([test "${enable_mpris}" != "no"], [
748+
AS_IF([test "${enable_staticlink}" != "no"], [
749+
HAVE_MPRIS=yes
750+
MPRIS_LIBS="L${GTK_ROOT_310}/lib -lglib-2.0 -lgio-2.0 -lgio-unix-2.0 -lgthread-2.0"
751+
MPRIS_CFLAGS="${GTK3_310_CFLAGS}"
752+
], [
753+
PKG_CHECK_MODULES(MPRIS, [glib-2.0 gio-2.0 gio-unix-2.0 gthread-2.0], HAVE_MPRIS=yes, HAVE_MPRIS=no)
754+
])
755+
AC_SUBST(MPRIS_LIBS)
756+
AC_SUBST(MPRIS_CFLAGS)
757+
])
758+
747759
AS_IF([test "${HAVE_DBUS}" = "yes" -a "${enable_notify}" != "no"], [
748760
AS_IF([test "${enable_staticlink}" != "no"], [
749761
HAVE_NOTIFY=yes
@@ -864,7 +876,7 @@ AS_IF([test "${enable_soundtouch}" != "no"], [
864876
HAVE_SOUNDTOUCH=yes
865877
])
866878

867-
PLUGINS_DIRS="plugins/liboggedit plugins/lastfm plugins/mp3 plugins/vorbis plugins/opus plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/shellexecui plugins/dsp_libsrc plugins/m3u plugins/vfs_zip plugins/converter plugins/dumb plugins/shn plugins/psf plugins/mono2stereo plugins/alac plugins/wma plugins/pltbrowser plugins/coreaudio plugins/sc68 plugins/rg_scanner plugins/soundtouch plugins/medialib plugins/lyrics"
879+
PLUGINS_DIRS="plugins/liboggedit plugins/lastfm plugins/mp3 plugins/vorbis plugins/opus plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/shellexecui plugins/dsp_libsrc plugins/m3u plugins/vfs_zip plugins/converter plugins/dumb plugins/shn plugins/psf plugins/mono2stereo plugins/alac plugins/wma plugins/pltbrowser plugins/coreaudio plugins/sc68 plugins/rg_scanner plugins/soundtouch plugins/medialib plugins/lyrics plugins/mpris"
868880

869881
AM_CONDITIONAL(APE_USE_YASM, test "x$APE_USE_YASM" = "xyes")
870882
AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes")
@@ -899,6 +911,7 @@ AM_CONDITIONAL(HAVE_MP3, test "x$HAVE_MP3" = "xyes")
899911
AM_CONDITIONAL(HAVE_LIBMAD, test "x$HAVE_LIBMAD" = "xyes")
900912
AM_CONDITIONAL(HAVE_LIBMPG123, test "x$HAVE_LIBMPG123" = "xyes")
901913
AM_CONDITIONAL(HAVE_LYRICS, test "x$HAVE_LYRICS" = "xyes")
914+
AM_CONDITIONAL(HAVE_MPRIS, test "x$HAVE_MPRIS" = "xyes")
902915
AM_CONDITIONAL(HAVE_OSS, test "x$HAVE_OSS" = "xyes")
903916
AM_CONDITIONAL(HAVE_SUPEREQ, test "x$HAVE_SUPEREQ" = "xyes")
904917
AM_CONDITIONAL(HAVE_NOTIFY, test "x$HAVE_NOTIFY" = "xyes")
@@ -1001,6 +1014,7 @@ plugins/rg_scanner/Makefile
10011014
plugins/soundtouch/Makefile
10021015
plugins/medialib/Makefile
10031016
plugins/lyrics/Makefile
1017+
plugins/mpris/Makefile
10041018
po/Makefile.in
10051019
intl/Makefile
10061020
deadbeef.desktop
@@ -1059,6 +1073,7 @@ PRINT_PLUGIN_INFO([mono2stereo],[mono2stereo DSP plugin],[test "x$HAVE_MONO2STER
10591073
PRINT_PLUGIN_INFO([mp3],[mp3 plugin],[test "x$HAVE_MP3" = "xyes"])
10601074
PRINT_PLUGIN_INFO([ libmad],[libmad backend for mp3 plugin],[test "x$HAVE_LIBMAD" = "xyes"])
10611075
PRINT_PLUGIN_INFO([ libmpg123],[libmpg123 backend for mp3 plugin],[test "x$HAVE_LIBMPG123" = "xyes"])
1076+
PRINT_PLUGIN_INFO([mpris],[MPRIS plugin],[test "x$HAVE_MPRIS" = "xyes"])
10621077
PRINT_PLUGIN_INFO([musepack],[musepack player plugin],[test "x$HAVE_MUSEPACK" = "xyes"])
10631078
PRINT_PLUGIN_INFO([notify],[notification-daemon support plugin],[test "x$HAVE_NOTIFY" = "xyes"])
10641079
PRINT_PLUGIN_INFO([nullout],[NULL output],[test "x$HAVE_NULLOUT" = "xyes"])

plugins/mpris/COPYING

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
MPRIS plugin for DeaDBeeF Player
2+
Copyright (C) 2014-2021 Peter Lamby <peterlamby@web.de>
3+
And other contributors:
4+
* Abi Hafshin Alfarouq
5+
* Evgeniy Gerasimenko
6+
* Evgeny Kravchenko
7+
* George Borisov
8+
* Jakub Wasylków
9+
* Jan Tojnar
10+
* Michael Livshin
11+
* Nicolai Syvertsen
12+
* Oleksiy Yakovenko
13+
* Toad King
14+
* yut23
15+
16+
This program is free software: you can redistribute it and/or modify
17+
it under the terms of the GNU General Public License as published by
18+
the Free Software Foundation, either version 2 of the License, or
19+
(at your option) any later version.
20+
21+
This program is distributed in the hope that it will be useful,
22+
but WITHOUT ANY WARRANTY; without even the implied warranty of
23+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24+
GNU General Public License for more details.
25+
26+
You should have received a copy of the GNU General Public License
27+
along with this program. If not, see <http://www.gnu.org/licenses/>.
28+

plugins/mpris/Makefile.am

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
if HAVE_MPRIS
2+
3+
mpris_path=@top_srcdir@/plugins/mpris
4+
5+
EXTRA_DIST = $(mpris_path)/COPYING
6+
7+
pkglib_LTLIBRARIES = mpris.la
8+
9+
mpris_la_SOURCES = mpris.c mprisServer.c logging.h mprisServer.h
10+
mpris_la_LDFLAGS = -module -avoid-version
11+
mpris_la_LIBADD = $(LDADD) $(MPRIS_LIBS)
12+
mpris_la_CFLAGS = $(CFLAGS) -std=c99 $(MPRIS_CFLAGS) -I@top_srcdir@/include -fPIC
13+
14+
endif

plugins/mpris/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# MPRIS plugin for DeaDBeeF
2+
3+
This plugin was originally developed externally.
4+
5+
The original source and history can be found at:
6+
https://github.com/DeaDBeeF-Player/deadbeef-mpris2-plugin
7+

plugins/mpris/logging.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
MPRIS plugin for DeaDBeeF Player
3+
Copyright (C) Peter Lamby and other contributors
4+
See the file COPYING for more details
5+
*/
6+
7+
#ifndef LOGGING_H_
8+
#define LOGGING_H_
9+
10+
#define logDebug(...) { deadbeef->log_detailed (&plugin.plugin, DDB_LOG_LAYER_INFO, __VA_ARGS__); }
11+
#define logError(...) { deadbeef->log_detailed (&plugin.plugin, 0, __VA_ARGS__); }
12+
#define debug(...) logDebug(__VA_ARGS__)
13+
#define error(...) logError(__VA_ARGS__)
14+
15+
#endif

plugins/mpris/mpris.c

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/*
2+
MPRIS plugin for DeaDBeeF Player
3+
Copyright (C) Peter Lamby and other contributors
4+
See the file COPYING for more details
5+
*/
6+
7+
#include <glib.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
#include "mprisServer.h"
12+
#include "logging.h"
13+
14+
DB_functions_t *deadbeef;
15+
DB_misc_t plugin;
16+
17+
static GThread *mprisThread;
18+
static struct MprisData mprisData;
19+
static int oldLoopStatus = -1;
20+
static int oldShuffleStatus = -1;
21+
22+
static int onStart() {
23+
oldLoopStatus = mprisData.deadbeef->conf_get_int("playback.loop", 0);
24+
oldShuffleStatus = mprisData.deadbeef->conf_get_int("playback.order", PLAYBACK_ORDER_LINEAR);
25+
mprisData.previousAction = mprisData.deadbeef->conf_get_int(SETTING_PREVIOUS_ACTION, PREVIOUS_ACTION_PREV_OR_RESTART);
26+
27+
#if (GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION < 32)
28+
mprisThread = g_thread_create(startServer, (void *)&mprisData, TRUE, NULL);
29+
#else
30+
mprisThread = g_thread_new("mpris-listener", startServer, (void *)&mprisData);
31+
#endif
32+
return 0;
33+
}
34+
35+
static int onStop() {
36+
debug("Emitting stop event on player exit\n");
37+
emitPlaybackStatusChanged(OUTPUT_STATE_STOPPED, &mprisData);
38+
39+
stopServer();
40+
41+
#if (GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION < 32)
42+
g_thread_join(mprisThread);
43+
#else
44+
g_thread_unref(mprisThread);
45+
#endif
46+
47+
if (mprisData.artworkData.artwork) {
48+
free(mprisData.artworkData.path);
49+
free(mprisData.artworkData.default_path);
50+
mprisData.artworkData.path = NULL;
51+
mprisData.artworkData.default_path = NULL;
52+
}
53+
54+
return 0;
55+
}
56+
57+
static int onDisconnect() {
58+
if (mprisData.artworkData.artwork) {
59+
mprisData.artworkData.artwork->cancel_queries_with_source_id(mprisData.artworkData.source_id);
60+
}
61+
return 0;
62+
}
63+
64+
static int onConnect() {
65+
mprisData.prevOrRestart = NULL;
66+
67+
ddb_artwork_plugin_t *artworkPlugin = (ddb_artwork_plugin_t *)mprisData.deadbeef->plug_get_for_id ("artwork2");
68+
69+
if (artworkPlugin != NULL) {
70+
debug("artwork plugin detected... album art support enabled\n");
71+
if (artworkPlugin) {
72+
mprisData.artworkData.artwork = artworkPlugin;
73+
mprisData.artworkData.source_id = artworkPlugin->allocate_source_id();
74+
mprisData.artworkData.path = NULL;
75+
mprisData.artworkData.default_path = malloc(PATH_MAX);
76+
if (mprisData.artworkData.default_path) {
77+
strcpy(mprisData.artworkData.default_path,"file://");
78+
size_t offset = strlen("file://");
79+
artworkPlugin->default_image_path(mprisData.artworkData.default_path + offset, PATH_MAX - offset);
80+
}
81+
}
82+
} else {
83+
debug("artwork plugin not detected... album art support disabled\n");
84+
}
85+
86+
DB_plugin_t **plugins = mprisData.deadbeef->plug_get_list();
87+
for (int i = 0; plugins[i]; i++) {
88+
if (plugins[i]->get_actions != NULL) {
89+
for (DB_plugin_action_t *dbaction = plugins[i]->get_actions(NULL); dbaction; dbaction = dbaction->next) {
90+
if (strcmp(dbaction->name, "prev_or_restart") == 0) {
91+
debug("prev_or_restart command detected... previous or restart support enabled\n");
92+
mprisData.prevOrRestart = dbaction;
93+
break;
94+
}
95+
}
96+
97+
if (mprisData.prevOrRestart != NULL) {
98+
break;
99+
}
100+
}
101+
}
102+
103+
104+
if (mprisData.prevOrRestart == NULL) {
105+
debug("prev_or_restart command not detected... previous or restart support disabled\n");
106+
}
107+
108+
return 0;
109+
}
110+
111+
//***********************
112+
//* Handels signals for *
113+
//* - Playback status *
114+
//* - Metadata *
115+
//* - Volume *
116+
//* - Seeked *
117+
//* - Loop status *
118+
//* - Shuffle status *
119+
//***********************
120+
static int handleEvent (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
121+
DB_functions_t *deadbeef = mprisData.deadbeef;
122+
123+
switch (id) {
124+
case DB_EV_SEEKED:
125+
debug("DB_EV_SEEKED event received\n");
126+
emitSeeked(((ddb_event_playpos_t *) ctx)->playpos);
127+
break;
128+
case DB_EV_TRACKINFOCHANGED:
129+
debug("DB_EV_TRACKINFOCHANGED event received\n");
130+
emitMetadataChanged(-1, &mprisData);
131+
emitCanGoChanged(&mprisData);
132+
emitSeeked(deadbeef->streamer_get_playpos());
133+
break;
134+
case DB_EV_SELCHANGED:
135+
case DB_EV_PLAYLISTSWITCHED:
136+
emitCanGoChanged(&mprisData);
137+
break;
138+
case DB_EV_SONGSTARTED:
139+
debug("DB_EV_SONGSTARTED event received\n");
140+
emitMetadataChanged(-1, &mprisData);
141+
emitPlaybackStatusChanged(OUTPUT_STATE_PLAYING, &mprisData);
142+
break;
143+
case DB_EV_PAUSED:
144+
debug("DB_EV_PAUSED event received\n");
145+
emitPlaybackStatusChanged(p1 ? OUTPUT_STATE_PAUSED : OUTPUT_STATE_PLAYING, &mprisData);
146+
break;
147+
case DB_EV_STOP:
148+
debug("DB_EV_STOP event received\n");
149+
emitPlaybackStatusChanged(OUTPUT_STATE_STOPPED, &mprisData);
150+
break;
151+
case DB_EV_VOLUMECHANGED:
152+
debug("DB_EV_VOLUMECHANGED event received\n");
153+
emitVolumeChanged(deadbeef->volume_get_db());
154+
break;
155+
case DB_EV_CONFIGCHANGED:
156+
debug("DB_EV_CONFIGCHANGED event received\n");
157+
if (oldShuffleStatus != -1) {
158+
int newLoopStatus = mprisData.deadbeef->conf_get_int("playback.loop", PLAYBACK_MODE_LOOP_ALL);
159+
int newShuffleStatus = mprisData.deadbeef->conf_get_int("playback.order", PLAYBACK_ORDER_LINEAR);
160+
161+
if (newLoopStatus != oldLoopStatus) {
162+
debug("LoopStatus changed %d\n", newLoopStatus);
163+
emitLoopStatusChanged(oldLoopStatus = newLoopStatus);
164+
} if (newShuffleStatus != oldShuffleStatus) {
165+
debug("ShuffleStatus changed %d\n", newShuffleStatus);
166+
emitShuffleStatusChanged(oldShuffleStatus = newShuffleStatus);
167+
}
168+
169+
mprisData.previousAction = mprisData.deadbeef->conf_get_int(SETTING_PREVIOUS_ACTION, PREVIOUS_ACTION_PREV_OR_RESTART);
170+
}
171+
if (deadbeef->conf_get_int ("mpris.trace", 0)) {
172+
plugin.plugin.flags |= DDB_PLUGIN_FLAG_LOGGING;
173+
}
174+
else {
175+
plugin.plugin.flags &= ~DDB_PLUGIN_FLAG_LOGGING;
176+
}
177+
break;
178+
default:
179+
break;
180+
}
181+
182+
return 0;
183+
}
184+
185+
#define STR(x) #x
186+
#define XSTR(x) STR(x)
187+
188+
static const char settings_dlg[] =
189+
"property \"\\\"Previous\\\" action behavior\" select[2] " SETTING_PREVIOUS_ACTION " " XSTR(PREVIOUS_ACTION_PREV_OR_RESTART) " \"Previous\" \"Previous or restart current track\";"
190+
"property \"Enable logging\" checkbox mpris.trace 0;\n"
191+
"property \"Disable shuffle and repeat\" checkbox mpris.disable_shuffle_repeat 0;\n"
192+
;
193+
194+
195+
DB_misc_t plugin = {
196+
.plugin.api_vmajor = DB_API_VERSION_MAJOR,
197+
.plugin.api_vminor = DB_API_VERSION_MINOR,
198+
.plugin.type = DB_PLUGIN_MISC,
199+
.plugin.version_major = 2,
200+
.plugin.version_minor = 0,
201+
.plugin.id = "mpris",
202+
.plugin.name ="MPRIS (multimedia keys support)",
203+
.plugin.descr =
204+
"Control playback using multimedia keys.\n"
205+
"\n"
206+
"This requires a running MPRIS server.\n"
207+
"GNOME and KDE already have one / no configuration necessary.\n"
208+
"Otherwise you may need to install and configure it manually.\n"
209+
,
210+
.plugin.copyright =
211+
"MPRIS plugin for DeaDBeeF Player\n"
212+
"Copyright (C) 2014-2021 Peter Lamby <peterlamby@web.de>\n"
213+
"And other contributors:\n"
214+
"* Abi Hafshin Alfarouq\n"
215+
"* Evgeniy Gerasimenko\n"
216+
"* Evgeny Kravchenko\n"
217+
"* George Borisov\n"
218+
"* Jakub Wasylków\n"
219+
"* Jan Tojnar\n"
220+
"* Michael Livshin\n"
221+
"* Nicolai Syvertsen\n"
222+
"* Oleksiy Yakovenko\n"
223+
"* Toad King\n"
224+
"* yut23\n"
225+
"\n"
226+
"This program is free software: you can redistribute it and/or modify\n"
227+
"it under the terms of the GNU General Public License as published by\n"
228+
"the Free Software Foundation, either version 2 of the License, or\n"
229+
"(at your option) any later version.\n"
230+
"\n"
231+
"This program is distributed in the hope that it will be useful,\n"
232+
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
233+
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
234+
"GNU General Public License for more details.\n"
235+
"\n"
236+
"You should have received a copy of the GNU General Public License\n"
237+
"along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
238+
,
239+
.plugin.website = "https://github.com/DeaDBeeF-Player/deadbeef-mpris2-plugin",
240+
.plugin.start = onStart,
241+
.plugin.stop = onStop,
242+
.plugin.connect = onConnect,
243+
.plugin.disconnect = onDisconnect,
244+
.plugin.configdialog = settings_dlg,
245+
.plugin.message = handleEvent,
246+
};
247+
248+
DB_plugin_t * mpris_load (DB_functions_t *ddb) {
249+
deadbeef = mprisData.deadbeef = ddb;
250+
251+
return DB_PLUGIN(&plugin);
252+
}

0 commit comments

Comments
 (0)