added file id to smil and implemented XML-RPC callback for playback start

This commit is contained in:
nebojsa 2009-09-28 00:27:05 +00:00
parent 2b4ce13d7e
commit 9cc4389052
15 changed files with 254 additions and 28 deletions

View File

@ -90,6 +90,17 @@ class AudioPlayerEventListener
virtual void
onStop(Ptr<const Glib::ustring>::Ref errorMessage)
throw () = 0;
/**
* Catch the event when playback started.
* Every time player plays a new file, it sends this event at the beginning.
* App should use this to synchronize playback
*
* @param id represents the file that just started
*/
virtual void
onStart(gint64 id)
throw () = 0;
};

View File

@ -153,9 +153,8 @@ class AudioPlayerInterface
* @see #start
*/
virtual bool
open(const std::string fileUrl) throw (std::invalid_argument,
std::runtime_error)
= 0;
open(const std::string fileUrl, gint64 id)
throw (std::invalid_argument, std::runtime_error) = 0;
/**
* Tell if the audio player has been openned.

View File

@ -73,8 +73,8 @@ static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data
switch (GST_MESSAGE_TYPE (message)) {
//we shall handle errors as non critical events as we should not stop playback in any case
case GST_MESSAGE_EOS:
case GST_MESSAGE_ERROR:
case GST_MESSAGE_EOS:
if(player->playNextSmil()){
break;
}
@ -210,6 +210,28 @@ GstreamerPlayer :: fireOnStopEvent(gpointer self) throw ()
return false;
}
/*------------------------------------------------------------------------------
* Send the onStart event to all attached listeners.
*----------------------------------------------------------------------------*/
gboolean
GstreamerPlayer :: fireOnStartEvent(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)->onStart(player->m_Id);
++it;
}
// false == Don't call this idle function again
return false;
}
/*------------------------------------------------------------------------------
* Preload a file, to speed up the subsequent open() call.
@ -231,9 +253,8 @@ GstreamerPlayer :: preload(const std::string fileUrl)
* Specify which file to play
*----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: open(const std::string fileUri)
throw (std::invalid_argument,
std::runtime_error)
GstreamerPlayer :: open(const std::string fileUri, gint64 id)
throw (std::invalid_argument, std::runtime_error)
{
DEBUG_BLOCK
@ -254,9 +275,13 @@ GstreamerPlayer :: open(const std::string fileUri)
m_smilHandler = new SmilHandler();
m_smilHandler->openSmilFile(fileUri.c_str());
AudioDescription *audioDescription = m_smilHandler->getNext();
m_Id = audioDescription->m_Id;
m_open=m_playContext->openSource(audioDescription);
m_url = (const char*) audioDescription->m_src;
}else{
m_open=m_playContext->openSource(fileUri.c_str());
m_url = fileUri;
m_Id = id;
}
if(!m_open){
@ -266,6 +291,7 @@ GstreamerPlayer :: open(const std::string fileUri)
m_playContext->forceEOS();
return false;
}
g_idle_add(GstreamerPlayer::fireOnStartEvent, this);
return true;
}
@ -297,6 +323,9 @@ GstreamerPlayer :: playNextSmil(void) throw (
m_playContext->forceEOS();
return true;
}
m_Id = audioDescription->m_Id;
m_url = (const char*) audioDescription->m_src;
g_idle_add(GstreamerPlayer::fireOnStartEvent, this);
m_smilOffset += m_currentPlayLength;
m_playContext->playContext();
return true;

View File

@ -122,14 +122,10 @@ class GstreamerPlayer : virtual public Configurable,
* 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;
gint64 m_Id;
public:
@ -164,6 +160,12 @@ public:
static gboolean
fireOnStopEvent(gpointer self) throw ();
/**
* Send the onStart event to all attached listeners.
*/
static gboolean
fireOnStartEvent(gpointer self) throw ();
public:
/**
@ -286,8 +288,8 @@ public:
* @see #start
*/
virtual bool
open(const std::string fileUrl) throw (std::invalid_argument,
std::runtime_error);
open(const std::string fileUrl, gint64 id)
throw (std::invalid_argument, std::runtime_error);
/**
* Tell if the object is currently opened (has a file source to

View File

@ -84,11 +84,9 @@ public:
m_begin(0),
m_end(0)
{
// std::cout << "AnimationDescription created!" << std::endl;
}
~AnimationDescription()
{
// std::cout << "AnimationDescription destroyed!" << std::endl;
}
};
@ -101,19 +99,19 @@ public:
gint64 m_begin;
gint64 m_clipBegin;
gint64 m_clipEnd;
gint64 m_Id;
std::vector<AnimationDescription*> m_animations;
AudioDescription():
m_src(NULL),
m_begin(0),
m_clipBegin(0),
m_clipEnd(0)
m_clipEnd(0),
m_Id(0)
{
// std::cout << "AudioDescription created!" << std::endl;
}
~AudioDescription()
{
// std::cout << "AudioDescription destroyed!" << std::endl;
}
void release()
@ -287,6 +285,7 @@ private:
gchar * begin = 0;
gchar * clipBegin = 0;
gchar * clipEnd = 0;
gchar * idStr = 0;
/* handle the attributes */
for (attr = ((xmlElement*)audio)->attributes; attr; attr = (xmlAttribute*) attr->next) {
@ -296,6 +295,10 @@ private:
if ((node = attr->children) && node->type == XML_TEXT_NODE) {
src = (gchar*) node->content;
}
} else if (!strcmp((const char*)attr->name, "id")) {
if ((node = attr->children) && node->type == XML_TEXT_NODE) {
idStr = (gchar*) node->content;
}
} else if (!strcmp((const char*)attr->name, "begin")) {
if ((node = attr->children) && node->type == XML_TEXT_NODE) {
begin = (gchar*) node->content;
@ -328,6 +331,11 @@ private:
audioDescription->m_begin = su_smil_clock_value_to_nanosec(begin);
audioDescription->m_clipBegin = su_smil_clock_value_to_nanosec(clipBegin);
audioDescription->m_clipEnd = su_smil_clock_value_to_nanosec(clipEnd);
if(idStr)
{
std::stringstream idReader(idStr);
idReader >> audioDescription->m_Id;
}
// now handle the possible animate elements inside this audio element
for (node = audio->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {

View File

@ -146,6 +146,11 @@ const std::string smilPlayableNodeName = "audio";
*----------------------------------------------------------------------------*/
const std::string smilPlayableUriAttrName = "src";
/*------------------------------------------------------------------------------
* The name of the attribute containing the Id of the Playable element.
*----------------------------------------------------------------------------*/
const std::string smilPlayableIdAttrName = "id";
/*------------------------------------------------------------------------------
* The name of the attribute containing the relative offset of the element.
*----------------------------------------------------------------------------*/
@ -1591,9 +1596,13 @@ WebStorageClient :: acquirePlaylist(Ptr<const UniqueId>::Ref id,
switch (plElement->getType()) {
case PlaylistElement::AudioClipType :
{
url.reset(new std::string(
contentElement[getPlaylistUrlParamName]));
playable = plElement->getAudioClip();
Ptr<Playable>::Ref audioClip = playable;
subPlaylistId = audioClip->getId();
}
break;
case PlaylistElement::PlaylistType :
subPlaylistId = plElement->getPlaylist()->getId();
@ -1612,6 +1621,9 @@ WebStorageClient :: acquirePlaylist(Ptr<const UniqueId>::Ref id,
smilPlayableNode->set_attribute(
smilPlayableUriAttrName,
*url );
smilPlayableNode->set_attribute(
smilPlayableIdAttrName,
*subPlaylistId->toDecimalString() );
smilPlayableNode->set_attribute(
smilRelativeOffsetAttrName,
*TimeConversion::timeDurationToSmilString(

View File

@ -211,6 +211,14 @@ CuePlayer :: onStop(Ptr<const Glib::ustring>::Ref errorMessage) throw ()
}
}
/*------------------------------------------------------------------------------
* Event handler for the "cue audio player has started" event.
*----------------------------------------------------------------------------*/
void
CuePlayer :: onStart(gint64 id) throw ()
{
}
/*------------------------------------------------------------------------------
* Set the state of the widget.

View File

@ -175,6 +175,15 @@ class CuePlayer : public GuiComponent,
onStop(Ptr<const Glib::ustring>::Ref errorMessage
= Ptr<const Glib::ustring>::Ref())
throw ();
/**
* Event handler for the "cue audio player has started" event.
*
* @param fileName
*/
virtual void
onStart(gint64 id)
throw ();
};

View File

@ -1298,7 +1298,7 @@ GLiveSupport :: playOutputAudio(Ptr<Playable>::Ref playable)
switch (playable->getType()) {
case Playable::AudioClipType:
outputItemPlayingNow = acquireAudioClip(playable->getId());
if(false == outputPlayer->open(*outputItemPlayingNow->getUri()))
if(false == outputPlayer->open(*outputItemPlayingNow->getUri(), (gint64)outputItemPlayingNow->getId()->getId()))
{
return false;
}
@ -1310,7 +1310,7 @@ GLiveSupport :: playOutputAudio(Ptr<Playable>::Ref playable)
case Playable::PlaylistType:
outputItemPlayingNow = acquirePlaylist(playable->getId());
outputPlayer->open(*outputItemPlayingNow->getUri());
outputPlayer->open(*outputItemPlayingNow->getUri(), (gint64)outputItemPlayingNow->getId()->getId());
outputPlayer->start();
std::cerr << "gLiveSupport: Live Mode playing playlist '"
<< *playable->getTitle()
@ -1414,6 +1414,17 @@ GLiveSupport :: onStop(Ptr<const Glib::ustring>::Ref errorMessage)
}
}
/*------------------------------------------------------------------------------
* Event handler for the "output audio player has started" event.
*----------------------------------------------------------------------------*/
void
LiveSupport :: GLiveSupport ::
GLiveSupport :: onStart(gint64 id)
throw ()
{
masterPanel->setCurrentInnerPlayable(id);
}
/*------------------------------------------------------------------------------
* Play a Playable object using the cue audio player.
@ -1432,7 +1443,7 @@ GLiveSupport :: playCueAudio(Ptr<Playable>::Ref playable)
switch (playable->getType()) {
case Playable::AudioClipType:
cueItemPlayingNow = acquireAudioClip(playable->getId());
cuePlayer->open(*cueItemPlayingNow->getUri());
cuePlayer->open(*cueItemPlayingNow->getUri(), (gint64)cueItemPlayingNow->getId()->getId());
cuePlayer->start();
std::cerr << "gLiveSupport: Cue playing audio clip '"
<< *playable->getTitle()
@ -1441,7 +1452,7 @@ GLiveSupport :: playCueAudio(Ptr<Playable>::Ref playable)
case Playable::PlaylistType:
cueItemPlayingNow = acquirePlaylist(playable->getId());
cuePlayer->open(*cueItemPlayingNow->getUri());
cuePlayer->open(*cueItemPlayingNow->getUri(), (gint64)cueItemPlayingNow->getId()->getId());
cuePlayer->start();
std::cerr << "gLiveSupport: Cue playing playlist '"
<< *playable->getTitle()
@ -1758,7 +1769,7 @@ GLiveSupport :: playTestSoundOnCue(Ptr<const Glib::ustring>::Ref oldDevice,
cuePlayer->close();
}
cuePlayer->setAudioDevice(*newDevice);
cuePlayer->open(*testAudioUrl);
cuePlayer->open(*testAudioUrl, (gint64)0);
cuePlayer->start();
Ptr<time_duration>::Ref sleepT(new time_duration(microseconds(10)));
while (cuePlayer->isPlaying()) {

View File

@ -1125,6 +1125,15 @@ class GLiveSupport : public LocalizedConfigurable,
= Ptr<const Glib::ustring>::Ref())
throw ();
/**
* Event handler for the "output audio player has started" event.
*
* @param fileName
*/
virtual void
onStart(gint64 id)
throw ();
/**
* Display the playable item on the master panel as "now playing".
*/

View File

@ -411,12 +411,12 @@ LiveModeWindow :: onOutputPlay(void) throw ()
if (playable) {
try {
gLiveSupport->setNowPlaying(playable);
if(false == gLiveSupport->playOutputAudio(playable))
{
treeView->removeItem(itemPlayed);
return;
}
gLiveSupport->setNowPlaying(playable);
treeView->removeItem(itemPlayed);

View File

@ -559,6 +559,17 @@ class MasterPanelWindow : public GuiWindow
return nowPlayingWidget->getCurrentInnerPlayable();
}
/**
* Set the Playable currently shown in the "now playing" display.
*
* @return the currently playing item; 0 if nothing is playing.
*/
void
setCurrentInnerPlayable (gint64 id) throw ()
{
nowPlayingWidget->setCurrentInnerPlayable(id);
}
/**
* Upload a Playable object to the network hub.
* And display it in the Transports tab of the Search Window.

View File

@ -141,6 +141,20 @@ NowPlaying :: setStyle (Gtk::Label * label,
label->set_attributes(attributeList);
}
void
NowPlaying :: setCurrentInnerPlayable (gint64 id) throw ()
{
playableMutex.lock();
if((gint64)currentInnerPlayable->getId()->getId() != id)
{
//we are not playing a correct file, must have had an error - adjust the playlist
std::cout << "NowPlaying :: setCurrentInnerPlayable ERROR DETECTED! called = " << id << ", current = " << (gint64)currentInnerPlayable->getId()->getId() << std::endl;
}
else{
std::cout << "NowPlaying :: setCurrentInnerPlayable CORRECT!" << std::endl;
}
playableMutex.unlock();
}
/*------------------------------------------------------------------------------
* Set the title etc. of the playable shown in the widget.
@ -162,8 +176,99 @@ NowPlaying :: setPlayable (Ptr<Playable>::Ref playable) throw ()
isActive = true;
isPaused = false;
resetRemainsTimeState();
onUpdateTime();
remainsTimeCounter++;
if (remainsTimeCounter == 2*blinkingConstant) {
remainsTimeCounter = 0;
}
Ptr<time_duration>::Ref elapsed;
try {
elapsed = gLiveSupport->getOutputAudioPosition();
} catch (std::logic_error &e) {
elapsed.reset(new time_duration(microseconds(0)));
}
Ptr<time_duration>::Ref totalLength
= TimeConversion::roundToNearestSecond(
playable->getPlaylength());
Ptr<time_duration>::Ref remains(new time_duration(
*totalLength - *elapsed));
switch (remainsTimeState) {
case TIME_GREEN :
if (*remains <= seconds(20)) {
remainsTimeState = TIME_YELLOW;
}
break;
case TIME_YELLOW :
if (*remains <= seconds(10)) {
remainsTimeState = TIME_RED;
}
break;
case TIME_RED :
break;
}
setRemainsTimeColor(remainsTimeState);
Ptr<Playable>::Ref innerPlayable = playable;
Ptr<time_duration>::Ref innerElapsed = elapsed;
Ptr<time_duration>::Ref innerRemains = remains;
Glib::ustring playlistInfo;
bool isFirst = true;
while (innerPlayable->getType() == Playable::PlaylistType) {
if (isFirst) {
isFirst = false;
} else {
playlistInfo += " >>> ";
}
playlistInfo += *innerPlayable->getTitle();
playlistInfo += " [";
playlistInfo += *TimeConversion::timeDurationToHhMmSsString(innerRemains);
playlistInfo += "/";
playlistInfo += *TimeConversion::timeDurationToHhMmSsString(innerPlayable->getPlaylength());
playlistInfo += "]";
Ptr<PlaylistElement>::Ref element = innerPlayable->getPlaylist()->findAtOffset(elapsed);
if (!element) {
break;
}
innerPlayable = element->getPlayable();
*innerElapsed -= *element->getRelativeOffset();
*innerRemains = *TimeConversion::roundToNearestSecond(
innerPlayable->getPlaylength()) - *innerElapsed;
}
playlistLabel->set_text(playlistInfo);
titleLabel->set_text(*innerPlayable->getTitle());
Ptr<Glib::ustring>::Ref
creator = innerPlayable->getMetadata("dc:creator");
if (creator) {
creatorLabel->set_text(*creator);
} else {
creatorLabel->set_text("");
}
elapsedTimeLabel->set_text(*TimeConversion::timeDurationToHhMmSsString(innerElapsed ));
remainsTimeLabel->set_text(*TimeConversion::timeDurationToHhMmSsString(innerRemains ));
long elapsedMilliSec = innerElapsed->total_milliseconds();
long totalMilliSec = elapsedMilliSec
+ innerRemains->total_milliseconds();
double fraction = double(elapsedMilliSec) / double(totalMilliSec);
if (fraction < 0.0) {
fraction = 0.0; // can't happen afaik
}
if (fraction > 1.0) {
fraction = 1.0; // can and does happen!
}
progressBar->set_fraction(fraction);
currentInnerPlayable = innerPlayable;
} else {
if (isActive && !isPaused) {
playButton->set_label(playStockImageName);

View File

@ -290,6 +290,18 @@ class NowPlaying : public GuiComponent
return currentInnerPlayable;
}
/**
* Set the Playable object which is playing now.
* If a playlist is playing, does not return the playlist, but
* the audio clip inside the playlist (possibly several levels deep).
*
* This is used by GLiveSupport::substituteRdsData().
*
* @return void
*/
void
setCurrentInnerPlayable (gint64 id) throw ();
/**
* Change the user interface language of the widget.
*

View File

@ -158,7 +158,7 @@ PlaylistEvent :: start(void) throw ()
}
try {
audioPlayer->open(*playlist->getUri());
audioPlayer->open(*playlist->getUri(), (gint64)playlist->getId()->getId());
audioPlayer->start();
playLog->addPlayLogEntry(playlist->getId(), TimeConversion::now());