resolved conflicts

This commit is contained in:
nebojsa 2008-01-21 18:14:22 +00:00
parent c9026785f9
commit d5f97fd48e
6 changed files with 154 additions and 544 deletions

View file

@ -157,7 +157,7 @@ xmlrpcxx_version=xmlrpc++-20040713
xmlrpcxx_tmpdir=$tools_tmpdir/xmlrpc++ xmlrpcxx_tmpdir=$tools_tmpdir/xmlrpc++
gstreamer_dir=$toolsdir/gstreamer gstreamer_dir=$toolsdir/gstreamer
gstreamer_version=gstreamer-0.8.12 gstreamer_version=gstreamer-0.10.15
gstreamer_tmpdir=$tools_tmpdir/gstreamer gstreamer_tmpdir=$tools_tmpdir/gstreamer
taglib_dir=$toolsdir/taglib taglib_dir=$toolsdir/taglib

View file

@ -108,7 +108,7 @@ LIBODBCXX_VERSION = libodbc++-0.2.3-20050404
XMLRPCXX_DIR = ${TOOLS_DIR}/xmlrpc++ XMLRPCXX_DIR = ${TOOLS_DIR}/xmlrpc++
XMLRPCXX_VERSION = xmlrpc++-20040713 XMLRPCXX_VERSION = xmlrpc++-20040713
GSTREAMER_DIR = ${TOOLS_DIR}/gstreamer GSTREAMER_DIR = ${TOOLS_DIR}/gstreamer
GSTREAMER_VERSION = gstreamer-0.8.12 GSTREAMER_VERSION = gstreamer-0.10.15
TAGLIB_DIR = ${TOOLS_DIR}/taglib TAGLIB_DIR = ${TOOLS_DIR}/taglib
TAGLIB_VERSION = taglib-1.4 TAGLIB_VERSION = taglib-1.4
LIBSERIAL_DIR = ${TOOLS_DIR}/libserial LIBSERIAL_DIR = ${TOOLS_DIR}/libserial
@ -120,7 +120,6 @@ CORE_DIR = ${MODULES_DIR}/core
AUTHENTICATION_DIR = ${MODULES_DIR}/authentication AUTHENTICATION_DIR = ${MODULES_DIR}/authentication
DB_DIR = ${MODULES_DIR}/db DB_DIR = ${MODULES_DIR}/db
STORAGE_CLIENT_DIR = ${MODULES_DIR}/storageClient STORAGE_CLIENT_DIR = ${MODULES_DIR}/storageClient
GSTREAMER_ELEMENTS_DIR = ${MODULES_DIR}/gstreamerElements
PLAYLIST_EXECUTOR_DIR = ${MODULES_DIR}/playlistExecutor PLAYLIST_EXECUTOR_DIR = ${MODULES_DIR}/playlistExecutor
EVENT_SCHEDULER_DIR = ${MODULES_DIR}/eventScheduler EVENT_SCHEDULER_DIR = ${MODULES_DIR}/eventScheduler
SCHEDULER_CLIENT_DIR = ${MODULES_DIR}/schedulerClient SCHEDULER_CLIENT_DIR = ${MODULES_DIR}/schedulerClient
@ -181,8 +180,6 @@ flawfinder:
${AUTHENTICATION_DIR}/include ${AUTHENTICATION_DIR}/src \ ${AUTHENTICATION_DIR}/include ${AUTHENTICATION_DIR}/src \
${DB_DIR}/include ${DB_DIR}/src \ ${DB_DIR}/include ${DB_DIR}/src \
${STORAGE_CLIENT_DIR}/include ${STORAGE_CLIENT_DIR}/src \ ${STORAGE_CLIENT_DIR}/include ${STORAGE_CLIENT_DIR}/src \
${GSTREAMER_ELEMENTS_DIR}/include \
${GSTREAMER_ELEMENTS_DIR}/src \
${PLAYLIST_EXECUTOR_DIR}/include \ ${PLAYLIST_EXECUTOR_DIR}/include \
${PLAYLIST_EXECUTOR_DIR}/src \ ${PLAYLIST_EXECUTOR_DIR}/src \
${EVENT_SCHEDULER_DIR}/include ${EVENT_SCHEDULER_DIR}/src \ ${EVENT_SCHEDULER_DIR}/include ${EVENT_SCHEDULER_DIR}/src \
@ -297,9 +294,6 @@ ${TMP_DIR}/modules_setup.stamp:
cd ${STORAGE_CLIENT_DIR} && \ cd ${STORAGE_CLIENT_DIR} && \
./configure --prefix=${prefix} --enable-debug=${DEBUG} \ ./configure --prefix=${prefix} --enable-debug=${DEBUG} \
PACKAGE_VERSION=${PACKAGE_VERSION} PACKAGE_VERSION=${PACKAGE_VERSION}
cd ${GSTREAMER_ELEMENTS_DIR} && \
./configure --prefix=${prefix} --enable-debug=${DEBUG} \
PACKAGE_VERSION=${PACKAGE_VERSION}
cd ${PLAYLIST_EXECUTOR_DIR} && \ cd ${PLAYLIST_EXECUTOR_DIR} && \
./configure --prefix=${prefix} --enable-debug=${DEBUG} \ ./configure --prefix=${prefix} --enable-debug=${DEBUG} \
PACKAGE_VERSION=${PACKAGE_VERSION} PACKAGE_VERSION=${PACKAGE_VERSION}
@ -352,7 +346,6 @@ modprod_distclean:
${MAKE} -C ${AUTHENTICATION_DIR} distclean ${MAKE} -C ${AUTHENTICATION_DIR} distclean
${MAKE} -C ${DB_DIR} distclean ${MAKE} -C ${DB_DIR} distclean
${MAKE} -C ${STORAGE_CLIENT_DIR} distclean ${MAKE} -C ${STORAGE_CLIENT_DIR} distclean
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} distclean
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} distclean ${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} distclean
${MAKE} -C ${EVENT_SCHEDULER_DIR} distclean ${MAKE} -C ${EVENT_SCHEDULER_DIR} distclean
${MAKE} -C ${SCHEDULER_CLIENT_DIR} distclean ${MAKE} -C ${SCHEDULER_CLIENT_DIR} distclean
@ -368,7 +361,6 @@ depclean:
${MAKE} -C ${AUTHENTICATION_DIR} depclean ${MAKE} -C ${AUTHENTICATION_DIR} depclean
${MAKE} -C ${DB_DIR} depclean ${MAKE} -C ${DB_DIR} depclean
${MAKE} -C ${STORAGE_CLIENT_DIR} depclean ${MAKE} -C ${STORAGE_CLIENT_DIR} depclean
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} depclean
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} depclean ${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} depclean
${MAKE} -C ${EVENT_SCHEDULER_DIR} depclean ${MAKE} -C ${EVENT_SCHEDULER_DIR} depclean
${MAKE} -C ${SCHEDULER_CLIENT_DIR} depclean ${MAKE} -C ${SCHEDULER_CLIENT_DIR} depclean
@ -384,7 +376,6 @@ ${TMP_DIR}/compile.stamp:
${MAKE} -C ${AUTHENTICATION_DIR} all ${MAKE} -C ${AUTHENTICATION_DIR} all
${MAKE} -C ${DB_DIR} all ${MAKE} -C ${DB_DIR} all
${MAKE} -C ${STORAGE_CLIENT_DIR} all ${MAKE} -C ${STORAGE_CLIENT_DIR} all
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} all
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} all ${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} all
${MAKE} -C ${EVENT_SCHEDULER_DIR} all ${MAKE} -C ${EVENT_SCHEDULER_DIR} all
${MAKE} -C ${SCHEDULER_CLIENT_DIR} all ${MAKE} -C ${SCHEDULER_CLIENT_DIR} all
@ -398,7 +389,6 @@ check:
-${MAKE} -C ${AUTHENTICATION_DIR} check -${MAKE} -C ${AUTHENTICATION_DIR} check
-${MAKE} -C ${DB_DIR} check -${MAKE} -C ${DB_DIR} check
-${MAKE} -C ${STORAGE_CLIENT_DIR} check -${MAKE} -C ${STORAGE_CLIENT_DIR} check
-${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} check
# -${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} check # hangs on edge.campware.org # -${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} check # hangs on edge.campware.org
-${MAKE} -C ${EVENT_SCHEDULER_DIR} check -${MAKE} -C ${EVENT_SCHEDULER_DIR} check
-${MAKE} -C ${SCHEDULER_CLIENT_DIR} check -${MAKE} -C ${SCHEDULER_CLIENT_DIR} check
@ -462,7 +452,6 @@ install_modules:
${MAKE} -C ${AUTHENTICATION_DIR} install ${MAKE} -C ${AUTHENTICATION_DIR} install
${MAKE} -C ${DB_DIR} install ${MAKE} -C ${DB_DIR} install
${MAKE} -C ${STORAGE_CLIENT_DIR} install ${MAKE} -C ${STORAGE_CLIENT_DIR} install
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} install
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} install ${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} install
${MAKE} -C ${EVENT_SCHEDULER_DIR} install ${MAKE} -C ${EVENT_SCHEDULER_DIR} install
${MAKE} -C ${SCHEDULER_CLIENT_DIR} install ${MAKE} -C ${SCHEDULER_CLIENT_DIR} install

View file

@ -339,10 +339,6 @@ dnl set up the storage client module
AC_CONFIG_COMMANDS([../src/modules/storageClient/tmp/configure], AC_CONFIG_COMMANDS([../src/modules/storageClient/tmp/configure],
[../src/modules/storageClient/bin/autogen.sh]) [../src/modules/storageClient/bin/autogen.sh])
dnl set up the gstreamer elements module
AC_CONFIG_COMMANDS([../src/modules/gstreamerElements/tmp/configure],
[../src/modules/gstreamerElements/bin/autogen.sh])
dnl set up the playlist executor module dnl set up the playlist executor module
AC_CONFIG_COMMANDS([../src/modules/playlistExecutor/tmp/configure], AC_CONFIG_COMMANDS([../src/modules/playlistExecutor/tmp/configure],
[../src/modules/playlistExecutor/bin/autogen.sh]) [../src/modules/playlistExecutor/bin/autogen.sh])
@ -376,7 +372,7 @@ AC_MSG_NOTICE(
by Campcaster: by Campcaster:
cppunit 1.10.2 ${COMPILE_CPPUNIT} cppunit 1.10.2 ${COMPILE_CPPUNIT}
gstreamer 0.8.12 yes gstreamer 0.10.15 yes
libodbc++ 0.2.3 yes libodbc++ 0.2.3 yes
taglib 1.4 yes taglib 1.4 yes
xmlrpc++ 2004-07-13 yes xmlrpc++ 2004-07-13 yes

View file

@ -37,6 +37,7 @@
#include "LiveSupport/Core/Debug.h" #include "LiveSupport/Core/Debug.h"
#include "LiveSupport/Core/TimeConversion.h" #include "LiveSupport/Core/TimeConversion.h"
#include "GstreamerPlayer.h" #include "GstreamerPlayer.h"
@ -65,6 +66,42 @@ static const std::string audioDeviceName = "audioDevice";
/* ============================================================= module code */ /* ============================================================= module code */
static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data)
{
GstreamerPlayer* const player = (GstreamerPlayer*) data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
if(player->playNextSmil()){
break;
}
player->close();
// Important: We *must* use an idle function call here, so that the signal handler returns
// before fireOnStopEvent() is executed.
g_idle_add(GstreamerPlayer::fireOnStopEvent, data);
break;
case GST_MESSAGE_ERROR:
// We make sure that we don't send multiple error messages in a row to the GUI
if (!player->m_errorWasRaised) {
GError *gerror;
gchar *debug;
gst_message_parse_error (message, &gerror, &debug);
player->m_errorMessage.reset(new const Glib::ustring(gerror->message));
player->m_errorWasRaised = true;
std::cerr << "gstreamer error: " << gerror->message << std::endl;
g_error_free (gerror);
g_free (debug);
// Important: We *must* use an idle function call here, so that the signal handler returns
// before fireOnStopEvent() is executed.
g_idle_add(GstreamerPlayer::fireOnStopEvent, data);
}
break;
}
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Configure the Audio Player. * Configure the Audio Player.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@ -102,65 +139,19 @@ GstreamerPlayer :: initialize(void) throw (std::exception)
} }
// initialize the gstreamer library // initialize the gstreamer library
if (!gst_init_check(0, 0)) { if (!gst_init_check(0, 0, 0)) {
throw std::runtime_error("couldn't initialize the gstreamer library"); throw std::runtime_error("couldn't initialize the gstreamer library");
} }
// create the pipeline container (threaded) m_playContext = new GstreamerPlayContext();
m_pipeline = gst_thread_new("audio-player");
m_filesrc = 0; m_playContext->setParentData(this);
m_decoder = 0;
m_audioconvert = 0;
m_audioscale = 0;
g_signal_connect(m_pipeline, "error", G_CALLBACK(errorHandler), this);
// TODO: read the caps from the config file
m_sinkCaps = gst_caps_new_simple("audio/x-raw-int",
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16,
"endiannes", G_TYPE_INT, G_BYTE_ORDER,
"channels", G_TYPE_INT, 2,
"rate", G_TYPE_INT, 44100,
NULL);
setAudioDevice(m_audioDevice);
// set up other variables // set up other variables
m_initialized = true; m_initialized = true;
} }
/*------------------------------------------------------------------------------
* Handler for gstreamer errors.
*----------------------------------------------------------------------------*/
void
GstreamerPlayer :: errorHandler(GstElement * pipeline,
GstElement * source,
GError * error,
gchar * debug,
gpointer self)
throw ()
{
DEBUG_BLOCK
GstreamerPlayer* const player = (GstreamerPlayer*) self;
// We make sure that we don't send multiple error messages in a row to the GUI
if (!player->m_errorWasRaised) {
player->m_errorMessage.reset(new const Glib::ustring(error->message));
player->m_errorWasRaised = true;
std::cerr << "gstreamer error: " << error->message << std::endl;
// Important: We *must* use an idle function call here, so that the signal handler returns
// before fireOnStopEvent() is executed.
g_idle_add(fireOnStopEvent, self);
}
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* De-initialize the Gstreamer Player * De-initialize the Gstreamer Player
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@ -170,23 +161,13 @@ GstreamerPlayer :: deInitialize(void) throw ()
DEBUG_FUNC_INFO DEBUG_FUNC_INFO
if (m_initialized) { if (m_initialized) {
gst_element_set_state(m_pipeline, GST_STATE_NULL); m_playContext->closeContext();
gst_bin_sync_children_state(GST_BIN(m_pipeline)); delete m_playContext;
m_playContext = NULL;
if (!gst_element_get_parent(m_audiosink)) {
// delete manually, if audiosink wasn't added to the pipeline
// for some reason
gst_object_unref(GST_OBJECT(m_audiosink));
}
gst_object_unref(GST_OBJECT(m_pipeline));
gst_caps_free(m_sinkCaps);
m_audiosink = 0;
m_initialized = false; m_initialized = false;
} }
} }
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Attach an event listener. * Attach an event listener.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@ -224,15 +205,15 @@ GstreamerPlayer :: detachListener(AudioPlayerEventListener* eventListener)
* Send the onStop event to all attached listeners. * Send the onStop event to all attached listeners.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
gboolean gboolean
GstreamerPlayer :: fireOnStopEvent(gpointer self) throw () GstreamerPlayer :: fireOnStopEvent(gpointer self) throw ()
{ {
DEBUG_BLOCK DEBUG_BLOCK
GstreamerPlayer* const player = (GstreamerPlayer*) self; GstreamerPlayer* const player = (GstreamerPlayer*) self;
ListenerVector::iterator it = player->m_listeners.begin(); ListenerVector::iterator it = player->m_listeners.begin();
ListenerVector::iterator end = player->m_listeners.end(); ListenerVector::iterator end = player->m_listeners.end();
while (it != end) { while (it != end) {
(*it)->onStop(player->m_errorMessage); (*it)->onStop(player->m_errorMessage);
++it; ++it;
@ -245,51 +226,6 @@ GstreamerPlayer :: fireOnStopEvent(gpointer self) throw (
} }
/*------------------------------------------------------------------------------
* An EOS event handler, that will put the pipeline to EOS as well.
*----------------------------------------------------------------------------*/
void
GstreamerPlayer :: eosEventHandler(GstElement * element,
gpointer self)
throw ()
{
DEBUG_BLOCK
GstreamerPlayer* const player = (GstreamerPlayer*) self;
gst_element_set_eos(player->m_pipeline);
// Important: We *must* use an idle function call here, so that the signal handler returns
// before fireOnStopEvent() is executed.
g_idle_add(fireOnStopEvent, player);
}
/*------------------------------------------------------------------------------
* NewPad event handler. Links the decoder after decodebin's autoplugging.
*----------------------------------------------------------------------------*/
void
GstreamerPlayer::newpadEventHandler(GstElement*, GstPad* pad, gboolean, gpointer self) throw ()
{
DEBUG_BLOCK
GstreamerPlayer* const player = (GstreamerPlayer*) self;
GstPad* const audiopad = gst_element_get_pad(player->m_audioconvert, "sink");
if (GST_PAD_IS_LINKED(audiopad)) {
debug() << "audiopad is already linked. Unlinking old pad." << endl;
gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad));
}
gst_pad_link(pad, audiopad);
if (gst_element_get_parent(player->m_audiosink) == NULL)
gst_bin_add(GST_BIN(player->m_pipeline), player->m_audiosink);
gst_bin_sync_children_state(GST_BIN(player->m_pipeline));
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Preload a file, to speed up the subsequent open() call. * Preload a file, to speed up the subsequent open() call.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
@ -299,18 +235,10 @@ GstreamerPlayer :: preload(const std::string fileUrl)
std::runtime_error) std::runtime_error)
{ {
DEBUG_BLOCK DEBUG_BLOCK
//According to the Gstreamer documentation, stream buffering happens
if (m_preloadThread) { //automatically when the pipeline is set to GST_STATE_PAUSED.
m_preloadThread->stop(); //As this state is now set automatically in the open function,
m_preloadThread->join(); //we no longer have a need for preloading.
m_preloadThread.reset();
}
Ptr<Preloader>::Ref loader;
loader.reset(new Preloader(this, fileUrl));
m_preloadThread.reset(new Thread(loader));
m_preloadThread->start();
} }
@ -318,100 +246,61 @@ GstreamerPlayer :: preload(const std::string fileUrl)
* Specify which file to play * Specify which file to play
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void void
GstreamerPlayer :: open(const std::string fileUrl) GstreamerPlayer :: open(const std::string fileUri)
throw (std::invalid_argument, throw (std::invalid_argument,
std::runtime_error) std::runtime_error)
{ {
// GStreamer pipeline overview:
// filesrc -> decoder -> audioconvert -> audioscale -> audiosink
DEBUG_BLOCK DEBUG_BLOCK
if (isOpen()) { if (isOpen()) {
close(); close();
} }
debug() << "Opening URL: " << fileUrl << endl; m_smilOffset = 0L;
debug() << "Opening URL: " << fileUri << endl;
debug() << "Timestamp: " << *TimeConversion::now() << endl; debug() << "Timestamp: " << *TimeConversion::now() << endl;
m_errorMessage.reset(); m_errorMessage.reset();
m_errorWasRaised = false; m_errorWasRaised = false;
std::string filePath; m_playContext->setAudioDevice(m_audioDevice);
if (fileUri.find(std::string(".smil")) != std::string::npos) {
if (fileUrl.find("file://") == 0) { m_smilHandler = new SmilHandler();
filePath = fileUrl.substr(7, fileUrl.size()); m_smilHandler->openSmilFile(fileUri.c_str());
} AudioDescription *audioDescription = m_smilHandler->getNext();
else if (fileUrl.find("file:") == 0) { m_open=m_playContext->openSource(audioDescription);
filePath = fileUrl.substr(5, fileUrl.size()); }else{
} m_open=m_playContext->openSource(fileUri.c_str());
else {
throw std::invalid_argument("badly formed URL or unsupported protocol");
} }
if (m_preloadThread) { if(!m_open){
debug() << "Waiting for Preloader thread to finish..." << endl; m_errorMessage.reset(new const Glib::ustring("GstreamerPlayer :: open failed! Please consult console output for details."));
m_preloadThread->join(); m_errorWasRaised = true;
fireOnStopEvent(this);
} }
}
const bool isSmil = fileUrl.substr(fileUrl.size()-5, fileUrl.size()) == ".smil" ? true : false; bool
const bool isPreloaded = (m_preloadUrl == fileUrl); GstreamerPlayer :: playNextSmil(void) throw ()
{
if (isPreloaded) DEBUG_BLOCK
m_filesrc = m_preloadFilesrc; m_currentPlayLength = m_playContext->getPosition();//this gets the length of the stream that just completed
else { m_playContext->closeContext();
m_filesrc = gst_element_factory_make("filesrc", "file-source"); if(m_smilHandler == NULL){
gst_element_set(m_filesrc, "location", filePath.c_str(), NULL); return false;
} }
AudioDescription *audioDescription = m_smilHandler->getNext();
// converts between different audio formats (e.g. bitrate) if(audioDescription == NULL){//no more audio entries to play
m_audioconvert = gst_element_factory_make("audioconvert", NULL); delete m_smilHandler;
m_smilHandler = NULL;
// scale the sampling rate, if necessary return false;
m_audioscale = gst_element_factory_make("audioscale", NULL);
// Due to bugs in the minimalaudiosmil element, it does not currently work with decodebin.
// Therefore we instantiate it manually if the file has the .smil extension.
if (isSmil) {
if (isPreloaded) {
debug() << "Using preloaded SMIL element instance." << endl;
m_decoder = m_preloadDecoder;
gst_element_link(m_decoder, m_audioconvert);
}
else {
debug() << "SMIL file detected." << endl;
m_stopPreloader = false;
m_decoder = gst_element_factory_make("minimalaudiosmil", NULL);
gst_element_set(m_decoder, "abort", &m_stopPreloader, NULL);
gst_element_link_many(m_filesrc, m_decoder, m_audioconvert, NULL);
}
if (gst_element_get_parent(m_audiosink) == NULL)
gst_bin_add(GST_BIN(m_pipeline), m_audiosink);
} }
// Using GStreamer's decodebin autoplugger for everything else if(!m_playContext->openSource(audioDescription)){
else { return false;
m_decoder = gst_element_factory_make("decodebin", NULL);
gst_element_link(m_filesrc, m_decoder);
g_signal_connect(m_decoder, "new-decoded-pad", G_CALLBACK(newpadEventHandler), this);
}
if (!m_decoder) {
throw std::runtime_error("GstreamerPlayer: could not create decoder");
}
gst_bin_add_many(GST_BIN(m_pipeline), m_filesrc, m_decoder, m_audioconvert, m_audioscale, NULL);
gst_element_link_many(m_audioconvert, m_audioscale, m_audiosink, NULL);
// connect the eos signal handler
g_signal_connect(m_decoder, "eos", G_CALLBACK(eosEventHandler), this);
m_preloadUrl.clear();
if (gst_element_set_state(m_pipeline,GST_STATE_PAUSED) == GST_STATE_FAILURE) {
close();
throw std::runtime_error("GstreamerPlayer: could not open file");
} }
m_smilOffset += m_currentPlayLength;
m_playContext->playContext();
} }
@ -421,34 +310,30 @@ GstreamerPlayer :: open(const std::string fileUrl)
bool bool
GstreamerPlayer :: isOpen(void) throw () GstreamerPlayer :: isOpen(void) throw ()
{ {
return m_decoder != 0; return m_open;
} }
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Get the length of the current audio clip. * Get the length of the current audio clip.
* Currently not used by the Studio, but may be used later on.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref Ptr<time_duration>::Ref
GstreamerPlayer :: getPlaylength(void) throw (std::logic_error) GstreamerPlayer :: getPlaylength(void) throw (std::logic_error)
{ {
Ptr<time_duration>::Ref length; DEBUG_BLOCK
gint64 ns;
GstFormat format = GST_FORMAT_TIME;
if (!isOpen()) { if (!isOpen()) {
throw std::logic_error("player not open"); throw std::logic_error("player not open");
} }
if (m_decoder Ptr<time_duration>::Ref length;
&& gst_element_query(m_decoder, GST_QUERY_TOTAL, &format, &ns)
&& format == GST_FORMAT_TIME) {
// use microsec, as nanosec() is not found by the compiler (?) gint64 ns = m_playContext->getPlayLength();
length.reset(new time_duration(microsec(ns / 1000LL)));
} else {
length.reset(new time_duration(microsec(0LL)));
}
length.reset(new time_duration(microsec(ns / 1000LL)));
debug() << length << endl;
return length; return length;
} }
@ -460,16 +345,14 @@ Ptr<time_duration>::Ref
GstreamerPlayer :: getPosition(void) throw (std::logic_error) GstreamerPlayer :: getPosition(void) throw (std::logic_error)
{ {
Ptr<time_duration>::Ref length; Ptr<time_duration>::Ref length;
gint64 ns = 0;
if (!isOpen()) { if (!isOpen()) {
throw std::logic_error("player not open"); throw std::logic_error("player not open");
} }
GstFormat fmt = GST_FORMAT_TIME; gint64 ns = m_playContext->getPosition();
gst_element_query(m_audiosink, GST_QUERY_POSITION, &fmt, &ns);
length.reset(new time_duration(microseconds(ns / 1000LL))); length.reset(new time_duration(microseconds((m_smilOffset + ns) / 1000LL)));
return length; return length;
} }
@ -488,7 +371,9 @@ GstreamerPlayer :: start(void) throw (std::logic_error)
} }
if (!isPlaying()) { if (!isPlaying()) {
gst_element_set_state(m_pipeline, GST_STATE_PLAYING); m_playContext->playContext();
}else{
error() << "Already playing!" << endl;
} }
} }
@ -499,8 +384,10 @@ GstreamerPlayer :: start(void) throw (std::logic_error)
void void
GstreamerPlayer :: pause(void) throw (std::logic_error) GstreamerPlayer :: pause(void) throw (std::logic_error)
{ {
DEBUG_BLOCK
if (isPlaying()) { if (isPlaying()) {
gst_element_set_state(m_pipeline, GST_STATE_PAUSED); m_playContext->pauseContext();
} }
} }
@ -511,7 +398,7 @@ GstreamerPlayer :: pause(void) throw (std::logic_error)
bool bool
GstreamerPlayer :: isPlaying(void) throw () GstreamerPlayer :: isPlaying(void) throw ()
{ {
return gst_element_get_state(m_pipeline) == GST_STATE_PLAYING; return m_playContext->isPlaying();
} }
@ -521,12 +408,14 @@ GstreamerPlayer :: isPlaying(void) throw ()
void void
GstreamerPlayer :: stop(void) throw (std::logic_error) GstreamerPlayer :: stop(void) throw (std::logic_error)
{ {
DEBUG_BLOCK
if (!isOpen()) { if (!isOpen()) {
throw std::logic_error("GstreamerPlayer not opened yet"); throw std::logic_error("GstreamerPlayer not opened yet");
} }
if (isPlaying()) { if (isPlaying()) {
gst_element_set_state(m_pipeline, GST_STATE_READY); m_playContext->stopContext();
} }
} }
@ -539,48 +428,14 @@ GstreamerPlayer :: close(void) throw (std::logic_error)
{ {
DEBUG_BLOCK DEBUG_BLOCK
if (isPlaying()) { m_playContext->stopContext();
stop(); m_playContext->closeContext();
if(m_smilHandler != NULL){
delete m_smilHandler;
m_smilHandler = NULL;
} }
gst_element_set_state(m_pipeline, GST_STATE_NULL); m_open = false;
// Unlink elements:
if (m_filesrc && m_decoder) {
gst_element_unlink(m_filesrc, m_decoder);
}
if (m_decoder && m_audioconvert) {
gst_element_unlink(m_decoder, m_audioconvert);
}
if (m_audioconvert && m_audioscale ) {
gst_element_unlink(m_audioconvert, m_audioscale);
}
if (m_audioscale && m_audiosink) {
gst_element_unlink(m_audioscale, m_audiosink);
}
// Remove elements from pipeline:
if (m_audioscale) {
gst_bin_remove(GST_BIN(m_pipeline), m_audioscale);
}
if (m_audioconvert) {
gst_bin_remove(GST_BIN(m_pipeline), m_audioconvert);
}
if (m_decoder) {
gst_bin_remove(GST_BIN(m_pipeline), m_decoder);
}
if (m_filesrc) {
gst_bin_remove(GST_BIN(m_pipeline), m_filesrc);
}
if (m_audiosink && gst_element_get_parent(m_audiosink) == GST_OBJECT(m_pipeline)) {
gst_object_ref(GST_OBJECT(m_audiosink));
gst_bin_remove(GST_BIN(m_pipeline), m_audiosink);
}
m_filesrc = 0;
m_decoder = 0;
m_audioconvert = 0;
m_audioscale = 0;
} }
@ -611,145 +466,14 @@ GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
{ {
DEBUG_BLOCK DEBUG_BLOCK
debug() << "Using device: " << deviceName << endl;
if (deviceName.size() == 0) { if (deviceName.size() == 0) {
return false; return false;
} }
const bool oss = deviceName.find("/dev") == 0; m_playContext->setAudioDevice(deviceName);
if (m_audiosink) {
debug() << "Destroying old sink." << endl;
if (m_audioscale) {
gst_element_unlink(m_audioscale, m_audiosink);
}
if (gst_element_get_parent(m_audiosink) == NULL)
gst_object_unref(GST_OBJECT(m_audiosink));
else
gst_bin_remove(GST_BIN(m_pipeline), m_audiosink);
m_audiosink = 0;
}
if (!m_audiosink) {
m_audiosink = (oss ? gst_element_factory_make("osssink", "osssink")
: gst_element_factory_make("alsasink", "alsasink"));
}
if (!m_audiosink) {
return false;
}
// it's the same property, "device" for both alsasink and osssink
gst_element_set(m_audiosink, "device", deviceName.c_str(), NULL);
if (m_audioscale) {
gst_element_link_filtered(m_audioscale, m_audiosink, m_sinkCaps);
}
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////
// CLASS Preloader
//////////////////////////////////////////////////////////////////////////////
Preloader::Preloader(GstreamerPlayer* player, const std::string url) throw()
: RunnableInterface()
, m_player(player)
, m_fileUrl(url)
{
DEBUG_FUNC_INFO
player->m_stopPreloader = false;
}
Preloader::~Preloader() throw()
{
DEBUG_FUNC_INFO
}
void Preloader::run() throw()
{
DEBUG_BLOCK
GstreamerPlayer* const p = m_player;
const std::string fileUrl(m_fileUrl);
const bool isSmil = fileUrl.substr(fileUrl.size()-5, fileUrl.size()) == ".smil" ? true : false;
if (!isSmil)
return;
debug() << "Preloading SMIL file: " << fileUrl << endl;
std::string filePath;
if (fileUrl.find("file://") == 0) {
filePath = fileUrl.substr(7, fileUrl.size());
}
else if (fileUrl.find("file:") == 0) {
filePath = fileUrl.substr(5, fileUrl.size());
}
else {
return;
}
if (!p->m_preloadUrl.empty()) {
p->m_preloadUrl.clear();
g_object_unref(G_OBJECT(p->m_preloadFilesrc));
g_object_unref(G_OBJECT(p->m_preloadDecoder));
}
p->m_preloadFilesrc = gst_element_factory_make("filesrc", NULL);
gst_element_set(p->m_preloadFilesrc, "location", filePath.c_str(), NULL);
p->m_preloadDecoder = gst_element_factory_make("minimalaudiosmil", NULL);
gst_element_set(p->m_preloadDecoder, "abort", &p->m_stopPreloader, NULL);
GstElement* pipe = gst_pipeline_new("pipe");
GstElement* fakesink = gst_element_factory_make("fakesink", "fakesink");
gst_element_link_many(p->m_preloadFilesrc, p->m_preloadDecoder, fakesink, NULL);
gst_bin_add_many(GST_BIN(pipe), p->m_preloadFilesrc, p->m_preloadDecoder, fakesink, NULL);
gst_element_set_state(pipe, GST_STATE_PLAYING);
gint64 position = 0LL;
while (position == 0LL && !p->m_stopPreloader && gst_bin_iterate(GST_BIN(pipe))) {
GstFormat format = GST_FORMAT_DEFAULT;
gst_element_query(fakesink, GST_QUERY_POSITION, &format, &position);
}
gst_element_set_state(pipe, GST_STATE_PAUSED);
if (p->m_stopPreloader) {
debug() << "Aborting preloader, per request." << endl;
g_object_unref(G_OBJECT(p->m_preloadFilesrc));
g_object_unref(G_OBJECT(p->m_preloadDecoder));
return;
}
g_object_ref(G_OBJECT(p->m_preloadFilesrc));
g_object_ref(G_OBJECT(p->m_preloadDecoder));
gst_bin_remove_many(GST_BIN(pipe), p->m_preloadFilesrc, p->m_preloadDecoder, NULL);
gst_element_unlink(p->m_preloadFilesrc, fakesink);
gst_object_unref(GST_OBJECT(pipe));
p->m_preloadUrl = fileUrl;
p->m_preloadThread.reset();
}
void Preloader::signal(int) throw()
{}
void Preloader::stop() throw()
{
DEBUG_FUNC_INFO
m_player->m_stopPreloader = true;
}

View file

@ -50,6 +50,7 @@
#include "LiveSupport/Core/Playlist.h" #include "LiveSupport/Core/Playlist.h"
#include "GstreamerPlayContext.h"
namespace LiveSupport { namespace LiveSupport {
namespace PlaylistExecutor { namespace PlaylistExecutor {
@ -92,7 +93,6 @@ using namespace LiveSupport::Core;
class GstreamerPlayer : virtual public Configurable, class GstreamerPlayer : virtual public Configurable,
virtual public AudioPlayerInterface virtual public AudioPlayerInterface
{ {
friend class Preloader;
private: private:
/** /**
@ -103,37 +103,9 @@ class GstreamerPlayer : virtual public Configurable,
/** /**
* The pipeline inside the player * The pipeline inside the player
*/ */
GstElement * m_pipeline; GstreamerPlayContext *m_playContext;
SmilHandler *m_smilHandler;
/**
* The file source element.
*/
GstElement * m_filesrc;
/**
* The decoder element.
*/
GstElement * m_decoder;
/**
* The audioconvert element.
*/
GstElement * m_audioconvert;
/**
* The audioscale element.
*/
GstElement * m_audioscale;
/**
* The desired capabilities of the audio sink.
*/
GstCaps * m_sinkCaps;
/**
* The audio sink
*/
GstElement * m_audiosink;
/** /**
* The URL to play. * The URL to play.
@ -144,12 +116,23 @@ class GstreamerPlayer : virtual public Configurable,
* Flag to indicate if this object has been initialized. * Flag to indicate if this object has been initialized.
*/ */
bool m_initialized; bool m_initialized;
bool m_open;
/** /**
* The audio device to play on. * The audio device to play on.
*/ */
std::string m_audioDevice; std::string m_audioDevice;
/**
* The URL of the preloaded file. Empty if nothing is preloaded.
*/
std::string m_preloadUrl;
gint64 m_smilOffset;
gint64 m_currentPlayLength;
public:
/** /**
* Contains runtime error messages from GStreamer. * Contains runtime error messages from GStreamer.
*/ */
@ -160,32 +143,6 @@ class GstreamerPlayer : virtual public Configurable,
*/ */
bool m_errorWasRaised; bool m_errorWasRaised;
/**
* The URL of the preloaded file. Empty if nothing is preloaded.
*/
std::string m_preloadUrl;
/**
* The filesrc element created by the preloader.
*/
GstElement * m_preloadFilesrc;
/**
* The decoder element created by the preloader
*/
GstElement * m_preloadDecoder;
/**
* The thread that runs the preloader instance.
*/
Ptr<Thread>::Ref m_preloadThread;
/**
* Flag that indicates that the preloader should abort.
*/
gboolean m_stopPreloader;
/** /**
* The type for the vector of listeners. * The type for the vector of listeners.
* Just a shorthand notation, to make reference to the type * Just a shorthand notation, to make reference to the type
@ -200,49 +157,12 @@ class GstreamerPlayer : virtual public Configurable,
*/ */
ListenerVector m_listeners; ListenerVector m_listeners;
/**
* Handler to recieve errors from gstreamer.
*
* @param pipeline the pipeline generating the error
* @param source the source of the error
* @param error the error itself
* @param debug debug info
* @param self pointer to the associated GsreamerPlayer object.
*/
static void
errorHandler(GstElement * pipeline,
GstElement * source,
GError * error,
gchar * debug,
gpointer self) throw ();
/**
* An end-of-stream event handler, that will notify our pipeline,
* that it's all over.
*
* @param element the element emitting the eos signal
* @param self a pointer to the associated GstreamerPlayer object.
*/
static void
eosEventHandler(GstElement * element,
gpointer self)
throw ();
/**
* A newpad event handler, that will link the decoder after
* decodebin's autoplugging.
*
* @param element the element emitting the eos signal
* @param self a pointer to the associated GstreamerPlayer object.
*/
static void
newpadEventHandler(GstElement*, GstPad*, gboolean, gpointer self) throw();
/** /**
* Send the onStop event to all attached listeners. * Send the onStop event to all attached listeners.
*/ */
static gboolean static gboolean
fireOnStopEvent(gpointer self) throw (); fireOnStopEvent(gpointer self) throw ();
public: public:
@ -251,11 +171,12 @@ class GstreamerPlayer : virtual public Configurable,
*/ */
GstreamerPlayer(void) throw () GstreamerPlayer(void) throw ()
{ {
m_pipeline = 0; m_playContext = 0;
m_filesrc = 0; m_open = false;
m_decoder = 0;
m_audiosink = 0;
m_initialized = false; m_initialized = false;
m_smilHandler = NULL;
m_smilOffset = 0L;
m_currentPlayLength = 0L;
} }
/** /**
@ -377,6 +298,15 @@ class GstreamerPlayer : virtual public Configurable,
virtual bool virtual bool
isOpen(void) throw (); isOpen(void) throw ();
/**
* Plays next audio from current smil sequence
*
*
* @return true if next smil is available, false otherwise.
*/
virtual bool
playNextSmil(void) throw ();
/** /**
* Close an audio source that was opened. * Close an audio source that was opened.
* *
@ -468,39 +398,6 @@ class GstreamerPlayer : virtual public Configurable,
/**
* A class for preloading GStreamer SMIL decoder instances.
*
* Preloading initializes the decoder element in a helper thread, so
* that most of the initialization overhead is eleminated when playback
* is started.
*
* @author $Author$
* @version $Revision$
*/
class Preloader : public RunnableInterface
{
public:
Preloader(GstreamerPlayer*, const std::string) throw();
~Preloader() throw();
void run() throw();
void signal(int) throw();
void stop() throw();
private:
/**
* Pointer to GstreamerPlayer class instance.
*/
GstreamerPlayer* m_player;
/**
* The URL of the file to be preloaded.
*/
std::string m_fileUrl;
};
/* ================================================= external data structures */ /* ================================================= external data structures */

View file

@ -105,10 +105,14 @@ PKG_CHECK_MODULES(LIBGLADEMM,[libglademm-2.4 >= 2.6.2])
AC_SUBST(LIBGLADEMM_CFLAGS) AC_SUBST(LIBGLADEMM_CFLAGS)
AC_SUBST(LIBGLADEMM_LIBS) AC_SUBST(LIBGLADEMM_LIBS)
PKG_CHECK_MODULES(GSTREAMER,[gstreamer-0.8 >= 0.8]) PKG_CHECK_MODULES(GSTREAMER,[gstreamer-0.10 >= 0.10])
AC_SUBST(GSTREAMER_CFLAGS) AC_SUBST(GSTREAMER_CFLAGS)
AC_SUBST(GSTREAMER_LIBS) AC_SUBST(GSTREAMER_LIBS)
PKG_CHECK_MODULES(GSTCONTROLLER,[gstreamer-controller-0.10 >= 0.10])
AC_SUBST(GSTCONTROLLER_CFLAGS)
AC_SUBST(GSTCONTROLLER_LIBS)
AC_CHECK_CURL(7.12.3) AC_CHECK_CURL(7.12.3)
AC_SUBST(CURL_CFLAGS) AC_SUBST(CURL_CFLAGS)
AC_SUBST(CURL_LIBS) AC_SUBST(CURL_LIBS)