Experimental VLC audio engine

This commit is contained in:
David Sansome 2010-04-04 20:45:03 +00:00
parent d5eb2297d2
commit 993a4f0e43
6 changed files with 281 additions and 8 deletions

View File

@ -36,7 +36,7 @@ if(WIN32)
find_library(TAGLIB_LIBRARIES tag)
else(WIN32)
pkg_check_modules(TAGLIB taglib)
pkg_check_modules(XINE libxine)
pkg_check_modules(LIBVLC libvlc)
if (TAGLIB_VERSION VERSION_LESS 1.6)
message(FATAL_ERROR "Taglib version 1.6 or greater is required")
@ -62,13 +62,13 @@ endif(${CMAKE_BUILD_TYPE} MATCHES "Release")
# Set up definitions and paths
add_definitions(${QT_DEFINITIONS})
link_directories(${TAGLIB_LIBRARY_DIRS})
link_directories(${XINE_LIBRARY_DIRS})
link_directories(${LIBVLC_LIBRARY_DIRS})
link_directories(${LASTFM_LIBRARY_DIRS})
include(${QT_USE_FILE})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${TAGLIB_INCLUDE_DIRS})
include_directories(${XINE_INCLUDE_DIRS})
include_directories(${LIBVLC_INCLUDE_DIRS})
include_directories(${LASTFM_INCLUDE_DIRS})
include_directories("3rdparty/qsqlite")

View File

@ -198,8 +198,8 @@ if(USE_PHONON)
set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} engines/phononengine.cpp)
set(CLEMENTINE-MOC-HEADERS ${CLEMENTINE-MOC-HEADERS} engines/phononengine.h)
else(USE_PHONON)
set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} engines/xine-engine.cpp engines/xine-scope.c)
set(CLEMENTINE-MOC-HEADERS ${CLEMENTINE-MOC-HEADERS} engines/xine-engine.h)
set(CLEMENTINE-SOURCES ${CLEMENTINE-SOURCES} engines/vlcengine.cpp)
set(CLEMENTINE-MOC-HEADERS ${CLEMENTINE-MOC-HEADERS} engines/vlcengine.h)
endif(USE_PHONON)
# OSD and DBus.
@ -264,7 +264,7 @@ target_link_libraries(clementine_lib
qtsingleapplication
qxt
lastfm
${XINE_LIBRARIES}
${LIBVLC_LIBRARIES}
${TAGLIB_LIBRARIES}
${QT_LIBRARIES}
)

206
src/engines/vlcengine.cpp Normal file
View File

@ -0,0 +1,206 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vlcengine.h"
#include "vlcscopedref.h"
#include <QTimer>
#include <QtDebug>
#include <boost/bind.hpp>
VlcEngine::VlcEngine()
: instance_(NULL),
player_(NULL),
state_(Engine::Empty)
{
static const char * const args[] = {
"-I", "dummy", // Don't use any interface
"--ignore-config", // Don't use VLC's config
"--extraintf=logger", // log anything
"--verbose=2", // be much more verbose then normal for debugging purpose
//"--plugin-path=C:\\vlc-0.9.9-win32\\plugins\\"
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
"--aout=alsa", // The default, pulseaudio, is buggy
#endif
};
// Create the VLC instance
libvlc_exception_init(&exception_);
instance_ = libvlc_new(sizeof(args) / sizeof(args[0]), args, &exception_);
HandleErrors();
// Create the media player
player_ = libvlc_media_player_new(instance_, &exception_);
HandleErrors();
// Add event handlers
libvlc_event_manager_t* player_em =
libvlc_media_player_event_manager(player_, &exception_);
HandleErrors();
AttachCallback(player_em, libvlc_MediaPlayerEncounteredError, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerNothingSpecial, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerOpening, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerBuffering, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerPlaying, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerPaused, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerStopped, StateChangedCallback);
AttachCallback(player_em, libvlc_MediaPlayerEndReached, StateChangedCallback);
HandleErrors();
}
VlcEngine::~VlcEngine() {
libvlc_media_player_stop(player_, &exception_);
libvlc_media_player_release(player_);
libvlc_release(instance_);
HandleErrors();
}
void VlcEngine::AttachCallback(libvlc_event_manager_t* em, libvlc_event_type_t type,
libvlc_callback_t callback) {
libvlc_event_attach(em, type, callback, this, &exception_);
HandleErrors();
}
void VlcEngine::StateChangedCallback(const libvlc_event_t* e, void* data) {
VlcEngine* engine = reinterpret_cast<VlcEngine*>(data);
switch (e->type) {
case libvlc_MediaPlayerNothingSpecial:
case libvlc_MediaPlayerStopped:
case libvlc_MediaPlayerEncounteredError:
engine->state_ = Engine::Empty;
break;
case libvlc_MediaPlayerOpening:
case libvlc_MediaPlayerBuffering:
case libvlc_MediaPlayerPlaying:
engine->state_ = Engine::Playing;
break;
case libvlc_MediaPlayerPaused:
engine->state_ = Engine::Paused;
break;
case libvlc_MediaPlayerEndReached:
engine->state_ = Engine::Idle;
break;
}
emit engine->stateChanged(engine->state_);
}
bool VlcEngine::init() {
return true;
}
bool VlcEngine::canDecode(const QUrl &url) const {
// TODO
return true;
}
bool VlcEngine::load(const QUrl &url, bool stream) {
VlcScopedRef<libvlc_media_t> media(
libvlc_media_new(instance_, url.toEncoded().constData(), &exception_));
if (libvlc_exception_raised(&exception_))
return false;
libvlc_media_player_set_media(player_, media, &exception_);
if (libvlc_exception_raised(&exception_))
return false;
return true;
}
bool VlcEngine::play(uint offset) {
libvlc_media_player_play(player_, &exception_);
if (libvlc_exception_raised(&exception_))
return false;
seek(offset);
return true;
}
void VlcEngine::stop() {
libvlc_media_player_stop(player_, &exception_);
HandleErrors();
}
void VlcEngine::pause() {
libvlc_media_player_pause(player_, &exception_);
HandleErrors();
}
void VlcEngine::unpause() {
libvlc_media_player_play(player_, &exception_);
HandleErrors();
}
uint VlcEngine::position() const {
bool is_playing = libvlc_media_player_is_playing(
player_, const_cast<libvlc_exception_t*>(&exception_));
HandleErrors();
if (!is_playing)
return 0;
float pos = libvlc_media_player_get_position(
player_, const_cast<libvlc_exception_t*>(&exception_));
HandleErrors();
return pos * length();
}
uint VlcEngine::length() const {
bool is_playing = libvlc_media_player_is_playing(
player_, const_cast<libvlc_exception_t*>(&exception_));
HandleErrors();
if (!is_playing)
return 0;
libvlc_time_t len = libvlc_media_player_get_length(
player_, const_cast<libvlc_exception_t*>(&exception_));
HandleErrors();
return len;
}
void VlcEngine::seek(uint ms) {
uint len = length();
if (len == 0)
return;
float pos = float(ms) / len;
libvlc_media_player_set_position(player_, pos, &exception_);
HandleErrors();
}
void VlcEngine::setVolumeSW(uint volume) {
libvlc_audio_set_volume(instance_, volume, &exception_);
HandleErrors();
}
void VlcEngine::HandleErrors() const {
if (libvlc_exception_raised(&exception_)) {
qFatal("libvlc error: %s", libvlc_exception_get_message(&exception_));
}
}

66
src/engines/vlcengine.h Normal file
View File

@ -0,0 +1,66 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VLCENGINE_H
#define VLCENGINE_H
#include "enginebase.h"
#include <vlc/vlc.h>
class QTimer;
class VlcEngine : public Engine::Base {
Q_OBJECT
public:
VlcEngine();
~VlcEngine();
bool init();
bool canDecode( const QUrl &url ) const;
bool load( const QUrl &url, bool stream = false );
bool play( uint offset = 0 );
void stop();
void pause();
void unpause();
Engine::State state() const { return state_; }
uint position() const;
uint length() const;
void seek( uint ms );
protected:
void setVolumeSW( uint percent );
private:
void HandleErrors() const;
void AttachCallback(libvlc_event_manager_t* em, libvlc_event_type_t type,
libvlc_callback_t callback);
static void StateChangedCallback(const libvlc_event_t* e, void* data);
private:
libvlc_exception_t exception_;
libvlc_instance_t* instance_;
libvlc_media_player_t* player_;
Engine::State state_;
};
#endif // VLCENGINE_H

View File

@ -74,6 +74,7 @@ int main(int argc, char *argv[]) {
qRegisterMetaType<Subdirectory>("Subdirectory");
qRegisterMetaType<SubdirectoryList>("SubdirectoryList");
qRegisterMetaType<SongList>("SongList");
qRegisterMetaType<Engine::State>("Engine::State");
lastfm::ws::ApiKey = LastFMService::kApiKey;

View File

@ -27,7 +27,7 @@
#ifdef USE_PHONON
# include "engines/phononengine.h"
#else
# include "engines/xine-engine.h"
# include "engines/vlcengine.h"
#endif
#include <QtDebug>
@ -68,7 +68,7 @@ Player::Player(Playlist* playlist, LastFMService* lastfm, QObject* parent)
#ifdef USE_PHONON
engine_ = new PhononEngine;
#else
engine_ = new XineEngine;
engine_ = new VlcEngine;
#endif
settings_.beginGroup("Player");