[UI/MOBILE] Changed the audio player. Still WIP
This commit is contained in:
+4
-25
@@ -419,31 +419,6 @@
|
||||
</nav>
|
||||
</message>
|
||||
|
||||
<message id="mobile-audio-player">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="row">
|
||||
<div class="mobile-audio-footer">
|
||||
<div class="vertical-align mobile-audio-footer">
|
||||
<div class="col-xs-2">${cover}</div>
|
||||
<div class="col-xs-7">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">${track}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">${artist}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3">${play}${pause}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</message>
|
||||
|
||||
<message id="wa-release-wrapper">
|
||||
<div class="section text-center">
|
||||
<div class="container">
|
||||
@@ -541,4 +516,8 @@
|
||||
<div class="menu-item list-group-item ">${<if-has-disc-num>}${disc-num}-${</if-has-disc-num>}${<if-has-track-num>}${track-num}. ${</if-has-track-num>}${track-name} <span class="badge">${btn}</span><span class="badge">${time}</span></div>
|
||||
</message>
|
||||
|
||||
<message id="wa-audio-player">
|
||||
${shuffle} ${repeat} ${playlist} ${prev} ${play-pause} ${next} ${cover} ${artist} ${track} ${release} ${curtime} ${seekbar} ${duration} ${volume}
|
||||
</message>
|
||||
|
||||
</messages>
|
||||
|
||||
Executable → Regular
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
+2
-1
@@ -24,6 +24,7 @@ lms_SOURCES = \
|
||||
$(srcdir)/service/DatabaseUpdateService.cpp \
|
||||
$(srcdir)/ui/LmsApplication.cpp \
|
||||
$(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 \
|
||||
@@ -33,11 +34,11 @@ lms_SOURCES = \
|
||||
$(srcdir)/ui/audio/desktop/TrackView.cpp \
|
||||
$(srcdir)/ui/audio/mobile/ArtistSearch.cpp \
|
||||
$(srcdir)/ui/audio/mobile/MobileAudio.cpp \
|
||||
$(srcdir)/ui/audio/mobile/MobileAudioMediaPlayer.cpp \
|
||||
$(srcdir)/ui/audio/mobile/ReleaseSearch.cpp \
|
||||
$(srcdir)/ui/audio/mobile/TrackReleaseView.cpp \
|
||||
$(srcdir)/ui/audio/mobile/TrackSearch.cpp \
|
||||
$(srcdir)/ui/common/DirectoryValidator.cpp \
|
||||
$(srcdir)/ui/common/InputRange.cpp \
|
||||
$(srcdir)/ui/common/LineEdit.cpp \
|
||||
$(srcdir)/ui/resource/AvConvTranscodeStreamResource.cpp \
|
||||
$(srcdir)/ui/resource/CoverResource.cpp \
|
||||
|
||||
@@ -264,25 +264,6 @@ Transcoder::start()
|
||||
args.push_back("m4v");
|
||||
break;
|
||||
|
||||
case Encoding::FLV:
|
||||
args.push_back("-acodec");
|
||||
args.push_back("libmp3lame");
|
||||
args.push_back("-ac");
|
||||
args.push_back("2");
|
||||
args.push_back("-ar");
|
||||
args.push_back("44100");
|
||||
args.push_back("-vcodec");
|
||||
args.push_back("libx264");
|
||||
args.push_back("-f");
|
||||
args.push_back("flv");
|
||||
break;
|
||||
|
||||
case Encoding::FLA:
|
||||
args.push_back("-acodec");
|
||||
args.push_back("libmp3lame");
|
||||
args.push_back("-f");
|
||||
args.push_back("flv");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -40,8 +40,6 @@ enum class Encoding
|
||||
MP3,
|
||||
WEBMA,
|
||||
WEBMV,
|
||||
FLA,
|
||||
FLV,
|
||||
M4A,
|
||||
M4V,
|
||||
};
|
||||
|
||||
@@ -55,7 +55,6 @@ User::audioEncodings =
|
||||
AudioEncoding::MP3,
|
||||
AudioEncoding::OGA,
|
||||
AudioEncoding::WEBMA,
|
||||
AudioEncoding::FLA,
|
||||
};
|
||||
|
||||
const std::vector<VideoEncoding>
|
||||
|
||||
@@ -39,7 +39,6 @@ enum class AudioEncoding
|
||||
MP3,
|
||||
OGA,
|
||||
WEBMA,
|
||||
FLA,
|
||||
};
|
||||
|
||||
enum class VideoEncoding
|
||||
|
||||
@@ -100,6 +100,7 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
|
||||
setTheme(bootstrapTheme);
|
||||
|
||||
useStyleSheet("css/lms.css");
|
||||
useStyleSheet("resources/font-awesome/css/font-awesome.min.css");
|
||||
|
||||
// Add a resource bundle
|
||||
messageResourceBundle().use(appRoot() + "templates");
|
||||
@@ -142,6 +143,16 @@ Database::User::pointer CurrentUser()
|
||||
return DbHandler().getCurrentUser();
|
||||
}
|
||||
|
||||
CoverResource* SessionCoverResource()
|
||||
{
|
||||
return LmsApplication::instance()->getCoverResource();
|
||||
}
|
||||
|
||||
TranscodeResource* SessionTranscodeResource()
|
||||
{
|
||||
return LmsApplication::instance()->getTranscodeResource();
|
||||
}
|
||||
|
||||
void
|
||||
LmsApplication::createFirstConnectionUI()
|
||||
{
|
||||
@@ -155,6 +166,8 @@ void
|
||||
LmsApplication::createLmsUI()
|
||||
{
|
||||
_coverResource = new CoverResource(_db, root());
|
||||
_transcodeResource = new TranscodeResource(_db, root());
|
||||
|
||||
DbHandler().getLogin().changed().connect(this, &LmsApplication::handleAuthEvent);
|
||||
|
||||
LmsAuth *authWidget = new LmsAuth();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "database/DatabaseHandler.hpp"
|
||||
#include "resource/CoverResource.hpp"
|
||||
#include "resource/TranscodeResource.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
@@ -40,6 +41,7 @@ class LmsApplication : public Wt::WApplication
|
||||
|
||||
// Session application data
|
||||
CoverResource* getCoverResource() { return _coverResource; }
|
||||
TranscodeResource* getTranscodeResource() { return _transcodeResource; }
|
||||
Database::Handler& getDbHandler() { return _db;}
|
||||
|
||||
private:
|
||||
@@ -50,6 +52,7 @@ class LmsApplication : public Wt::WApplication
|
||||
|
||||
Database::Handler _db;
|
||||
CoverResource* _coverResource;
|
||||
TranscodeResource* _transcodeResource;
|
||||
};
|
||||
|
||||
// Helpers to get session data
|
||||
@@ -59,6 +62,9 @@ Wt::Dbo::Session& DboSession();
|
||||
const Wt::Auth::User& CurrentAuthUser();
|
||||
Database::User::pointer CurrentUser();
|
||||
|
||||
CoverResource *SessionCoverResource();
|
||||
TranscodeResource *SessionTranscodeResource();
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <Wt/WText>
|
||||
#include <Wt/WAudio>
|
||||
#include <Wt/WImage>
|
||||
#include <Wt/WTemplate>
|
||||
#include <Wt/WPushButton>
|
||||
|
||||
#include "common/InputRange.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
#include "AudioPlayer.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
void
|
||||
AudioPlayer::loadTrack(Database::Track::id_type trackId)
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(DboSession());
|
||||
|
||||
Database::Track::pointer track = Database::Track::getById(DboSession(), trackId);
|
||||
if (!track)
|
||||
{
|
||||
std::cerr << "no track for this id!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
_trackName->setText(Wt::WString::fromUTF8(track->getName()));
|
||||
_artistName->setText( Wt::WString::fromUTF8(track->getArtist()->getName()));
|
||||
_releaseName->setText( Wt::WString::fromUTF8(track->getRelease()->getName()));
|
||||
_cover->setImageLink(SessionCoverResource()->getTrackUrl(trackId, 64));
|
||||
_trackDuration->setText( boost::posix_time::to_simple_string( track->getDuration() ));
|
||||
|
||||
// Analyse track, select the best media stream
|
||||
Av::MediaFile mediaFile(track->getPath());
|
||||
|
||||
if (!mediaFile.open() || !mediaFile.scan())
|
||||
{
|
||||
std::cerr << "cannot open file '" << track->getPath() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int audioBestStreamId = mediaFile.getBestStreamId(Av::Stream::Type::Audio);
|
||||
std::vector<std::size_t> streams;
|
||||
if (audioBestStreamId != -1)
|
||||
streams.push_back(audioBestStreamId);
|
||||
|
||||
this->doJavaScript("\
|
||||
document.lms.audio.state = \"loaded\";\
|
||||
document.lms.audio.seekbar.min = " + std::to_string(0) + ";\
|
||||
document.lms.audio.seekbar.max = " + std::to_string(track->getDuration().total_seconds()) + ";\
|
||||
document.lms.audio.seekbar.value = 0;\
|
||||
document.lms.audio.seekbar.disabled = false;\
|
||||
document.lms.audio.offset = 0;\
|
||||
document.lms.audio.curTime = 0;\
|
||||
");
|
||||
|
||||
//TODO, try to load everything in JS in order to prevent the WriteError bug?
|
||||
_audio->pause();
|
||||
_audio->clearSources();
|
||||
//TODOencoding
|
||||
_audio->addSource(SessionTranscodeResource()->getUrl(trackId, Av::Encoding::MP3, 0, streams));
|
||||
_audio->play();
|
||||
}
|
||||
|
||||
AudioPlayer::AudioPlayer(Wt::WContainerWidget *parent)
|
||||
: Wt::WContainerWidget(parent)
|
||||
{
|
||||
Wt::WTemplate *t = new Wt::WTemplate(this);
|
||||
t->setTemplateText(Wt::WString::tr("wa-audio-player"));
|
||||
|
||||
_audio = new Wt::WAudio(this);
|
||||
|
||||
_cover = new Wt::WImage();
|
||||
t->bindWidget("cover", _cover);
|
||||
_cover->setImageLink(SessionCoverResource()->getUnknownTrackUrl(64));
|
||||
|
||||
InputRange *seekbar = new InputRange();
|
||||
t->bindWidget("seekbar", seekbar);
|
||||
|
||||
_trackName = new Wt::WText();
|
||||
t->bindWidget("track", _trackName);
|
||||
|
||||
_artistName = new Wt::WText();
|
||||
t->bindWidget("artist", _artistName);
|
||||
|
||||
_releaseName = new Wt::WText();
|
||||
t->bindWidget("release", _releaseName);
|
||||
|
||||
InputRange *volumeSlider = new InputRange();
|
||||
t->bindWidget("volume", volumeSlider);
|
||||
|
||||
Wt::WPushButton *playlistBtn = new Wt::WPushButton("<i class=\"fa fa-list fa-lg\"></i>", Wt::XHTMLText);
|
||||
t->bindWidget("playlist", playlistBtn);
|
||||
|
||||
Wt::WPushButton *repeatBtn = new Wt::WPushButton("<i class=\"fa fa-repeat fa-lg\"></i>", Wt::XHTMLText);
|
||||
t->bindWidget("repeat", repeatBtn);
|
||||
|
||||
Wt::WPushButton *shuffleBtn = new Wt::WPushButton("<i class=\"fa fa-random fa-lg\"></i>", Wt::XHTMLText);
|
||||
t->bindWidget("shuffle", shuffleBtn);
|
||||
|
||||
Wt::WPushButton *prevBtn = new Wt::WPushButton("<i class=\"fa fa-step-backward fa-lg\"></i>", Wt::XHTMLText);
|
||||
t->bindWidget("prev", prevBtn);
|
||||
|
||||
Wt::WPushButton *nextBtn = new Wt::WPushButton("<i class=\"fa fa-step-forward fa-lg\"></i>", Wt::XHTMLText);
|
||||
t->bindWidget("next", nextBtn);
|
||||
|
||||
Wt::WPushButton *playPauseBtn = new Wt::WPushButton("<i class=\"fa fa-play fa-lg\"></i>", Wt::XHTMLText);
|
||||
t->bindWidget("play-pause", playPauseBtn);
|
||||
|
||||
Wt::WText *trackCurrentTime = new Wt::WText("00:00");
|
||||
t->bindWidget("curtime", trackCurrentTime);
|
||||
|
||||
_trackDuration = new Wt::WText("00:00");
|
||||
t->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;\
|
||||
}\
|
||||
\
|
||||
var mouseDown = 0;\
|
||||
function seekMouseDown(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;\
|
||||
}\
|
||||
\
|
||||
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 + \" \";\
|
||||
}\
|
||||
\
|
||||
function volumeChanged() {\
|
||||
document.lms.audio.audio.volume = document.lms.audio.volumeSlider.value / 100;\
|
||||
}\
|
||||
\
|
||||
function updateCurTime() {\
|
||||
document.lms.audio.curTime = document.lms.audio.offset + ~~document.lms.audio.audio.currentTime; \
|
||||
if (mouseDown == 0)\
|
||||
updateUI();\
|
||||
} \
|
||||
\
|
||||
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();\
|
||||
\
|
||||
}\
|
||||
\
|
||||
document.lms.audio.audio.addEventListener('timeupdate', updateCurTime); \
|
||||
document.lms.audio.seekbar.addEventListener('change', seek);\
|
||||
document.lms.audio.seekbar.addEventListener('input', seeking);\
|
||||
document.lms.audio.seekbar.addEventListener('mousedown', seekMouseDown);\
|
||||
document.lms.audio.seekbar.addEventListener('mouseup', seekMouseUp);\
|
||||
document.lms.audio.volumeSlider.addEventListener('input', volumeChanged);\
|
||||
document.lms.audio.playPause.addEventListener('click', playPause);\
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
} // namespaceUserInterface
|
||||
@@ -17,43 +17,31 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_AUDIO_MOBILE_MEDIA_PLAYER_HPP
|
||||
#define UI_AUDIO_MOBILE_MEDIA_PLAYER_HPP
|
||||
#pragma once
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WMediaPlayer>
|
||||
#include <Wt/WImage>
|
||||
|
||||
#include "database/DatabaseHandler.hpp"
|
||||
#include "av/AvTranscoder.hpp"
|
||||
#include "common/InputRange.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Mobile {
|
||||
|
||||
class AudioMediaPlayer : public Wt::WContainerWidget
|
||||
class AudioPlayer : public Wt::WContainerWidget
|
||||
{
|
||||
public:
|
||||
|
||||
static Wt::WMediaPlayer::Encoding getBestEncoding();
|
||||
AudioPlayer(Wt::WContainerWidget *parent = 0);
|
||||
|
||||
AudioMediaPlayer(Wt::WMediaPlayer::Encoding encoding, Wt::WContainerWidget *parent = 0);
|
||||
void loadTrack(Database::Track::id_type trackId);
|
||||
|
||||
void play(Database::Track::id_type trackId, Av::TranscodeParameters parameters);
|
||||
|
||||
Wt::WMediaPlayer::Encoding getEncoding() const { return _encoding; }
|
||||
// Slots
|
||||
|
||||
private:
|
||||
|
||||
Wt::WMediaPlayer* _player;
|
||||
Wt::WMediaPlayer::Encoding _encoding;
|
||||
|
||||
Wt::WImage* _cover;
|
||||
Wt::WText* _track;
|
||||
Wt::WText* _artistRelease;
|
||||
|
||||
Wt::WAudio* _audio;
|
||||
Wt::WText* _trackDuration;
|
||||
Wt::WText* _trackName;
|
||||
Wt::WText* _artistName;
|
||||
Wt::WText* _releaseName;
|
||||
Wt::WImage* _cover;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
} // namespace Mobile
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <Wt/WMediaPlayer>
|
||||
#include <Wt/WProgressBar>
|
||||
#include <Wt/WCheckBox>
|
||||
#include <Wt/WTemplate>
|
||||
#include <Wt/WHBoxLayout>
|
||||
#include <Wt/WVBoxLayout>
|
||||
|
||||
@@ -57,7 +56,6 @@ AudioMediaPlayer::AudioMediaPlayer(Wt::WContainerWidget *parent)
|
||||
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::FLA: _encoding = Wt::WMediaPlayer::FLA; break;
|
||||
case Database::AudioEncoding::AUTO:
|
||||
default:
|
||||
_encoding = getBestEncoding();
|
||||
@@ -237,7 +235,6 @@ AudioMediaPlayer::load(Database::Track::id_type trackId)
|
||||
switch (_encoding)
|
||||
{
|
||||
case Wt::WMediaPlayer::MP3: encoding = Av::Encoding::MP3; break;
|
||||
case Wt::WMediaPlayer::FLA: encoding = Av::Encoding::FLA; break;
|
||||
case Wt::WMediaPlayer::OGA: encoding = Av::Encoding::OGA; break;
|
||||
case Wt::WMediaPlayer::WEBMA: encoding = Av::Encoding::WEBMA; break;
|
||||
default:
|
||||
|
||||
@@ -27,14 +27,13 @@
|
||||
#include "logger/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "audio/AudioPlayer.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
#include "ArtistSearch.hpp"
|
||||
#include "ReleaseSearch.hpp"
|
||||
#include "TrackSearch.hpp"
|
||||
|
||||
#include "TrackReleaseView.hpp"
|
||||
#include "MobileAudioMediaPlayer.hpp"
|
||||
|
||||
#include "MobileAudio.hpp"
|
||||
|
||||
@@ -45,36 +44,16 @@ namespace Mobile {
|
||||
|
||||
using namespace Database;
|
||||
|
||||
static void playTrack(AudioMediaPlayer *mediaPlayer, Database::Track::id_type trackId)
|
||||
static void playTrack(AudioPlayer *audioPlayer, Database::Track::id_type trackId)
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "Playing track id " << trackId;
|
||||
// TODO reduce transaction scope here
|
||||
|
||||
Wt::Dbo::Transaction transaction(DboSession());
|
||||
|
||||
Track::pointer track = Track::getById(DboSession(), trackId);
|
||||
|
||||
if (track)
|
||||
{
|
||||
Av::TranscodeParameters parameters;
|
||||
|
||||
// Determine the output format using the encoding of the player
|
||||
Av::Encoding encoding;
|
||||
switch(mediaPlayer->getEncoding())
|
||||
{
|
||||
case Wt::WMediaPlayer::MP3: encoding = Av::Encoding::MP3; break;
|
||||
case Wt::WMediaPlayer::FLA: encoding = Av::Encoding::FLA; 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);
|
||||
|
||||
// TODO compute parameters using user's profile
|
||||
parameters.setBitrate(Av::Stream::Type::Audio, 96000);
|
||||
|
||||
mediaPlayer->play(track.id(), parameters);
|
||||
}
|
||||
audioPlayer->loadTrack(track.id());
|
||||
}
|
||||
|
||||
Audio::Audio(Wt::WContainerWidget *parent)
|
||||
@@ -103,26 +82,8 @@ Audio::Audio(Wt::WContainerWidget *parent)
|
||||
Wt::WTemplate* footer = new Wt::WTemplate(this);
|
||||
footer->setTemplateText(Wt::WString::tr("mobile-audio-footer"));
|
||||
|
||||
// Determine the encoding to be used
|
||||
Wt::WMediaPlayer::Encoding encoding;
|
||||
|
||||
{
|
||||
Wt::Dbo::Transaction transaction (DboSession());
|
||||
|
||||
switch (CurrentUser()->getAudioEncoding())
|
||||
{
|
||||
case AudioEncoding::MP3: encoding = Wt::WMediaPlayer::MP3; break;
|
||||
case AudioEncoding::WEBMA: encoding = Wt::WMediaPlayer::WEBMA; break;
|
||||
case AudioEncoding::OGA: encoding = Wt::WMediaPlayer::OGA; break;
|
||||
case AudioEncoding::FLA: encoding = Wt::WMediaPlayer::FLA; break;
|
||||
case AudioEncoding::AUTO:
|
||||
default:
|
||||
encoding = AudioMediaPlayer::getBestEncoding();
|
||||
}
|
||||
}
|
||||
|
||||
AudioMediaPlayer* mediaPlayer = new AudioMediaPlayer(encoding);
|
||||
footer->bindWidget("player", mediaPlayer);
|
||||
AudioPlayer* audioPlayer = new AudioPlayer();
|
||||
footer->bindWidget("player", audioPlayer);
|
||||
|
||||
edit->changed().connect(std::bind([=] ()
|
||||
{
|
||||
@@ -188,12 +149,12 @@ Audio::Audio(Wt::WContainerWidget *parent)
|
||||
|
||||
trackSearch->trackPlay().connect(std::bind([=] (Track::id_type id)
|
||||
{
|
||||
playTrack(mediaPlayer, id);
|
||||
playTrack(audioPlayer, id);
|
||||
}, std::placeholders::_1));
|
||||
|
||||
trackReleaseView->trackPlay().connect(std::bind([=] (Track::id_type id)
|
||||
{
|
||||
playTrack(mediaPlayer, id);
|
||||
playTrack(audioPlayer, id);
|
||||
}, std::placeholders::_1));
|
||||
|
||||
// Initially, populate the widgets using an empty search
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Wt/WApplication>
|
||||
#include <Wt/WEnvironment>
|
||||
#include <Wt/WTemplate>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/WSlider>
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
#include "MobileAudioMediaPlayer.hpp"
|
||||
|
||||
#include "resource/AvConvTranscodeStreamResource.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Mobile {
|
||||
|
||||
Wt::WMediaPlayer::Encoding
|
||||
AudioMediaPlayer::getBestEncoding()
|
||||
{
|
||||
// MP3 seems to be better supported everywhere
|
||||
return Wt::WMediaPlayer::MP3;
|
||||
}
|
||||
|
||||
AudioMediaPlayer::AudioMediaPlayer(Wt::WMediaPlayer::Encoding encoding, Wt::WContainerWidget *parent)
|
||||
:
|
||||
Wt::WContainerWidget(parent),
|
||||
_player(nullptr),
|
||||
_encoding(encoding)
|
||||
{
|
||||
Wt::WTemplate* container = new Wt::WTemplate(this);
|
||||
container->setTemplateText(Wt::WString::tr("mobile-audio-player"));
|
||||
|
||||
Wt::WPushButton *play = new Wt::WPushButton("Play");
|
||||
play->setStyleClass("btn-sm");
|
||||
play->setWidth(52);
|
||||
container->bindWidget("play", play);
|
||||
|
||||
Wt::WPushButton *pause = new Wt::WPushButton("Pause");
|
||||
pause->setStyleClass("btn-sm");
|
||||
pause->setWidth(52);
|
||||
container->bindWidget("pause", pause);
|
||||
|
||||
_track = new Wt::WText("", Wt::PlainText);
|
||||
_track->setStyleClass("mobile-track");
|
||||
container->bindWidget("track", _track);
|
||||
|
||||
_artistRelease = new Wt::WText("", Wt::PlainText);
|
||||
_artistRelease->setStyleClass("mobile-artist");
|
||||
container->bindWidget("artist", _artistRelease);
|
||||
|
||||
_cover = new Wt::WImage();
|
||||
container->bindWidget("cover", _cover);
|
||||
_cover->setStyleClass("mobile-audio-player-cover");
|
||||
|
||||
|
||||
_player = new Wt::WMediaPlayer(Wt::WMediaPlayer::Audio, this);
|
||||
_player->addSource( _encoding, "" );
|
||||
_player->setControlsWidget( 0 );
|
||||
_player->setButton(Wt::WMediaPlayer::Play, play);
|
||||
_player->setButton(Wt::WMediaPlayer::Pause, pause);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AudioMediaPlayer::play(Database::Track::id_type trackId, Av::TranscodeParameters parameters)
|
||||
{
|
||||
boost::filesystem::path path;
|
||||
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(DboSession());
|
||||
|
||||
Database::Track::pointer track = Database::Track::getById(DboSession(), trackId);
|
||||
|
||||
_track->setText( Wt::WString::fromUTF8(track->getName() ));
|
||||
_artistRelease->setText( Wt::WString::fromUTF8(track->getArtist()->getName()) );
|
||||
path = track->getPath();
|
||||
}
|
||||
|
||||
// FIXME memleak here
|
||||
AvConvTranscodeStreamResource *resource = new AvConvTranscodeStreamResource( path, parameters, this );
|
||||
|
||||
_player->clearSources();
|
||||
_player->addSource( _encoding, Wt::WLink(resource));
|
||||
|
||||
_player->play();
|
||||
|
||||
_cover->setImageLink( Wt::WLink (LmsApplication::instance()->getCoverResource()->getTrackUrl(trackId, 48)));
|
||||
|
||||
}
|
||||
|
||||
} // namespace UserInterface
|
||||
} // namespace Mobile
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Wt/WConfig.h>
|
||||
|
||||
#if WT_VERSION < 0X03030500
|
||||
#include <Wt/WTemplate>
|
||||
#endif
|
||||
|
||||
#include "InputRange.hpp"
|
||||
|
||||
InputRange::InputRange(Wt::WContainerWidget *parent)
|
||||
: Wt::WWebWidget(parent)
|
||||
{
|
||||
//TODO woraround for older Wt versions
|
||||
#if WT_VERSION >= 0X03030500
|
||||
setHtmlTagName("input");
|
||||
setAttributeValue("type", "range");
|
||||
#else
|
||||
Wt::WTemplate *t = new Wt::WTemplate("<input type=\"range\"></input>", parent);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
InputRange::jsRef(void) const
|
||||
{
|
||||
#if WT_VERSION >= 0X03030500
|
||||
return Wt::WWebWidget::jsRef();
|
||||
#else
|
||||
return this->jsRef() + ".getElementsByTagName(\"input\")[0]";
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WWebWidget>
|
||||
|
||||
class InputRange : public Wt::WWebWidget
|
||||
{
|
||||
public:
|
||||
InputRange(Wt::WContainerWidget *parent = 0);
|
||||
|
||||
Wt::DomElementType domElementType() const
|
||||
{
|
||||
return Wt::DomElement_INPUT;
|
||||
}
|
||||
|
||||
std::string jsRef() const;
|
||||
};
|
||||
|
||||
@@ -71,11 +71,11 @@ TranscodeResource::handleRequest(const Wt::Http::Request& request,
|
||||
Wt::Http::ResponseContinuation *continuation = request.continuation();
|
||||
if (continuation)
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "Continuation!";
|
||||
LMS_LOG(UI, DEBUG) << "Continuation! " << continuation ;
|
||||
transcoder = boost::any_cast<std::shared_ptr<Av::Transcoder> >(continuation->data());
|
||||
if (!transcoder)
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "No transcoder set -> abort!";
|
||||
LMS_LOG(UI, ERROR) << "No transcoder set -> abort!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -101,18 +101,23 @@ TranscodeResource::handleRequest(const Wt::Http::Request& request,
|
||||
Database::User::pointer user = _db.getCurrentUser();
|
||||
Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId);
|
||||
|
||||
if (!track/* || !user */)
|
||||
if (!track)
|
||||
{
|
||||
LMS_LOG(UI, ERROR) << "Missing track or user";
|
||||
LMS_LOG(UI, ERROR) << "Missing track";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user)
|
||||
{
|
||||
LMS_LOG(UI, ERROR) << "Missing user";
|
||||
return;
|
||||
}
|
||||
|
||||
Av::TranscodeParameters parameters;
|
||||
|
||||
// TODO
|
||||
parameters.setOffset(boost::posix_time::seconds(std::stol(*offsetStr)));
|
||||
parameters.setEncoding(Av::encoding_from_int(std::stol(*encodingStr)));
|
||||
parameters.setBitrate(Av::Stream::Type::Audio, 96000);
|
||||
parameters.setBitrate(Av::Stream::Type::Audio, user->getAudioBitrate() );
|
||||
for (std::string strStream: streams)
|
||||
{
|
||||
LMS_LOG(UI, DEBUG) << "Added stream " << std::stol(strStream);
|
||||
@@ -135,18 +140,14 @@ TranscodeResource::handleRequest(const Wt::Http::Request& request,
|
||||
LMS_LOG(UI, DEBUG) << "Transcoder started";
|
||||
}
|
||||
|
||||
LMS_LOG(UI, DEBUG) << "processing data?";
|
||||
|
||||
if (!transcoder->isComplete())
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
data.reserve(_bufferSize);
|
||||
|
||||
LMS_LOG(UI, DEBUG) << "Processing data from transcoder...";
|
||||
LMS_LOG(UI, DEBUG) << "Reading data from transcoder";
|
||||
transcoder->process(data, _bufferSize);
|
||||
LMS_LOG(UI, DEBUG) << "Processing data from transcoder DONE";
|
||||
|
||||
// Give the client all the output data
|
||||
response.out().write(reinterpret_cast<char*>(&data[0]), data.size());
|
||||
|
||||
LMS_LOG(UI, DEBUG) << "Written " << data.size() << " bytes! complete = " << std::boolalpha << transcoder->isComplete();
|
||||
|
||||
@@ -41,7 +41,6 @@ std::string encodingToString(Database::AudioEncoding encoding)
|
||||
case Database::AudioEncoding::MP3: return "MP3";
|
||||
case Database::AudioEncoding::OGA: return "OGG";
|
||||
case Database::AudioEncoding::WEBMA: return "WebM";
|
||||
case Database::AudioEncoding::FLA: return "Flash";
|
||||
}
|
||||
|
||||
return "?";
|
||||
|
||||
Reference in New Issue
Block a user