resolved conflicts
This commit is contained in:
parent
c9026785f9
commit
d5f97fd48e
6 changed files with 154 additions and 544 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue