Qt multimedia with the ffmpeg backend suddenly started sending
LoadedMedia signals in the PlayingState, even though that should not be
a valid combination according to the docs. This is messing up the
AudioManager.
- Don't make them QObjects; those are heavy and there's no reason for that
- In fact, don't make them objects at all; we're only using them in string form anyway
Make error reporting less ambiguous: report either "no connection" or
"not allowed on metered connection". Also show hint how to disable
network status checking altogether.
BUG: 475400
This would happen when the current track is changed to "no track".
Signals from the backend KMediaSession would still trigger duration()
calls which would try to dereference the pointer to the current track
entry.
SolidExtras will still be used for the Qt5 version for the time being.
This refactoring makes it trivial to rip out SolidExtras once the jump
to Qt6-only will be made.
Stop spamming the DBus with positionChanged signals if playback is
progressing at the nominal playback rate. This brings the
implementation in line with the MPRIS2 player spec. The previous
implementation was causing android battery drain issues with KDEConnect
constantly updating the position (and player details) on the notification
widget.
This implementation will still send the current playback position every
10 seconds to ensure that clients that don't implement the standard
properly or did not receive previous messages, will still get regularly
updated.
This also fixes correct signaling of playback rate changes over DBus.
Make seek times adjustable. Expose seek time under Playback Settings.
Set min time allowed in seconds to 1 and max time in seconds to 300.
FEATURE: 468686
Before the introduction of streaming, the "status" would be removed when
an episode was downloaded or marked as played, which made sense. With
the introduction of streaming it makes sense to also remove the "new"
status when (streaming) playback starts. At that point in time the
episode should indeed no longer considered to be "new".
libVLC has a hardcoded maximum number of redirects. Several podcasts
need more than this number. Therefore we resolve the final url through
QNetworkReply and send the final url to the audio player.
AudioManager was reporting no connectivity in case the networkstatus was
reported as being "Unknown". We might as well attempt to stream in that
case. If there is no connectivity, it will fail anyway with another
useful error message.
KMediaSession is an audio player library that has an API which is close
to QMediaPlayer and which allows to use --- and dynamically switch
between --- different audio backends. At this moment there is
implementation for libVLC, gstreamer and QtMultimedia. Only QtMultimedia
is a hard dependency in order to at least have one functional backend on
all platforms; all other dependencies are optional.
KMediaSession has out-of-the-box, built-in MPRIS2 support, sleep inhibit,
and basic metadata support.
BUG: 462358
Closes#35
This implements support for streaming episodes rather than downloading them
first.
This introduces a new setting: prioritizeStreaming. If it's set to false
(default) then a streaming play button is only added to the EntryPage. If
it is set to true, then the streaming play button will also appear on the
Entry delegates instead of the download button.
There is a separate setting to decide if streaming is also allowed on
metered connections.
FEATURE: 438864
This implements the gpodder API from scratch. It turned out that
libmygpo-qt has several critical bugs, and there's no response to pull
requests upstream. So using that library was not an option.
The implementation into kasts consists of the following:
- Can sync with gpodder.net or with a nextcloud server that has the
nextcloud-gpodder app installed. (This app is mostly API compatible
with gpodder.)
- Passwords are stored using qtkeychain. If the keychain is
unavailable it will fallback to file.
- It syncs podcast subscriptions and episode play positions, including
marking episodes as played. Episodes that have a non-zero play
position will be added to the queue automatically.
- It will check for a metered connection before syncing. This is
coupled to the allowMeteredFeedUpdates setting.
- Full synchronization can be performed either manually (from the
settings page) or through automatic triggers: on startup and/or on
feed refresh.
- There is an additional possibility to trigger quick upload-only syncs
to make sure that the local changes are immediately uploaded to the
server (if the connection allows). This will trigger when
subscriptions are added or removed, when the pause/play button is
toggled or an episode is marked as played.
- This implements a few safeguards to avoid having multiple feed URLS
pointing to the same underlying feed (e.g. http vs https). This
solves part of #17
Solves #13
This adds a new setting to the Settings page.
Existing enclosures and images will be moved to the new location
(first copied, then deleted in the original location). If any of
the copy actions fail, the operation is aborted and the original
path is restored.
The StorageMoveJob is set up in such a way that it's easy to add other
files or subfolders in the future.
Solves #15
The main bits of this implementation are:
- Start a new track in paused state. We don't care about the actual
media state or player state that QMediaPlayer is reporting. We will
deal with that when the audio actually starts playing.
- If a player position needs to be restored, we set d->m_pendingSeek to
the position that needs to be seeked. We don't actually seek because
we have no idea what state the player is in yet.
- On the positionChanged signal of QMP, and if the media is buffered, we
check if there is pendingSeek value set which is set to a different
value than the current player position. If so, we call
d->m_player.setPosition(). If we have arrived at the correct
position, then we reset d->m_pendingSeek to -1.
- In the position(), duration() and seek() methods, we return sensible
values, even QMP is not. So, we report the duration from the
enclosure, the position from d->m_pendingSeek, and let seek() change
the value of d->m_PendingSeek (if it's not -1) to the new seek
position.
- When there's a pending seek, we set the notifyInterval to shorter
interval to reduce the startup audio glitch as much as possible. We
then reset it to the default of 1000 msec.
This was tested on linux and android.
Making it toggle based on the playerState did not work properly because
the stream is toggling between pause and play several times in the
prepareAudioStream method.
GStreamer is not used as QMediaPlayer backend on other platforms, so
audio will not start with a custom gst-pipeline on Android and Windows.
Still needs a solution to get rid of the horrible pitch change on
Android and Windows, though.
This allows the hack to be re-used in the play() method. Apparently on
some systems the stream becomes unresponsive again after pausing. So
probably it's required to ensure that the stream is fully seekable and
buffered before restarting playback.