Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
Nate Graham
Kid3
Commits
9f9cf498
Commit
9f9cf498
authored
Dec 10, 2016
by
Urs Fleisch
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MPRIS D-Bus interface to control audio player from panel.
parent
0e3c3f54
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1072 additions
and
10 deletions
+1072
-10
ChangeLog
ChangeLog
+1
-0
src/core/model/Sources.cmake
src/core/model/Sources.cmake
+2
-0
src/core/model/audioplayer.cpp
src/core/model/audioplayer.cpp
+167
-5
src/core/model/audioplayer.h
src/core/model/audioplayer.h
+101
-4
src/core/model/kid3application.cpp
src/core/model/kid3application.cpp
+69
-0
src/core/model/kid3application.h
src/core/model/kid3application.h
+15
-0
src/core/model/mprisinterface.cpp
src/core/model/mprisinterface.cpp
+440
-0
src/core/model/mprisinterface.h
src/core/model/mprisinterface.h
+267
-0
src/gui/forms/basemainwindow.cpp
src/gui/forms/basemainwindow.cpp
+2
-0
src/gui/widgets/playtoolbar.cpp
src/gui/widgets/playtoolbar.cpp
+3
-1
src/gui/widgets/playtoolbar.h
src/gui/widgets/playtoolbar.h
+5
-0
No files found.
ChangeLog
View file @
9f9cf498
...
...
@@ -6,6 +6,7 @@ Fri Dec 23 08:33:40 CET 2016 Urs Fleisch <ufleisch@users.sourceforge.net>
+ If the first command line argument is "--portable", the
configuration is stored in a file kid3.ini in the program folder.
+ Image data can be copied to clipboard.
+ MPRIS2 D-Bus interface for the audio player.
* Improved:
+ "Import CSV" can import to different files if no matching
...
...
src/core/model/Sources.cmake
View file @
9f9cf498
...
...
@@ -32,6 +32,7 @@ set(model_SRCS
model/frameeditorobject.cpp
model/frameobjectmodel.cpp
model/iusercommandprocessor.cpp
model/mprisinterface.cpp
)
set
(
model_MOC_HDRS
...
...
@@ -54,6 +55,7 @@ set(model_MOC_HDRS
model/genremodel.h
model/frameeditorobject.h
model/frameobjectmodel.h
model/mprisinterface.h
)
if
(
HAVE_QTDBUS
)
...
...
src/core/model/audioplayer.cpp
View file @
9f9cf498
...
...
@@ -38,13 +38,17 @@
#include <QMediaPlayer>
#include <QMediaPlaylist>
#endif
#include "kid3application.h"
#include "taggedfile.h"
#include "fileproxymodel.h"
/**
* Constructor.
*
* @param
parent
parent
object
* @param
app
parent
application
*/
AudioPlayer
::
AudioPlayer
(
QObject
*
parent
)
:
QObject
(
parent
)
AudioPlayer
::
AudioPlayer
(
Kid3Application
*
app
)
:
QObject
(
app
),
m_app
(
app
)
#ifdef HAVE_PHONON
,
m_fileNr
(
-
1
)
#endif
...
...
@@ -63,6 +67,10 @@ AudioPlayer::AudioPlayer(QObject* parent) : QObject(parent)
this
,
SLOT
(
currentSourceChanged
()));
connect
(
m_mediaObject
,
SIGNAL
(
tick
(
qint64
)),
this
,
SIGNAL
(
positionChanged
(
qint64
)));
connect
(
m_mediaObject
,
SIGNAL
(
stateChanged
(
Phonon
::
State
,
Phonon
::
State
)),
this
,
SLOT
(
onStateChanged
()));
connect
(
m_audioOutput
,
SIGNAL
(
volumeChanged
(
qreal
)),
this
,
SLOT
(
onVolumeChanged
(
qreal
)));
#else
m_mediaPlayer
=
new
QMediaPlayer
(
this
);
m_mediaPlaylist
=
new
QMediaPlaylist
(
m_mediaPlayer
);
...
...
@@ -71,6 +79,10 @@ AudioPlayer::AudioPlayer(QObject* parent) : QObject(parent)
this
,
SLOT
(
currentIndexChanged
(
int
)));
connect
(
m_mediaPlayer
,
SIGNAL
(
positionChanged
(
qint64
)),
this
,
SIGNAL
(
positionChanged
(
qint64
)));
connect
(
m_mediaPlayer
,
SIGNAL
(
stateChanged
(
QMediaPlayer
::
State
)),
this
,
SLOT
(
onStateChanged
()));
connect
(
m_mediaPlayer
,
SIGNAL
(
volumeChanged
(
int
)),
this
,
SIGNAL
(
volumeChanged
(
int
)));
#endif
}
...
...
@@ -109,10 +121,24 @@ void AudioPlayer::setFiles(const QStringList& files, int fileNr)
m_mediaPlaylist
->
setCurrentIndex
(
0
);
}
#endif
emit
fileCountChanged
(
getFileCount
());
}
/**
* Get name of current file.
* Get number of files in play list.
* @return number of files.
*/
int
AudioPlayer
::
getFileCount
()
const
{
#ifdef HAVE_PHONON
return
m_files
.
size
();
#else
return
m_mediaPlaylist
->
mediaCount
();
#endif
}
/**
* Get path of current file.
* @return file name.
*/
QString
AudioPlayer
::
getFileName
()
const
...
...
@@ -127,6 +153,33 @@ QString AudioPlayer::getFileName() const
#endif
}
/**
* Get tagged file for current file.
* @return tagged file, 0 if not available.
*/
TaggedFile
*
AudioPlayer
::
getTaggedFile
()
const
{
FileProxyModel
*
model
=
m_app
->
getFileProxyModel
();
QModelIndex
index
=
model
->
index
(
getFileName
());
if
(
index
.
isValid
())
{
return
FileProxyModel
::
getTaggedFileOfIndex
(
index
);
}
return
0
;
}
/**
* Get index of current file in playlist.
* @return index of current file.
*/
int
AudioPlayer
::
getCurrentIndex
()
const
{
#ifdef HAVE_PHONON
return
m_fileNr
;
#else
return
m_mediaPlaylist
->
currentIndex
();
#endif
}
/**
* Get the current playback position in milliseconds.
* @return time in milliseconds.
...
...
@@ -147,9 +200,85 @@ quint64 AudioPlayer::getCurrentPosition() const
void
AudioPlayer
::
setCurrentPosition
(
quint64
position
)
{
#ifdef HAVE_PHONON
return
m_mediaObject
->
seek
(
position
);
m_mediaObject
->
seek
(
position
);
#else
m_mediaPlayer
->
setPosition
(
position
);
#endif
emit
currentPositionChanged
(
position
);
}
/**
* Get playing state.
* @return state.
*/
AudioPlayer
::
State
AudioPlayer
::
getState
()
const
{
#ifdef HAVE_PHONON
switch
(
m_mediaObject
->
state
())
{
case
Phonon
::
PlayingState
:
return
PlayingState
;
case
Phonon
::
PausedState
:
return
PausedState
;
default:
return
StoppedState
;
}
#else
switch
(
m_mediaPlayer
->
state
())
{
case
QMediaPlayer
::
StoppedState
:
return
StoppedState
;
case
QMediaPlayer
::
PlayingState
:
return
PlayingState
;
case
QMediaPlayer
::
PausedState
:
return
PausedState
;
}
#endif
return
StoppedState
;
}
/**
* Signal stateChanged() when the playing state is changed.
*/
void
AudioPlayer
::
onStateChanged
()
{
emit
stateChanged
(
getState
());
}
/**
* Get duration of current track in milliseconds.
* @return duration.
*/
qint64
AudioPlayer
::
getDuration
()
const
{
#ifdef HAVE_PHONON
return
m_mediaObject
->
totalTime
();
#else
return
m_mediaPlayer
->
duration
();
#endif
}
/**
* Get volume.
* @return volume level between 0 and 100.
*/
int
AudioPlayer
::
getVolume
()
const
{
#ifdef HAVE_PHONON
return
m_audioOutput
->
volume
()
*
100
;
#else
return
m_mediaPlayer
->
volume
();
#endif
}
/**
* Set volume.
* @param volume level between 0 and 100
*/
void
AudioPlayer
::
setVolume
(
int
volume
)
{
#ifdef HAVE_PHONON
m_audioOutput
->
setVolume
(
static_cast
<
qreal
>
(
volume
)
/
100
);
#else
return
m_mediaPlayer
->
set
Position
(
position
);
m_mediaPlayer
->
set
Volume
(
volume
);
#endif
}
...
...
@@ -223,6 +352,30 @@ void AudioPlayer::playOrPause()
#endif
}
/**
* Resume playback.
*/
void
AudioPlayer
::
play
()
{
#ifdef HAVE_PHONON
m_mediaObject
->
play
();
#else
m_mediaPlayer
->
play
();
#endif
}
/**
* Pause playback.
*/
void
AudioPlayer
::
pause
()
{
#ifdef HAVE_PHONON
m_mediaObject
->
pause
();
#else
m_mediaPlayer
->
pause
();
#endif
}
/**
* Stop playback.
*/
...
...
@@ -265,6 +418,15 @@ void AudioPlayer::aboutToFinish()
}
}
}
/**
* Signal volumeChanged() when the volume is changed.
* @param volume volume
*/
void
AudioPlayer
::
onVolumeChanged
(
qreal
volume
)
{
emit
volumeChanged
(
volume
*
100
);
}
#else
/**
* Update display and button state when the current source is changed.
...
...
src/core/model/audioplayer.h
View file @
9f9cf498
...
...
@@ -45,6 +45,9 @@ class QMediaPlayer;
class
QMediaPlaylist
;
#endif
class
Kid3Application
;
class
TaggedFile
;
/**
* Audio player toolbar.
*/
...
...
@@ -52,12 +55,19 @@ class KID3_CORE_EXPORT AudioPlayer : public QObject {
Q_OBJECT
public:
/** Playing state. */
enum
State
{
StoppedState
,
/**< Stopped */
PlayingState
,
/**< Playing */
PausedState
/**< Paused */
};
/**
* Constructor.
*
* @param
parent
parent
object
* @param
app
parent
application
*/
explicit
AudioPlayer
(
QObject
*
parent
);
explicit
AudioPlayer
(
Kid3Application
*
app
);
/**
* Destructor.
...
...
@@ -73,11 +83,29 @@ public:
void
setFiles
(
const
QStringList
&
files
,
int
fileNr
=
0
);
/**
* Get name of current file.
* Get number of files in play list.
* @return number of files.
*/
int
getFileCount
()
const
;
/**
* Get path of current file.
* @return file name.
*/
QString
getFileName
()
const
;
/**
* Get tagged file for current file.
* @return tagged file, 0 if not available.
*/
TaggedFile
*
getTaggedFile
()
const
;
/**
* Get index of current file in playlist.
* @return index of current file.
*/
int
getCurrentIndex
()
const
;
/**
* Get the current playback position in milliseconds.
* @return time in milliseconds.
...
...
@@ -90,6 +118,30 @@ public:
*/
void
setCurrentPosition
(
quint64
position
);
/**
* Get playing state.
* @return state.
*/
State
getState
()
const
;
/**
* Get duration of current track in milliseconds.
* @return duration.
*/
qint64
getDuration
()
const
;
/**
* Get volume.
* @return volume level between 0 and 100.
*/
int
getVolume
()
const
;
/**
* Set volume.
* @param volume level between 0 and 100
*/
void
setVolume
(
int
volume
);
#ifdef HAVE_PHONON
/**
* Play a track from the files.
...
...
@@ -136,7 +188,31 @@ signals:
* Emitted when the current track position changed.
* @param position time in milliseconds
*/
void
positionChanged
(
qint64
position
);
void
positionChanged
(
qint64
position
);
/**
* Emitted when the current position is changed using setCurrentPosition().
* @param position time in milliseconds
*/
void
currentPositionChanged
(
qint64
position
);
/**
* Emitted when the playing state is changed.
* @param state playing state
*/
void
stateChanged
(
AudioPlayer
::
State
state
);
/**
* Emitted when the volume is changed.
* @param volume level between 0 and 100
*/
void
volumeChanged
(
int
volume
);
/**
* Emitted when the file count changed.
* @param count number of files in play list
*/
void
fileCountChanged
(
int
count
);
public
slots
:
/**
...
...
@@ -144,6 +220,16 @@ public slots:
*/
void
playOrPause
();
/**
* Resume playback.
*/
void
play
();
/**
* Pause playback.
*/
void
pause
();
/**
* Stop playback.
*/
...
...
@@ -170,6 +256,12 @@ private slots:
* Queue next track when the current track is about to finish.
*/
void
aboutToFinish
();
/**
* Signal volumeChanged() when the volume is changed.
* @param volume volume
*/
void
onVolumeChanged
(
qreal
volume
);
#else
/**
* Update display and button state when the current source is changed.
...
...
@@ -177,8 +269,13 @@ private slots:
*/
void
currentIndexChanged
(
int
position
);
#endif
/**
* Signal stateChanged() when the playing state is changed.
*/
void
onStateChanged
();
private:
Kid3Application
*
m_app
;
#ifdef HAVE_PHONON
/**
* Select a track from the files and optionally start playing it.
...
...
src/core/model/kid3application.cpp
View file @
9f9cf498
...
...
@@ -86,6 +86,9 @@
#include "iusercommandprocessor.h"
#if defined HAVE_PHONON || QT_VERSION >= 0x050000
#include "audioplayer.h"
#ifdef HAVE_QTDBUS
#include "mprisinterface.h"
#endif
#endif
#include "importplugins.h"
...
...
@@ -516,7 +519,14 @@ AudioPlayer* Kid3Application::getAudioPlayer()
{
if
(
!
m_player
)
{
m_player
=
new
AudioPlayer
(
this
);
#ifdef HAVE_QTDBUS
new
MprisInterface
(
m_player
);
new
MprisPlayerInterface
(
m_player
);
#endif
}
#ifdef HAVE_QTDBUS
activateMprisInterface
();
#endif
return
m_player
;
}
...
...
@@ -526,10 +536,69 @@ AudioPlayer* Kid3Application::getAudioPlayer()
void
Kid3Application
::
deleteAudioPlayer
()
{
if
(
m_player
)
{
m_player
->
stop
();
#ifdef HAVE_QTDBUS
deactivateMprisInterface
();
#endif
delete
m_player
;
m_player
=
0
;
}
}
#ifdef HAVE_QTDBUS
/**
* Activate the MPRIS D-Bus Interface if not already active.
*/
void
Kid3Application
::
activateMprisInterface
()
{
if
(
!
m_mprisServiceName
.
isEmpty
()
||
!
m_player
)
return
;
if
(
QDBusConnection
::
sessionBus
().
isConnected
())
{
m_mprisServiceName
=
QLatin1String
(
"org.mpris.MediaPlayer2.kid3"
);
bool
ok
=
QDBusConnection
::
sessionBus
().
registerService
(
m_mprisServiceName
);
if
(
!
ok
)
{
// If another instance of Kid3 is already running register a service
// with ".instancePID" appended, see
// https://specifications.freedesktop.org/mpris-spec/latest/
m_mprisServiceName
+=
QLatin1String
(
".instance"
);
m_mprisServiceName
+=
QString
::
number
(
::
getpid
());
ok
=
QDBusConnection
::
sessionBus
().
registerService
(
m_mprisServiceName
);
}
if
(
ok
)
{
if
(
!
QDBusConnection
::
sessionBus
().
registerObject
(
QLatin1String
(
"/org/mpris/MediaPlayer2"
),
m_player
))
{
qWarning
(
"Registering D-Bus MPRIS object failed"
);
}
}
else
{
m_mprisServiceName
.
clear
();
qWarning
(
"Registering D-Bus MPRIS service failed"
);
}
}
else
{
qWarning
(
"Cannot connect to the D-BUS session bus."
);
}
}
/**
* Deactivate the MPRIS D-Bus Interface if it is active.
*/
void
Kid3Application
::
deactivateMprisInterface
()
{
if
(
m_mprisServiceName
.
isEmpty
())
return
;
if
(
QDBusConnection
::
sessionBus
().
isConnected
())
{
QDBusConnection
::
sessionBus
().
unregisterObject
(
QLatin1String
(
"/org/mpris/MediaPlayer2"
));
if
(
QDBusConnection
::
sessionBus
().
unregisterService
(
m_mprisServiceName
))
{
m_mprisServiceName
.
clear
();
}
else
{
qWarning
(
"Unregistering D-Bus MPRIS service failed"
);
}
}
else
{
qWarning
(
"Cannot connect to the D-BUS session bus."
);
}
}
#endif
#endif
/**
...
...
src/core/model/kid3application.h
View file @
9f9cf498
...
...
@@ -1060,6 +1060,18 @@ public slots:
* Show play tool bar.
*/
void
showAudioPlayer
();
#ifdef HAVE_QTDBUS
/**
* Activate the MPRIS D-Bus Interface if not already active.
*/
void
activateMprisInterface
();
/**
* Deactivate the MPRIS D-Bus Interface if it is active.
*/
void
deactivateMprisInterface
();
#endif
#endif
/**
...
...
@@ -1322,6 +1334,9 @@ private:
#if defined HAVE_PHONON || QT_VERSION >= 0x050000
/** Audio player */
AudioPlayer
*
m_player
;
#ifdef HAVE_QTDBUS
QString
m_mprisServiceName
;
#endif
#endif
FileFilter
*
m_expressionFileFilter
;
/** Information about selected tagged files */
...
...
src/core/model/mprisinterface.cpp
0 → 100644
View file @
9f9cf498
/**
* \file mprisinterface.cpp
* MPRIS D-Bus interface for audio player.
*
* \b Project: Kid3
* \author Urs Fleisch
* \date 09-Dec-2016
*
* Copyright (C) 2016 Urs Fleisch
*
* This file is part of Kid3.
*
* Kid3 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Kid3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mprisinterface.h"
#if (defined HAVE_PHONON || QT_VERSION >= 0x050000) && defined HAVE_QTDBUS
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusObjectPath>
#include <QUrl>
#include <QDir>
#include <QTemporaryFile>
#include <QApplication>
#include "audioplayer.h"
#include "taggedfile.h"
#include "trackdata.h"
#include "pictureframe.h"
MprisInterface
::
MprisInterface
(
AudioPlayer
*
player
)
:
QDBusAbstractAdaptor
(
player
),
m_audioPlayer
(
player
)
{
}
MprisInterface
::~
MprisInterface
()
{
}
QString
MprisInterface
::
identity
()
const
{
return
QLatin1String
(
"Kid3"
);
}
QString
MprisInterface
::
desktopEntry
()
const
{
// Organization domain is only set in the KDE application.
return
QApplication
::
organizationDomain
().
isEmpty
()
?
QLatin1String
(
"kid3-qt"
)
:
QLatin1String
(
"kid3"
);
}
QStringList
MprisInterface
::
supportedUriSchemes
()
const
{
return
QStringList
()
<<
QLatin1String
(
"file"
);
}
QStringList
MprisInterface
::
supportedMimeTypes
()
const
{
return
QStringList
()
<<
QLatin1String
(
"audio/mpeg"
)
<<
QLatin1String
(
"audio/ogg"
)
<<
QLatin1String
(
"application/ogg"
)
<<
QLatin1String
(
"audio/x-flac"
)
<<
QLatin1String
(
"audio/x-flac+ogg"
)
<<
QLatin1String
(
"audio/x-vorbis+ogg"
)
<<
QLatin1String
(
"audio/x-speex+ogg"
)
<<
QLatin1String
(
"audio/x-oggflac"
)
<<
QLatin1String
(
"audio/x-musepack"
)
<<
QLatin1String
(
"audio/aac"
)
<<
QLatin1String
(
"audio/mp4"
)
<<
QLatin1String
(
"audio/x-speex"
)
<<
QLatin1String
(
"audio/x-tta"
)
<<
QLatin1String
(
"audio/x-wavpack"
)
<<
QLatin1String
(
"audio/x-aiff"
)
<<
QLatin1String
(
"audio/x-it"
)