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++
gstreamer_dir=$toolsdir/gstreamer
gstreamer_version=gstreamer-0.8.12
gstreamer_version=gstreamer-0.10.15
gstreamer_tmpdir=$tools_tmpdir/gstreamer
taglib_dir=$toolsdir/taglib

View File

@ -108,7 +108,7 @@ LIBODBCXX_VERSION = libodbc++-0.2.3-20050404
XMLRPCXX_DIR = ${TOOLS_DIR}/xmlrpc++
XMLRPCXX_VERSION = xmlrpc++-20040713
GSTREAMER_DIR = ${TOOLS_DIR}/gstreamer
GSTREAMER_VERSION = gstreamer-0.8.12
GSTREAMER_VERSION = gstreamer-0.10.15
TAGLIB_DIR = ${TOOLS_DIR}/taglib
TAGLIB_VERSION = taglib-1.4
LIBSERIAL_DIR = ${TOOLS_DIR}/libserial
@ -120,7 +120,6 @@ CORE_DIR = ${MODULES_DIR}/core
AUTHENTICATION_DIR = ${MODULES_DIR}/authentication
DB_DIR = ${MODULES_DIR}/db
STORAGE_CLIENT_DIR = ${MODULES_DIR}/storageClient
GSTREAMER_ELEMENTS_DIR = ${MODULES_DIR}/gstreamerElements
PLAYLIST_EXECUTOR_DIR = ${MODULES_DIR}/playlistExecutor
EVENT_SCHEDULER_DIR = ${MODULES_DIR}/eventScheduler
SCHEDULER_CLIENT_DIR = ${MODULES_DIR}/schedulerClient
@ -181,8 +180,6 @@ flawfinder:
${AUTHENTICATION_DIR}/include ${AUTHENTICATION_DIR}/src \
${DB_DIR}/include ${DB_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}/src \
${EVENT_SCHEDULER_DIR}/include ${EVENT_SCHEDULER_DIR}/src \
@ -297,9 +294,6 @@ ${TMP_DIR}/modules_setup.stamp:
cd ${STORAGE_CLIENT_DIR} && \
./configure --prefix=${prefix} --enable-debug=${DEBUG} \
PACKAGE_VERSION=${PACKAGE_VERSION}
cd ${GSTREAMER_ELEMENTS_DIR} && \
./configure --prefix=${prefix} --enable-debug=${DEBUG} \
PACKAGE_VERSION=${PACKAGE_VERSION}
cd ${PLAYLIST_EXECUTOR_DIR} && \
./configure --prefix=${prefix} --enable-debug=${DEBUG} \
PACKAGE_VERSION=${PACKAGE_VERSION}
@ -352,7 +346,6 @@ modprod_distclean:
${MAKE} -C ${AUTHENTICATION_DIR} distclean
${MAKE} -C ${DB_DIR} distclean
${MAKE} -C ${STORAGE_CLIENT_DIR} distclean
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} distclean
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} distclean
${MAKE} -C ${EVENT_SCHEDULER_DIR} distclean
${MAKE} -C ${SCHEDULER_CLIENT_DIR} distclean
@ -368,7 +361,6 @@ depclean:
${MAKE} -C ${AUTHENTICATION_DIR} depclean
${MAKE} -C ${DB_DIR} depclean
${MAKE} -C ${STORAGE_CLIENT_DIR} depclean
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} depclean
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} depclean
${MAKE} -C ${EVENT_SCHEDULER_DIR} depclean
${MAKE} -C ${SCHEDULER_CLIENT_DIR} depclean
@ -384,7 +376,6 @@ ${TMP_DIR}/compile.stamp:
${MAKE} -C ${AUTHENTICATION_DIR} all
${MAKE} -C ${DB_DIR} all
${MAKE} -C ${STORAGE_CLIENT_DIR} all
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} all
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} all
${MAKE} -C ${EVENT_SCHEDULER_DIR} all
${MAKE} -C ${SCHEDULER_CLIENT_DIR} all
@ -398,7 +389,6 @@ check:
-${MAKE} -C ${AUTHENTICATION_DIR} check
-${MAKE} -C ${DB_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 ${EVENT_SCHEDULER_DIR} check
-${MAKE} -C ${SCHEDULER_CLIENT_DIR} check
@ -462,7 +452,6 @@ install_modules:
${MAKE} -C ${AUTHENTICATION_DIR} install
${MAKE} -C ${DB_DIR} install
${MAKE} -C ${STORAGE_CLIENT_DIR} install
${MAKE} -C ${GSTREAMER_ELEMENTS_DIR} install
${MAKE} -C ${PLAYLIST_EXECUTOR_DIR} install
${MAKE} -C ${EVENT_SCHEDULER_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],
[../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
AC_CONFIG_COMMANDS([../src/modules/playlistExecutor/tmp/configure],
[../src/modules/playlistExecutor/bin/autogen.sh])
@ -376,7 +372,7 @@ AC_MSG_NOTICE(
by Campcaster:
cppunit 1.10.2 ${COMPILE_CPPUNIT}
gstreamer 0.8.12 yes
gstreamer 0.10.15 yes
libodbc++ 0.2.3 yes
taglib 1.4 yes
xmlrpc++ 2004-07-13 yes

View File

@ -37,6 +37,7 @@
#include "LiveSupport/Core/Debug.h"
#include "LiveSupport/Core/TimeConversion.h"
#include "GstreamerPlayer.h"
@ -65,6 +66,42 @@ static const std::string audioDeviceName = "audioDevice";
/* ============================================================= 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.
*----------------------------------------------------------------------------*/
@ -102,65 +139,19 @@ GstreamerPlayer :: initialize(void) throw (std::exception)
}
// 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");
}
// create the pipeline container (threaded)
m_pipeline = gst_thread_new("audio-player");
m_playContext = new GstreamerPlayContext();
m_filesrc = 0;
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);
m_playContext->setParentData(this);
// set up other variables
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
*----------------------------------------------------------------------------*/
@ -170,23 +161,13 @@ GstreamerPlayer :: deInitialize(void) throw ()
DEBUG_FUNC_INFO
if (m_initialized) {
gst_element_set_state(m_pipeline, GST_STATE_NULL);
gst_bin_sync_children_state(GST_BIN(m_pipeline));
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_playContext->closeContext();
delete m_playContext;
m_playContext = NULL;
m_initialized = false;
}
}
/*------------------------------------------------------------------------------
* Attach an event listener.
*----------------------------------------------------------------------------*/
@ -224,15 +205,15 @@ GstreamerPlayer :: detachListener(AudioPlayerEventListener* eventListener)
* Send the onStop event to all attached listeners.
*----------------------------------------------------------------------------*/
gboolean
GstreamerPlayer :: fireOnStopEvent(gpointer self) throw ()
GstreamerPlayer :: fireOnStopEvent(gpointer self) throw ()
{
DEBUG_BLOCK
GstreamerPlayer* const player = (GstreamerPlayer*) self;
ListenerVector::iterator it = player->m_listeners.begin();
ListenerVector::iterator end = player->m_listeners.end();
while (it != end) {
(*it)->onStop(player->m_errorMessage);
++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.
*----------------------------------------------------------------------------*/
@ -299,18 +235,10 @@ GstreamerPlayer :: preload(const std::string fileUrl)
std::runtime_error)
{
DEBUG_BLOCK
if (m_preloadThread) {
m_preloadThread->stop();
m_preloadThread->join();
m_preloadThread.reset();
}
Ptr<Preloader>::Ref loader;
loader.reset(new Preloader(this, fileUrl));
m_preloadThread.reset(new Thread(loader));
m_preloadThread->start();
//According to the Gstreamer documentation, stream buffering happens
//automatically when the pipeline is set to GST_STATE_PAUSED.
//As this state is now set automatically in the open function,
//we no longer have a need for preloading.
}
@ -318,100 +246,61 @@ GstreamerPlayer :: preload(const std::string fileUrl)
* Specify which file to play
*----------------------------------------------------------------------------*/
void
GstreamerPlayer :: open(const std::string fileUrl)
GstreamerPlayer :: open(const std::string fileUri)
throw (std::invalid_argument,
std::runtime_error)
{
// GStreamer pipeline overview:
// filesrc -> decoder -> audioconvert -> audioscale -> audiosink
DEBUG_BLOCK
if (isOpen()) {
close();
}
m_smilOffset = 0L;
debug() << "Opening URL: " << fileUrl << endl;
debug() << "Opening URL: " << fileUri << endl;
debug() << "Timestamp: " << *TimeConversion::now() << endl;
m_errorMessage.reset();
m_errorWasRaised = false;
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 {
throw std::invalid_argument("badly formed URL or unsupported protocol");
m_playContext->setAudioDevice(m_audioDevice);
if (fileUri.find(std::string(".smil")) != std::string::npos) {
m_smilHandler = new SmilHandler();
m_smilHandler->openSmilFile(fileUri.c_str());
AudioDescription *audioDescription = m_smilHandler->getNext();
m_open=m_playContext->openSource(audioDescription);
}else{
m_open=m_playContext->openSource(fileUri.c_str());
}
if (m_preloadThread) {
debug() << "Waiting for Preloader thread to finish..." << endl;
m_preloadThread->join();
if(!m_open){
m_errorMessage.reset(new const Glib::ustring("GstreamerPlayer :: open failed! Please consult console output for details."));
m_errorWasRaised = true;
fireOnStopEvent(this);
}
}
const bool isSmil = fileUrl.substr(fileUrl.size()-5, fileUrl.size()) == ".smil" ? true : false;
const bool isPreloaded = (m_preloadUrl == fileUrl);
if (isPreloaded)
m_filesrc = m_preloadFilesrc;
else {
m_filesrc = gst_element_factory_make("filesrc", "file-source");
gst_element_set(m_filesrc, "location", filePath.c_str(), NULL);
bool
GstreamerPlayer :: playNextSmil(void) throw ()
{
DEBUG_BLOCK
m_currentPlayLength = m_playContext->getPosition();//this gets the length of the stream that just completed
m_playContext->closeContext();
if(m_smilHandler == NULL){
return false;
}
// converts between different audio formats (e.g. bitrate)
m_audioconvert = gst_element_factory_make("audioconvert", NULL);
// scale the sampling rate, if necessary
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);
AudioDescription *audioDescription = m_smilHandler->getNext();
if(audioDescription == NULL){//no more audio entries to play
delete m_smilHandler;
m_smilHandler = NULL;
return false;
}
// Using GStreamer's decodebin autoplugger for everything else
else {
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");
if(!m_playContext->openSource(audioDescription)){
return false;
}
m_smilOffset += m_currentPlayLength;
m_playContext->playContext();
}
@ -421,34 +310,30 @@ GstreamerPlayer :: open(const std::string fileUrl)
bool
GstreamerPlayer :: isOpen(void) throw ()
{
return m_decoder != 0;
return m_open;
}
/*------------------------------------------------------------------------------
* Get the length of the current audio clip.
* Currently not used by the Studio, but may be used later on.
*----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPlaylength(void) throw (std::logic_error)
{
Ptr<time_duration>::Ref length;
gint64 ns;
GstFormat format = GST_FORMAT_TIME;
DEBUG_BLOCK
if (!isOpen()) {
throw std::logic_error("player not open");
}
Ptr<time_duration>::Ref length;
gint64 ns = m_playContext->getPlayLength();
length.reset(new time_duration(microsec(ns / 1000LL)));
if (m_decoder
&& gst_element_query(m_decoder, GST_QUERY_TOTAL, &format, &ns)
&& format == GST_FORMAT_TIME) {
// use microsec, as nanosec() is not found by the compiler (?)
length.reset(new time_duration(microsec(ns / 1000LL)));
} else {
length.reset(new time_duration(microsec(0LL)));
}
debug() << length << endl;
return length;
}
@ -460,16 +345,14 @@ Ptr<time_duration>::Ref
GstreamerPlayer :: getPosition(void) throw (std::logic_error)
{
Ptr<time_duration>::Ref length;
gint64 ns = 0;
if (!isOpen()) {
throw std::logic_error("player not open");
}
GstFormat fmt = GST_FORMAT_TIME;
gst_element_query(m_audiosink, GST_QUERY_POSITION, &fmt, &ns);
length.reset(new time_duration(microseconds(ns / 1000LL)));
gint64 ns = m_playContext->getPosition();
length.reset(new time_duration(microseconds((m_smilOffset + ns) / 1000LL)));
return length;
}
@ -488,7 +371,9 @@ GstreamerPlayer :: start(void) throw (std::logic_error)
}
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
GstreamerPlayer :: pause(void) throw (std::logic_error)
{
DEBUG_BLOCK
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
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
GstreamerPlayer :: stop(void) throw (std::logic_error)
{
DEBUG_BLOCK
if (!isOpen()) {
throw std::logic_error("GstreamerPlayer not opened yet");
}
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
if (isPlaying()) {
stop();
m_playContext->stopContext();
m_playContext->closeContext();
if(m_smilHandler != NULL){
delete m_smilHandler;
m_smilHandler = NULL;
}
gst_element_set_state(m_pipeline, GST_STATE_NULL);
// 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;
m_open = false;
}
@ -611,145 +466,14 @@ GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
{
DEBUG_BLOCK
debug() << "Using device: " << deviceName << endl;
if (deviceName.size() == 0) {
return false;
}
const bool oss = deviceName.find("/dev") == 0;
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);
}
m_playContext->setAudioDevice(deviceName);
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 "GstreamerPlayContext.h"
namespace LiveSupport {
namespace PlaylistExecutor {
@ -92,7 +93,6 @@ using namespace LiveSupport::Core;
class GstreamerPlayer : virtual public Configurable,
virtual public AudioPlayerInterface
{
friend class Preloader;
private:
/**
@ -103,37 +103,9 @@ class GstreamerPlayer : virtual public Configurable,
/**
* 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.
@ -144,12 +116,23 @@ class GstreamerPlayer : virtual public Configurable,
* Flag to indicate if this object has been initialized.
*/
bool m_initialized;
bool m_open;
/**
* The audio device to play on.
*/
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.
*/
@ -160,32 +143,6 @@ class GstreamerPlayer : virtual public Configurable,
*/
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.
* Just a shorthand notation, to make reference to the type
@ -200,49 +157,12 @@ class GstreamerPlayer : virtual public Configurable,
*/
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.
*/
static gboolean
fireOnStopEvent(gpointer self) throw ();
fireOnStopEvent(gpointer self) throw ();
public:
@ -251,11 +171,12 @@ class GstreamerPlayer : virtual public Configurable,
*/
GstreamerPlayer(void) throw ()
{
m_pipeline = 0;
m_filesrc = 0;
m_decoder = 0;
m_audiosink = 0;
m_playContext = 0;
m_open = false;
m_initialized = false;
m_smilHandler = NULL;
m_smilOffset = 0L;
m_currentPlayLength = 0L;
}
/**
@ -377,6 +298,15 @@ class GstreamerPlayer : virtual public Configurable,
virtual bool
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.
*
@ -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 */

View File

@ -105,10 +105,14 @@ PKG_CHECK_MODULES(LIBGLADEMM,[libglademm-2.4 >= 2.6.2])
AC_SUBST(LIBGLADEMM_CFLAGS)
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_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_SUBST(CURL_CFLAGS)
AC_SUBST(CURL_LIBS)