diff --git a/approot/templates.xml b/approot/templates.xml
index b7924f8d..1f8f11a6 100644
--- a/approot/templates.xml
+++ b/approot/templates.xml
@@ -529,7 +529,7 @@
- ${shuffle} ${repeat} ${playlist} ${prev} ${play-pause} ${next} ${cover} ${artist} ${track} ${release} ${curtime} ${seekbar} ${duration} ${volume}
+ ${audio}${prev}${play-pause}${next}${cover}${artist}${track}${release}${curtime}${seekbar}${duration}${volume}${shuffle}${repeat}${playlist}
diff --git a/docroot/css/lms.css b/docroot/css/lms.css
index afe63087..304be0ac 100644
--- a/docroot/css/lms.css
+++ b/docroot/css/lms.css
@@ -10,11 +10,6 @@
background-color: white;
}
-div.contents {
- padding: 0px 12px 6px;
- margin-bottom: 64px;
-}
-
.playqueue {
background-color: #EEE;
border-radius: 10px;
@@ -40,15 +35,6 @@ div.contents {
height: 64px;
}
-.mediaplayer {
- background-color: #CCC;
- border-radius: 10px;
- min-width: 360px;
-}
-
-.mediaplayer-btn-controls {
- font-weight: bold;
-}
.mediaplayer-current-cover {
width: 72px;
@@ -57,15 +43,36 @@ div.contents {
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5);
}
-.mediaplayer-current-track {
+.mediaplayer-track {
font-weight: bold;
font-size: 120%;
}
-.mediaplayer-current-artist {
+.mediaplayer-artist {
font-style: italic;
}
+.mediaplayer {
+ background-color: #CCC;
+ border-radius: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: 72px;
+}
+
+.mediaplayer-btn {
+ margin: 8px;
+}
+
+.mediaplayer-btn:before {
+ cursor: pointer;
+}
+
+.mediaplayer-btn-active {
+ color: #428bca;
+}
+
.mobile-search-title {
font-weight: bold;
height: 32px;
diff --git a/src/Makefile.am b/src/Makefile.am
index 7cc1077c..e6b0f919 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,6 @@ lms_SOURCES = \
$(srcdir)/ui/auth/LmsAuth.cpp \
$(srcdir)/ui/audio/AudioPlayer.cpp \
$(srcdir)/ui/audio/desktop/DesktopAudio.cpp \
- $(srcdir)/ui/audio/desktop/AudioMediaPlayer.cpp \
$(srcdir)/ui/audio/desktop/FilterChain.cpp \
$(srcdir)/ui/audio/desktop/KeywordSearchFilter.cpp \
$(srcdir)/ui/audio/desktop/PlayQueue.cpp \
diff --git a/src/ui/audio/AudioPlayer.cpp b/src/ui/audio/AudioPlayer.cpp
index f529dc78..be5b68c3 100644
--- a/src/ui/audio/AudioPlayer.cpp
+++ b/src/ui/audio/AudioPlayer.cpp
@@ -33,7 +33,7 @@
namespace UserInterface {
-void
+bool
AudioPlayer::loadTrack(Database::Track::id_type trackId)
{
Wt::Dbo::Transaction transaction(DboSession());
@@ -42,7 +42,7 @@ AudioPlayer::loadTrack(Database::Track::id_type trackId)
if (!track)
{
LMS_LOG(UI, INFO) << "No track found for id " << trackId;
- return;
+ return false;
}
_trackName->setText(Wt::WString::fromUTF8(track->getName()));
@@ -57,7 +57,7 @@ AudioPlayer::loadTrack(Database::Track::id_type trackId)
if (!mediaFile.open() || !mediaFile.scan())
{
LMS_LOG(UI, ERROR) << "Cannot open file '" << track->getPath();
- return;
+ return false;
}
@@ -79,120 +79,170 @@ AudioPlayer::loadTrack(Database::Track::id_type trackId)
//TODO, try to load everything in JS in order to prevent the WriteError bug?
_audio->pause();
_audio->clearSources();
- //TODOencoding
+ //TODO, encoding
_audio->addSource(SessionTranscodeResource()->getUrl(trackId, Av::Encoding::MP3, 0, streams));
+ _audio->setPreloadMode(Wt::WAudio::PreloadAuto);
_audio->play();
+
+ return true;
}
AudioPlayer::AudioPlayer(Wt::WContainerWidget *parent)
-: Wt::WContainerWidget(parent)
+: Wt::WTemplate(parent)
{
- Wt::WTemplate *t = new Wt::WTemplate(this);
- t->setTemplateText(Wt::WString::tr("wa-audio-player"));
+ setTemplateText(Wt::WString::tr("wa-audio-player"));
+ addStyleClass("mediaplayer");
- _audio = new Wt::WAudio(this);
+ // TODO potential leak here
+ _audio = new Wt::WAudio();
_audio->setOptions(Wt::WAudio::Autoplay);
_audio->setPreloadMode(Wt::WAudio::PreloadAuto);
+ bindWidget("audio", _audio);
+
+ _audio->ended().connect(std::bind([=] ()
+ {
+ _playbackEnded.emit();
+ }));
_cover = new Wt::WImage();
- t->bindWidget("cover", _cover);
+ bindWidget("cover", _cover);
_cover->setImageLink(SessionCoverResource()->getUnknownTrackUrl(64));
InputRange *seekbar = new InputRange();
- t->bindWidget("seekbar", seekbar);
+ bindWidget("seekbar", seekbar);
_trackName = new Wt::WText();
- t->bindWidget("track", _trackName);
+ bindWidget("track", _trackName);
_artistName = new Wt::WText();
- t->bindWidget("artist", _artistName);
+ bindWidget("artist", _artistName);
_releaseName = new Wt::WText();
- t->bindWidget("release", _releaseName);
+ bindWidget("release", _releaseName);
InputRange *volumeSlider = new InputRange();
- t->bindWidget("volume", volumeSlider);
+ bindWidget("volume", volumeSlider);
- Wt::WPushButton *playlistBtn = new Wt::WPushButton("", Wt::XHTMLText);
- t->bindWidget("playlist", playlistBtn);
+ Wt::WText *playlistBtn = new Wt::WText("", Wt::XHTMLText);
+ playlistBtn->addStyleClass("mediaplayer-btn");
+ bindWidget("playlist", playlistBtn);
- Wt::WPushButton *repeatBtn = new Wt::WPushButton("", Wt::XHTMLText);
- t->bindWidget("repeat", repeatBtn);
+ Wt::WText *repeatBtn = new Wt::WText("", Wt::XHTMLText);
+ repeatBtn->addStyleClass("mediaplayer-btn");
+ bindWidget("repeat", repeatBtn);
+ repeatBtn->clicked().connect(std::bind([=] ()
+ {
+ if (repeatBtn->hasStyleClass("mediaplayer-btn-active"))
+ {
+ repeatBtn->removeStyleClass("mediaplayer-btn-active");
+ _loop.emit(false);
+ }
+ else
+ {
+ repeatBtn->addStyleClass("mediaplayer-btn-active");
+ _loop.emit(true);
+ }
+ }));
- Wt::WPushButton *shuffleBtn = new Wt::WPushButton("", Wt::XHTMLText);
- t->bindWidget("shuffle", shuffleBtn);
+ Wt::WText *shuffleBtn = new Wt::WText("", Wt::XHTMLText);
+ shuffleBtn->addStyleClass("mediaplayer-btn");
+ bindWidget("shuffle", shuffleBtn);
+ shuffleBtn->clicked().connect(std::bind([=] ()
+ {
+ if (shuffleBtn->hasStyleClass("mediaplayer-btn-active"))
+ {
+ shuffleBtn->removeStyleClass("mediaplayer-btn-active");
+ _shuffle.emit(false);
+ }
+ else
+ {
+ shuffleBtn->addStyleClass("mediaplayer-btn-active");
+ _shuffle.emit(true);
+ }
+ }));
- Wt::WPushButton *prevBtn = new Wt::WPushButton("", Wt::XHTMLText);
- t->bindWidget("prev", prevBtn);
+ Wt::WText *prevBtn = new Wt::WText("", Wt::XHTMLText);
+ prevBtn->addStyleClass("mediaplayer-btn");
+ bindWidget("prev", prevBtn);
+ prevBtn->clicked().connect(std::bind([=] ()
+ {
+ _playPrevious.emit();
+ }));
- Wt::WPushButton *nextBtn = new Wt::WPushButton("", Wt::XHTMLText);
- t->bindWidget("next", nextBtn);
+ Wt::WText *nextBtn = new Wt::WText("", Wt::XHTMLText);
+ nextBtn->addStyleClass("mediaplayer-btn");
+ bindWidget("next", nextBtn);
+ nextBtn->clicked().connect(std::bind([=] ()
+ {
+ _playNext.emit();
+ }));
- Wt::WPushButton *playPauseBtn = new Wt::WPushButton("", Wt::XHTMLText);
- t->bindWidget("play-pause", playPauseBtn);
+ Wt::WText *playPauseBtn = new Wt::WText("", Wt::XHTMLText);
+ playPauseBtn->addStyleClass("mediaplayer-btn");
+ bindWidget("play-pause", playPauseBtn);
Wt::WText *trackCurrentTime = new Wt::WText("00:00");
- t->bindWidget("curtime", trackCurrentTime);
+ bindWidget("curtime", trackCurrentTime);
_trackDuration = new Wt::WText("00:00");
- t->bindWidget("duration", _trackDuration);
+ bindWidget("duration", _trackDuration);
this->doJavaScript(
- "\
- document.lms = {};\
- document.lms.audio = {};\
- document.lms.audio.audio = " + _audio->jsRef() + ";\
- document.lms.audio.seekbar = " + seekbar->jsRef() +";\
- document.lms.audio.volumeSlider = " + volumeSlider->jsRef() + ";\
- document.lms.audio.curTimeText = " + trackCurrentTime->jsRef() + ";\
- document.lms.audio.playPause = " + playPauseBtn->jsRef() + ";\
- \
- document.lms.audio.offset = 0;\
- document.lms.audio.curTime = 0;\
- document.lms.audio.state = \"init\";\
- document.lms.audio.volume = 1;\
- \
- document.lms.audio.seekbar.value = 0;\
- document.lms.audio.seekbar.disabled = true;\
- \
- document.lms.audio.volumeSlider.min = 0;\
- document.lms.audio.volumeSlider.max = 100;\
- document.lms.audio.volumeSlider.value = 100;\
- \
- function updateUI() {\
- document.lms.audio.curTimeText.innerHTML = document.lms.audio.curTime;\
- document.lms.audio.seekbar.value = document.lms.audio.curTime;\
- }\
+ "\
+ document.lms = {};\
+ document.lms.audio = {};\
+ document.lms.audio.audio = " + _audio->jsRef() + ";\
+ document.lms.audio.seekbar = " + seekbar->jsRef() +";\
+ document.lms.audio.volumeSlider = " + volumeSlider->jsRef() + ";\
+ document.lms.audio.curTimeText = " + trackCurrentTime->jsRef() + ";\
+ document.lms.audio.playPause = " + playPauseBtn->jsRef() + ";\
+ \
+ document.lms.audio.offset = 0;\
+ document.lms.audio.curTime = 0;\
+ document.lms.audio.state = \"init\";\
+ document.lms.audio.volume = 1;\
+ \
+ document.lms.audio.seekbar.value = 0;\
+ document.lms.audio.seekbar.disabled = true;\
+ \
+ document.lms.audio.volumeSlider.min = 0;\
+ document.lms.audio.volumeSlider.max = 100;\
+ document.lms.audio.volumeSlider.value = 100;\
+ \
+ function updateUI() {\
+ document.lms.audio.curTimeText.innerHTML = document.lms.audio.curTime;\
+ document.lms.audio.seekbar.value = document.lms.audio.curTime;\
+ }\
\
var mouseDown = 0;\
function seekMouseDown(e) {\
++mouseDown;\
}\
- function seekMouseUp(e) {\
- --mouseDown;\
- }\
+ function seekMouseUp(e) {\
+ --mouseDown;\
+ }\
\
function seeking(e) {\
if (document.lms.audio.state == \"init\")\
return;\
- \
- document.lms.audio.curTimeText.innerHTML = document.lms.audio.seekbar.value;\
+ \
+ document.lms.audio.curTimeText.innerHTML = document.lms.audio.seekbar.value;\
}\
\
function seek(e) {\
if (document.lms.audio.state == \"init\")\
return;\
- \
- document.lms.audio.audio.pause(); \
- document.lms.audio.offset = parseInt(document.lms.audio.seekbar.value);\
- document.lms.audio.curTime = document.lms.audio.seekbar.value;\
- var audioSource = document.lms.audio.audio.getElementsByTagName(\"source\")[0];\
- var src = audioSource.src;\
- src = src.slice(0, src.lastIndexOf(\"=\") + 1);\
- audioSource.src = src + document.lms.audio.seekbar.value;\
- document.lms.audio.audio.load(); \
- document.lms.audio.audio.play(); \
- document.lms.audio.curTimeText.innerHTML = ~~document.lms.audio.curTime + \" \";\
+ \
+ document.lms.audio.audio.pause(); \
+ document.lms.audio.offset = parseInt(document.lms.audio.seekbar.value);\
+ document.lms.audio.curTime = document.lms.audio.seekbar.value;\
+ var audioSource = document.lms.audio.audio.getElementsByTagName(\"source\")[0];\
+ var src = audioSource.src;\
+ src = src.slice(0, src.lastIndexOf(\"=\") + 1);\
+ audioSource.src = src + document.lms.audio.seekbar.value;\
+ document.lms.audio.audio.load(); \
+ document.lms.audio.audio.play(); \
+ document.lms.audio.curTimeText.innerHTML = ~~document.lms.audio.curTime + \" \";\
}\
\
function volumeChanged() {\
@@ -208,12 +258,12 @@ AudioPlayer::AudioPlayer(Wt::WContainerWidget *parent)
function playPause() {\
if (document.lms.audio.state == \"init\") \
return;\
- \
- if (document.lms.audio.audio.paused)\
- document.lms.audio.audio.play();\
- else\
- document.lms.audio.audio.pause();\
- \
+ \
+ if (document.lms.audio.audio.paused)\
+ document.lms.audio.audio.play();\
+ else\
+ document.lms.audio.audio.pause();\
+ \
}\
\
document.lms.audio.audio.addEventListener('timeupdate', updateCurTime); \
@@ -223,8 +273,8 @@ AudioPlayer::AudioPlayer(Wt::WContainerWidget *parent)
document.lms.audio.seekbar.addEventListener('mouseup', seekMouseUp);\
document.lms.audio.volumeSlider.addEventListener('input', volumeChanged);\
document.lms.audio.playPause.addEventListener('click', playPause);\
- "
- );
+ "
+ );
}
diff --git a/src/ui/audio/AudioPlayer.hpp b/src/ui/audio/AudioPlayer.hpp
index f202e93e..fdc81607 100644
--- a/src/ui/audio/AudioPlayer.hpp
+++ b/src/ui/audio/AudioPlayer.hpp
@@ -19,23 +19,38 @@
#pragma once
+#include
+#include
+
#include "common/InputRange.hpp"
#include "database/Types.hpp"
namespace UserInterface {
-class AudioPlayer : public Wt::WContainerWidget
+class AudioPlayer : public Wt::WTemplate
{
public:
AudioPlayer(Wt::WContainerWidget *parent = 0);
- void loadTrack(Database::Track::id_type trackId);
+ bool loadTrack(Database::Track::id_type trackId);
- // Slots
+ // Signals
+ Wt::Signal& playbackEnded() {return _playbackEnded;}
+ Wt::Signal& playNext() {return _playNext;}
+ Wt::Signal& playPrevious() {return _playPrevious;}
+ Wt::Signal& shuffle() {return _shuffle;}
+ Wt::Signal& loop() {return _loop;}
private:
+ // Signals
+ Wt::Signal _playbackEnded;
+ Wt::Signal _playNext;
+ Wt::Signal _playPrevious;
+ Wt::Signal _shuffle;
+ Wt::Signal _loop;
+
Wt::WAudio* _audio;
Wt::WText* _trackDuration;
Wt::WText* _trackName;
diff --git a/src/ui/audio/desktop/AudioMediaPlayer.cpp b/src/ui/audio/desktop/AudioMediaPlayer.cpp
deleted file mode 100644
index 42d9e6cb..00000000
--- a/src/ui/audio/desktop/AudioMediaPlayer.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2013 Emeric Poupon
- *
- * This file is part of LMS.
- *
- * LMS 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 3 of the License, or
- * (at your option) any later version.
- *
- * LMS 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 LMS. If not, see .
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "logger/Logger.hpp"
-
-#include "LmsApplication.hpp"
-
-#include "AudioMediaPlayer.hpp"
-
-namespace UserInterface {
-namespace Desktop {
-
-Wt::WMediaPlayer::Encoding
-AudioMediaPlayer::getBestEncoding()
-{
- // MP3 seems to be better supported everywhere
- return Wt::WMediaPlayer::MP3;
-}
-
-AudioMediaPlayer::AudioMediaPlayer(Wt::WContainerWidget *parent)
- : Wt::WContainerWidget(parent),
- _mediaResource(nullptr)
-{
- this->setStyleClass("mediaplayer");
-
- Wt::WVBoxLayout* mainLayout = new Wt::WVBoxLayout();
- this->setLayout(mainLayout);
-
- // Determine the encoding to be used
- {
- Wt::Dbo::Transaction transaction(DboSession());
- switch (CurrentUser()->getAudioEncoding())
- {
- case Database::AudioEncoding::MP3: _encoding = Wt::WMediaPlayer::MP3; break;
- case Database::AudioEncoding::WEBMA: _encoding = Wt::WMediaPlayer::WEBMA; break;
- case Database::AudioEncoding::OGA: _encoding = Wt::WMediaPlayer::OGA; break;
- case Database::AudioEncoding::AUTO:
- default:
- _encoding = getBestEncoding();
- }
- }
-
- LMS_LOG(UI, INFO) << "Audio player using encoding " << _encoding;
-
- // Current Media info
- Wt::WHBoxLayout *currentMediaLayout = new Wt::WHBoxLayout();
- mainLayout->addLayout(currentMediaLayout, 1);
-
- currentMediaLayout->addWidget( _mediaCover = new Wt::WImage());
- _mediaCover->setImageLink( LmsApplication::instance()->getCoverResource()->getUnknownTrackUrl(72));
- _mediaCover->setStyleClass("mediaplayer-current-cover");
-
- Wt::WVBoxLayout* mediaInfoLayout = new Wt::WVBoxLayout();
- currentMediaLayout->addLayout(mediaInfoLayout, 1);
-
- mediaInfoLayout->addWidget( _mediaTitle = new Wt::WText("---"));
- mediaInfoLayout->addWidget( _mediaArtistRelease = new Wt::WText("---"));
- _mediaTitle->setStyleClass("mediaplayer-current-track vertical-align");
- _mediaArtistRelease->setStyleClass("mediaplayer-current-artist vertical-align");
-
- // Time control
- Wt::WHBoxLayout *sliderLayout = new Wt::WHBoxLayout();
- mainLayout->addLayout(sliderLayout);
-
- sliderLayout->addWidget(_curTime = new Wt::WText("00:00:00"));
- sliderLayout->addWidget(_timeSlider = new Wt::WSlider( ), 1);
- sliderLayout->addWidget(_duration = new Wt::WText("00:00:00"));
- _timeSlider->setHeight(26); // Default is too big (50)
- _curTime->setStyleClass("vertical-align");
- _duration->setStyleClass("vertical-align");
-
- // Controls
- Wt::WHBoxLayout *controlsLayout = new Wt::WHBoxLayout();
- mainLayout->addLayout(controlsLayout);
-
-
- Wt::WPushButton *prevBtn = new Wt::WPushButton("<<");
- controlsLayout->addWidget(prevBtn);
- prevBtn->setStyleClass("mediaplayer-btn-controls");
-
- Wt::WContainerWidget *btnContainer = new Wt::WContainerWidget();;
-
- _playBtn = new Wt::WPushButton("Play");
- btnContainer->addWidget(_playBtn);
- _playBtn->setWidth(70);
- _playBtn->setStyleClass("mediaplayer-btn-controls");
-
- _pauseBtn = new Wt::WPushButton("Pause");
- btnContainer->addWidget(_pauseBtn);
- _pauseBtn->setWidth(70);
- _pauseBtn->setStyleClass("mediaplayer-btn-controls");
-
- controlsLayout->addWidget(btnContainer);
-
- Wt::WPushButton *nextBtn = new Wt::WPushButton(">>");
- controlsLayout->addWidget(nextBtn);
- nextBtn->setStyleClass("mediaplayer-btn-controls");
-
- _volumeSlider = new Wt::WSlider();
- _volumeSlider->setRange(0,100);
- _volumeSlider->setWidth(60); // Default is too big (150)
- _volumeSlider->setHeight(26); // Default is too big (50)
- _volumeSlider->setMinimumSize(50, Wt::WLength::Auto);
- controlsLayout->addWidget(_volumeSlider, 1);
-
- Wt::WPushButton *loop = new Wt::WPushButton("Loop");
- loop->setCheckable(true);
- loop->setStyleClass("btn-xs");
- loop->checked().connect(std::bind([=] () { _loop.emit( true ); }));
- loop->unChecked().connect(std::bind([=] () { _loop.emit( false ); }));
- controlsLayout->addWidget(loop);
-
- Wt::WPushButton *shuffle = new Wt::WPushButton("Shuffle");
- shuffle->setCheckable(true);
- shuffle->setStyleClass("btn-xs");
- shuffle->checked().connect(std::bind([=] () { _shuffle.emit( true ); }));
- shuffle->unChecked().connect(std::bind([=] () { _shuffle.emit( false );}));
- controlsLayout->addWidget(shuffle);
-
- _mediaPlayer = new Wt::WMediaPlayer( Wt::WMediaPlayer::Audio, btnContainer );
- _mediaPlayer->addSource( _encoding, "" );
- _mediaPlayer->ended().connect(this, &AudioMediaPlayer::handleTrackEnded);
-
- _mediaPlayer->setControlsWidget( 0 );
- _mediaPlayer->setButton(Wt::WMediaPlayer::Play, _playBtn);
- _mediaPlayer->setButton(Wt::WMediaPlayer::Pause, _pauseBtn);
-
- _mediaPlayer->timeUpdated().connect(this, &AudioMediaPlayer::handleTimeUpdated);
-
- _volumeSlider->setValue(_mediaPlayer->volume() * 100);
-
- nextBtn->clicked().connect(std::bind([=] ()
- {
- _mediaPlayer->stop();
- _playNext.emit();
- }));
-
- prevBtn->clicked().connect(std::bind([=] ()
- {
- _mediaPlayer->stop();
- _playPrevious.emit();
- }));
- _timeSlider->valueChanged().connect(this, &AudioMediaPlayer::handlePlayOffset);
- _timeSlider->setDisabled(true);
-
- _volumeSlider->sliderMoved().connect(this, &AudioMediaPlayer::handleVolumeSliderMoved);
-
-}
-
-void
-AudioMediaPlayer::loadPlayer(boost::filesystem::path filePath, Av::TranscodeParameters& parameters)
-{
- _currentFile = filePath;
- _currentParameters = parameters;
-
- _mediaPlayer->clearSources();
-
- if (_mediaResource)
- delete _mediaResource;
-
- _mediaResource = new AvConvTranscodeStreamResource( filePath, parameters, this );
-
- _mediaPlayer->addSource( getEncoding(), Wt::WLink(_mediaResource));
-
- // Auto play
- _mediaPlayer->play();
-}
-
-bool
-AudioMediaPlayer::load(Database::Track::id_type trackId)
-{
- Av::TranscodeParameters parameters;
-
- boost::filesystem::path path;
-
- boost::posix_time::time_duration duration;
-
- {
- Wt::Dbo::Transaction transaction(DboSession());
-
- Database::Track::pointer track = Database::Track::getById(DboSession(), trackId);
- if (!track)
- {
- LMS_LOG(UI, INFO) << "Cannot find track id " << trackId;
- return false;
- }
-
- path = track->getPath();
- parameters.setBitrate(Av::Stream::Type::Audio, CurrentUser()->getAudioBitrate() );
-
- duration = track->getDuration();
-
- _mediaTitle->setText ( Wt::WString::fromUTF8(track->getName()) );
- _mediaArtistRelease->setText ( Wt::WString::fromUTF8(track->getArtist()->getName()) + " - " + Wt::WString::fromUTF8(track->getRelease()->getName()) );
- _mediaCover->setImageLink( Wt::WLink (LmsApplication::instance()->getCoverResource()->getTrackUrl(trackId, 72)));
- }
-
- Av::MediaFile mediaFile(path);
-
- if (!mediaFile.open() || !mediaFile.scan())
- {
- LMS_LOG(UI, INFO) << "Cannot open file '" << path << "'";
- return false;
- }
-
- // It seems to be far better to manually map the streams
- // otherwise, some files may have to be fully transcoded to be played by browser...
- int audioBestStreamId = mediaFile.getBestStreamId(Av::Stream::Type::Audio);
- if (audioBestStreamId != -1)
- parameters.addStream(audioBestStreamId);
-
- Av::Encoding encoding;
- switch (_encoding)
- {
- case Wt::WMediaPlayer::MP3: encoding = Av::Encoding::MP3; break;
- case Wt::WMediaPlayer::OGA: encoding = Av::Encoding::OGA; break;
- case Wt::WMediaPlayer::WEBMA: encoding = Av::Encoding::WEBMA; break;
- default:
- encoding = Av::Encoding::MP3;
- }
- parameters.setEncoding(encoding);
-
- _timeSlider->setDisabled(false);
- _timeSlider->setRange(0, duration.total_seconds() );
- _timeSlider->setValue(0);
-
- _duration->setText( boost::posix_time::to_simple_string( duration ));
-
- loadPlayer(path, parameters);
-
- return true;
-}
-
-void
-AudioMediaPlayer::handlePlayOffset(int offsetSecs)
-{
- Av::TranscodeParameters parameters = _currentParameters;
-
- parameters.setOffset( boost::posix_time::seconds(offsetSecs) );
-
- loadPlayer(_currentFile, parameters);
-}
-
-void
-AudioMediaPlayer::handleTrackEnded(void)
-{
- LMS_LOG(UI, INFO) << "Track ended!";
- _playbackEnded.emit();
-}
-
-void
-AudioMediaPlayer::handleTimeUpdated(void)
-{
- boost::posix_time::time_duration currentTime ( boost::posix_time::seconds( _mediaPlayer->currentTime() + _currentParameters.getOffset().total_seconds()));
-
- _timeSlider->setValue( currentTime.total_seconds() );
- _curTime->setText( boost::posix_time::to_simple_string( currentTime) );
-}
-
-void
-AudioMediaPlayer::handleVolumeSliderMoved(int value)
-{
- _mediaPlayer->setVolume( value / 100. );
-}
-
-} // namespace Desktop
-} // namespace UserInterface
diff --git a/src/ui/audio/desktop/AudioMediaPlayer.hpp b/src/ui/audio/desktop/AudioMediaPlayer.hpp
deleted file mode 100644
index 4c3b4416..00000000
--- a/src/ui/audio/desktop/AudioMediaPlayer.hpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2013 Emeric Poupon
- *
- * This file is part of LMS.
- *
- * LMS 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 3 of the License, or
- * (at your option) any later version.
- *
- * LMS 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 LMS. If not, see .
- */
-
-#ifndef __AUDIO_MEDIA_PLAYER_HPP
-#define __AUDIO_MEDIA_PLAYER_HPP
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "database/Types.hpp"
-
-#include "av/AvTranscoder.hpp"
-#include "resource/AvConvTranscodeStreamResource.hpp"
-#include "resource/CoverResource.hpp"
-
-namespace UserInterface {
-namespace Desktop {
-
-class AudioMediaPlayer : public Wt::WContainerWidget
-{
- public:
- static Wt::WMediaPlayer::Encoding getBestEncoding();
-
- AudioMediaPlayer(Wt::WContainerWidget *parent = 0);
-
- // Load Media to be played
- bool load(Database::Track::id_type trackId);
-
- // Accessors
- Wt::WMediaPlayer::Encoding getEncoding() const { return _encoding; }
-
- // Signal slots
- Wt::Signal& playbackEnded() {return _playbackEnded;}
- Wt::Signal& playNext() {return _playNext;}
- Wt::Signal& playPrevious() {return _playPrevious;}
- Wt::Signal& shuffle() {return _shuffle;}
- Wt::Signal& loop() {return _loop;}
-
-
- private:
-
- void handlePlayOffset(int offsetSecs);
- void handleTrackEnded(void);
-
- void handleValueChanged(double);
- void handleTimeUpdated(void);
- void handleSliderMoved(int value);
-
- void handleVolumeSliderMoved(int value);
-
- void loadPlayer(boost::filesystem::path filePath, Av::TranscodeParameters& parameters);
-
- // Signals
- Wt::Signal _playbackEnded;
- Wt::Signal _playNext;
- Wt::Signal _playPrevious;
- Wt::Signal _shuffle;
- Wt::Signal _loop;
-
- // Core
- Wt::WMediaPlayer* _mediaPlayer;
- AvConvTranscodeStreamResource* _mediaResource;
- Wt::WMediaPlayer::Encoding _encoding;
-
- // Media info
- Wt::WImage* _mediaCover;
- Wt::WText* _mediaTitle;
- Wt::WText* _mediaArtistRelease;
-
- // Controls
- Wt::WPushButton* _playBtn;
- Wt::WPushButton* _pauseBtn;
- Wt::WSlider* _timeSlider;
- Wt::WSlider* _volumeSlider;
- Wt::WText* _curTime;
- Wt::WText* _duration;
-
- // Transcode
- boost::filesystem::path _currentFile;
- Av::TranscodeParameters _currentParameters;
-
-};
-
-} // namespace Desktop
-} // namespace UserInterface
-
-#endif
-
diff --git a/src/ui/audio/desktop/DesktopAudio.cpp b/src/ui/audio/desktop/DesktopAudio.cpp
index 7e898a78..efcd13c3 100644
--- a/src/ui/audio/desktop/DesktopAudio.cpp
+++ b/src/ui/audio/desktop/DesktopAudio.cpp
@@ -120,73 +120,72 @@ _playQueue(nullptr)
_playQueue = new PlayQueue();
// Playlist/PlayQueue
+ Wt::WContainerWidget* playQueueContainer = new Wt::WContainerWidget();
+ playQueueContainer->setStyleClass("playqueue");
+ Wt::WVBoxLayout* playQueueLayout = new Wt::WVBoxLayout();
+ playQueueContainer->setLayout(playQueueLayout);
+
+ playQueueLayout->addWidget( _playQueue, 1);
+
+ Wt::WHBoxLayout* playlistControls = new Wt::WHBoxLayout();
+
+ Wt::WPushButton *playlistBtn = new Wt::WPushButton("Playlist");
+ playlistBtn->setStyleClass("btn-sm btn-primary");
+ playlistControls->addWidget(playlistBtn);
+
+ // Playlist menu
+ {
+ Wt::WPopupMenu *popupMain = new Wt::WPopupMenu();
+
+ _popupMenuSave = new Wt::WPopupMenu();
+ popupMain->addMenu("Save", _popupMenuSave);
+
+ _popupMenuLoad = new Wt::WPopupMenu();
+ popupMain->addMenu("Load", _popupMenuLoad);
+
+ _popupMenuDelete = new Wt::WPopupMenu();
+ popupMain->addMenu("Delete", _popupMenuDelete);
+
+ playlistBtn->setMenu(popupMain);
+ }
+
+ Wt::WPushButton *upBtn = new Wt::WPushButton("UP");
+ upBtn->setStyleClass("btn-sm");
+ playlistControls->addWidget(upBtn);
+ Wt::WPushButton *downBtn = new Wt::WPushButton("DO");
+ downBtn->setStyleClass("btn-sm");
+ playlistControls->addWidget(downBtn);
+ Wt::WPushButton *delBtn = new Wt::WPushButton("DEL");
+ delBtn->setStyleClass("btn-sm btn-warning");
+ playlistControls->addWidget(delBtn);
+ Wt::WPushButton *clearBtn = new Wt::WPushButton("CLR");
+ clearBtn->setStyleClass("btn-sm btn-danger");
+ playlistControls->addWidget(clearBtn);
+
+ delBtn->clicked().connect(_playQueue, &PlayQueue::delSelected);
+ upBtn->clicked().connect(_playQueue, &PlayQueue::moveSelectedUp);
+ downBtn->clicked().connect(_playQueue, &PlayQueue::moveSelectedDown);
+ clearBtn->clicked().connect(_playQueue, &PlayQueue::delAll);
+
+ playQueueLayout->addLayout(playlistControls);
+
+ mainLayout->addWidget(playQueueContainer, 0, 0, 2, 1);
+
+ // Load the last known queue
+ playlistLoadToPlayqueue(CurrentQueuePlaylistName);
+
+ // Select the last known playing track
{
Wt::Dbo::Transaction transaction(DboSession());
-
- Wt::WContainerWidget* playQueueContainer = new Wt::WContainerWidget();
- playQueueContainer->setStyleClass("playqueue");
- Wt::WVBoxLayout* playQueueLayout = new Wt::WVBoxLayout();
- playQueueContainer->setLayout(playQueueLayout);
-
- _mediaPlayer = new AudioMediaPlayer();
- playQueueLayout->addWidget(_mediaPlayer);
-
- playQueueLayout->addWidget( _playQueue, 1);
-
- Wt::WHBoxLayout* playlistControls = new Wt::WHBoxLayout();
-
- Wt::WPushButton *playlistBtn = new Wt::WPushButton("Playlist");
- playlistBtn->setStyleClass("btn-sm btn-primary");
- playlistControls->addWidget(playlistBtn);
-
- // Playlist menu
- {
- Wt::WPopupMenu *popupMain = new Wt::WPopupMenu();
-
- _popupMenuSave = new Wt::WPopupMenu();
- popupMain->addMenu("Save", _popupMenuSave);
-
- _popupMenuLoad = new Wt::WPopupMenu();
- popupMain->addMenu("Load", _popupMenuLoad);
-
- _popupMenuDelete = new Wt::WPopupMenu();
- popupMain->addMenu("Delete", _popupMenuDelete);
-
- playlistBtn->setMenu(popupMain);
- }
-
- Wt::WPushButton *upBtn = new Wt::WPushButton("UP");
- upBtn->setStyleClass("btn-sm");
- playlistControls->addWidget(upBtn);
- Wt::WPushButton *downBtn = new Wt::WPushButton("DO");
- downBtn->setStyleClass("btn-sm");
- playlistControls->addWidget(downBtn);
- Wt::WPushButton *delBtn = new Wt::WPushButton("DEL");
- delBtn->setStyleClass("btn-sm btn-warning");
- playlistControls->addWidget(delBtn);
- Wt::WPushButton *clearBtn = new Wt::WPushButton("CLR");
- clearBtn->setStyleClass("btn-sm btn-danger");
- playlistControls->addWidget(clearBtn);
-
- delBtn->clicked().connect(_playQueue, &PlayQueue::delSelected);
- upBtn->clicked().connect(_playQueue, &PlayQueue::moveSelectedUp);
- downBtn->clicked().connect(_playQueue, &PlayQueue::moveSelectedDown);
- clearBtn->clicked().connect(_playQueue, &PlayQueue::delAll);
-
-
- playQueueLayout->addLayout(playlistControls);
-
- mainLayout->addWidget(playQueueContainer, 0, 0, 2, 1);
-
- // Load the last known queue
- playlistLoadToPlayqueue(CurrentQueuePlaylistName);
- // Select the last known playing track
_playQueue->select(CurrentUser()->getCurPlayingTrackPos());
}
+ _mediaPlayer = new AudioPlayer();
+ mainLayout->addWidget(_mediaPlayer, 2, 0, 1, 4);
+
mainLayout->setRowStretch(1, 1);
mainLayout->setRowResizable(0, true, Wt::WLength(250, Wt::WLength::Pixel));
- mainLayout->setColumnResizable(0, true);
+ mainLayout->setColumnResizable(0, true, Wt::WLength(400, Wt::WLength::Pixel));
// Double click on track
// Set the selected tracks to the play queue
@@ -510,7 +509,7 @@ Audio::playTrack(Track::id_type trackId, int pos)
CurrentUser().modify()->setCurPlayingTrackPos(pos);
}
- if (!_mediaPlayer->load(trackId))
+ if (!_mediaPlayer->loadTrack(trackId))
_playQueue->playNext();
}
diff --git a/src/ui/audio/desktop/DesktopAudio.hpp b/src/ui/audio/desktop/DesktopAudio.hpp
index f5ee34ec..ac7bda65 100644
--- a/src/ui/audio/desktop/DesktopAudio.hpp
+++ b/src/ui/audio/desktop/DesktopAudio.hpp
@@ -17,14 +17,13 @@
* along with LMS. If not, see .
*/
-#ifndef UI_AUDIO_DESKTOP_HPP
-#define UI_AUDIO_DESKTOP_HPP
+#pragma once
#include
#include
-#include "AudioMediaPlayer.hpp"
+#include "audio/AudioPlayer.hpp"
#include "TrackView.hpp"
#include "PlayQueue.hpp"
@@ -66,7 +65,7 @@ class Audio : public UserInterface::Audio
void handlePlaylistSelected(Wt::WString name);
- AudioMediaPlayer* _mediaPlayer;
+ AudioPlayer* _mediaPlayer;
TrackView* _trackView;
PlayQueue* _playQueue;
@@ -80,5 +79,3 @@ class Audio : public UserInterface::Audio
} // namespace Desktop
} // namespace UserInterface
-#endif
-