HydrogenAudio

Hosted Forums => foobar2000 => Development - (fb2k) => Topic started by: Wadsbrau on 2009-05-11 01:55:30

Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-11 01:55:30
I'm putting the finishing touches on a plugin that makes FB2K a Upnp renderer.  However, I have run into a problem that is beyond my programming experience. 

I need FB2K to send out a message (in XML format per Upnp) whenever it stops playing.  The Upnp plugin generally will inquire regarding the state of the renderer every second.  However, some devices I have used to control the music turn off the screen to save power.  This also seems to stop (while scrren is off) the every second inquiy.

In order for the controller to play the next song in its playlist, it must be told by the transport that the current song has finished.  This is done with a simple XML script sent to the network.

I have no idea how to have FB2K do such a thing without some sort of loop askiing it if it's playing or not (which is what im doing now).

Please help me figure out how to make FB2K send out the message (I can write the XML stuff)

Thank you

Darren
Title: I need foobar2000 to send message when it is finished playing
Post by: Yirkha on 2009-05-11 02:14:06
I'm putting the finishing touches on a plugin that makes FB2K a Upnp renderer.
What does it do, something like foo_upnp (http://www.hydrogenaudio.org/forums/index.php?showtopic=69664)?
However, I have run into a problem that is beyond my programming experience. I have no idea how to have FB2K do such a thing without some sort of loop askiing it if it's playing or not (which is what im doing now).
Implement a [font= "Courier New"]play_callback[/font] service.
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-11 16:23:55
I'm putting the finishing touches on a plugin that makes FB2K a Upnp renderer.
What does it do, something like foo_upnp (http://www.hydrogenaudio.org/forums/index.php?showtopic=69664)?
However, I have run into a problem that is beyond my programming experience. I have no idea how to have FB2K do such a thing without some sort of loop askiing it if it's playing or not (which is what im doing now).
Implement a play_callback service.


Is there any way you could give me a hand regarding what that code would look like please?

Thank you
Darren

I'll look in to the renderer portion of that plugin and test it out.
EDIT: I did just now test that plugin for rendering from 2-3 different control point and server programs.  It failed to play the mp3's or the flac.  My plugin is only for rendering and is nearly fully functional execpt for this issue that just came up yesterday.
Title: I need foobar2000 to send message when it is finished playing
Post by: Yirkha on 2009-05-11 20:30:05
It is interesting that you've managed to write the whole component, but now simple service implementation is "beyond your programming experience".
Code: [Select]
class Foo : public play_callback_static {
  public:
    virtual unsigned get_flags() { return flag_on_playback_stop; }
    virtual void on_playback_starting(play_control::t_track_command p_command,bool p_paused) {}
    virtual void on_playback_new_track(metadb_handle_ptr p_track) {}
    virtual void on_playback_stop(play_control::t_stop_reason p_reason) { uDebugLog() << "on_playback_stop()"; }
    virtual void on_playback_seek(double p_time) {}
    virtual void on_playback_pause(bool p_state) {}
    virtual void on_playback_edited(metadb_handle_ptr p_track) {}
    virtual void on_playback_dynamic_info(const file_info & p_info) {}
    virtual void on_playback_dynamic_info_track(const file_info & p_info) {}
    virtual void on_playback_time(double p_time) {}
    virtual void on_volume_change(float p_new_val) {}
};

static play_callback_static_factory_t<Foo> bar;
Title: I need foobar2000 to send message when it is finished playing
Post by: bubbleguuum on 2009-05-11 20:53:34
I'll look in to the renderer portion of that plugin and test it out.
EDIT: I did just now test that plugin for rendering from 2-3 different control point and server programs.  It failed to play the mp3's or the flac.  My plugin is only for rendering and is nearly fully functional execpt for this issue that just came up yesterday.


What control point and server did you use that didn't work ? It could be possible teh flac wasn't working if the control point matched both the server and renderer protocolInfo since I added the correct mime-type for flac only in an unreleased version.
For your problem look at  on_playback_stop() and  on_playback_new_track().
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-11 21:25:43
I'll look in to the renderer portion of that plugin and test it out.
EDIT: I did just now test that plugin for rendering from 2-3 different control point and server programs.  It failed to play the mp3's or the flac.  My plugin is only for rendering and is nearly fully functional execpt for this issue that just came up yesterday.


What control point and server did you use that didn't work ? It could be possible teh flac wasn't working if the control point matched both the server and renderer protocolInfo since I added the correct mime-type for flac only in an unreleased version.
For your problem look at  on_playback_stop() and  on_playback_new_track().


I used Fuppes, Intel Tools server.  Control points are Cidero and the Intel Media controller.  I was going to test it more with the controllers, Plug Player (from iPhone) and mediastreamer (from Nokia N800).  Have to wait until i get home from work for that.  Where I can also try it with my TVersity and Twonky server setups.

Darren
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-11 21:31:54
It is interesting that you've managed to write the whole component, but now simple service implementation is "beyond your programming experience".
Code: [Select]
class Foo : public play_callback_static {
  public:
    virtual unsigned get_flags() { return flag_on_playback_stop; }
    virtual void on_playback_starting(play_control::t_track_command p_command,bool p_paused) {}
    virtual void on_playback_new_track(metadb_handle_ptr p_track) {}
    virtual void on_playback_stop(play_control::t_stop_reason p_reason) { uDebugLog() << "on_playback_stop()"; }
    virtual void on_playback_seek(double p_time) {}
    virtual void on_playback_pause(bool p_state) {}
    virtual void on_playback_edited(metadb_handle_ptr p_track) {}
    virtual void on_playback_dynamic_info(const file_info & p_info) {}
    virtual void on_playback_dynamic_info_track(const file_info & p_info) {}
    virtual void on_playback_time(double p_time) {}
    virtual void on_volume_change(float p_new_val) {}
};

static play_callback_static_factory_t<Foo> bar;


Most of my experience involves C and not C++.  Although I have learned much during the writing ofthis code.
All of the parts of the Upnp up until this point are either notifying (via XML) or manipulating FB2K (play,pause,stop,etc).  Which I have gotten to work perfectly.  This is a stumbling block for me as now I need FB2K to tell the UPnP connection that it has stopped playing.

Thanks for your help

Darren
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-12 22:47:33
I know about the on_playback_stop().  I am unsure as how to utilize it in the code.  I am new to using callbacks.

Please help, I am almost finished.

Thank you

Darren
Title: I need foobar2000 to send message when it is finished playing
Post by: bubbleguuum on 2009-05-12 23:35:38
I know about the on_playback_stop().  I am unsure as how to utilize it in the code.  I am new to using callbacks.

Please help, I am almost finished.

Thank you

Darren


on_playback_stop() is a callback called at the end of each track provided "stop after current" is enabled (for your purpose). You enable stop after current with this:

Code: [Select]
static_api_ptr_t<playback_control>()->set_stop_after_current(true);


ideally you want to enable "stop after current" before playing the track (ie before static_api_ptr_t<playback_control>()->start() ) and restore its previous value in on_playback_stop().

About implement play_callback, just inherit a class from play_callback_impl_base

Code: [Select]
class foo: public play_callback_impl_base {

virtual void on_playback_stop(play_control::t_stop_reason p_reason) {
// set the AVTransport variable "TransportState" to "STOPPED" here
}
};
Title: I need foobar2000 to send message when it is finished playing
Post by: Yirkha on 2009-05-20 09:35:57
From foo_upnp topic (http://www.hydrogenaudio.org/forums/index.php?s=&showtopic=69664&view=findpost&p=635661):
The renderer I started 6 months ago has hit a snag that I can't seem to get help with.  (...) My project is 95% finished.  But I might not finish it due to getting no help (which is what I thought a forum was for...but?) ...
But what? I certainly hope you don't mean this thread, which showed your inability to grasp simple programming topics on your own (this is not a C++ class, this is an application support forum) and where people have been explaining what you wanted to know over and over again (that's someone trying to help you, if you didn't notice).
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-20 20:44:46
From foo_upnp topic (http://www.hydrogenaudio.org/forums/index.php?s=&showtopic=69664&view=findpost&p=635661):
The renderer I started 6 months ago has hit a snag that I can't seem to get help with.  (...) My project is 95% finished.  But I might not finish it due to getting no help (which is what I thought a forum was for...but?) ...
But what? I certainly hope you don't mean this thread, which showed your inability to grasp simple programming topics on your own (this is not a C++ class, this is an application support forum) and where people have been explaining what you wanted to know over and over again (that's someone trying to help you, if you didn't notice).


Not to argue with you much.  This isnt about my programming ability.  If I were to write my own player software from scratch, I would now how to manipulate the code.  This code was written by someone else and the documentation for the so-called SDK is either non-existant or extremely poor.  It's like looking at a car engine for the first time.  Sure, someone could eventually figure out how to take it apart and repair it.  Wouldn't it be faster and easier if they had a manual?  Most of the code I have figured out.  All of the UPnP code I figured out on my own with no-one's help as there is even less documentation for that. 

If the knowledgable people that are members of this forum were more open to help others more, there would probably be many more coders out there that would write more plugins.  Wouldn't that be a good thing?  I have read through every thread in the Development section of this forum and found that there are many like myself who just needed a little help, never got it and abandoned thier projects.  What is the harm in explaining how one function works?  After all, If I was shown how the play callback works for stop, I would know how all of them would work.

I understand the above code.  The problem I ran into is that (until I re-write the whole plugin) the UPnP stack runs in a separate thread from Foobar2000.  I have been successful in sending the commands to Foobar (in its thread) telling it what to play and how to play it.  I just don't know how to have Foobar2000 (from it's own thread) send something back to the UPnP thread.

We all have various skill levels when it comes to programming.  If everyone had the skills to understand everything about the Foobar SDK, there would be no need for a forum at all.

Oh well.  I was just looking for a little help so I can finish my project.

Darren
Title: I need foobar2000 to send message when it is finished playing
Post by: Yirkha on 2009-05-20 22:17:15
Well...
You asked how to get a notification when playback stops, I told you the relevant service class name.
You asked for an example, I wrote you a fully functional piece of code, which, when pasted to a C++ file including the foobar2000 headers, outputs a message when playback stops.
You asked how to work with it, I did not understand, but bubbleguuum willingly tried to help you and wrote something more.
You just stopped participating in this thread and wrote the quoted claims elsewhere.
I'm sure that if you could say what specifically you don't understand and what specifically you need to know, instead of something vague like "I am unsure as how to utilize it in the code. I am new to using callbacks.", you would get more concise replies.
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-20 23:01:39
I tried asking specifi questions before with another issue.  I never got an answer and had to try for myself.  I am not actually complaining, just stating that the level of help seems to be "if you don't know how to do that, you need to learn more about programming". 

I understand the code example that was explained to me above.  And it would work if the UPnP stack was not running in its own thread calling foobar to perform functions.  I've know from the beginning that that is not a good way to do that at all.  I have learned enough about UPnP to re-write it so it is more closly embeded into Foobar.  But, I wanted to finish the current project first.  The only thing left is for Foobar to tell my UPnP thread when it is stopped.  I absolutley appreciate the assistance that you, Bubbleguuum and others have given me. 

Part of what I stated was due to some PM's that I sent to members asking for help and never received a reply. (no names)

Thank you

Darren
Title: I need foobar2000 to send message when it is finished playing
Post by: Yirkha on 2009-05-20 23:19:03
The only thing left is for Foobar to tell my UPnP thread when it is stopped.
Ok, that wasn't apparent previously. It's more of a platform-related issue though. Depends on how the thread works and what/if it uses any threading platform abstraction library.
If it's running some kind of a worker loop, you can simply update a global variable in various play_callback methods and then check it in other thread at relevant time.
If it waits on some synchronization object, you'd have to create an event object, set it in the play_callback and change the waiting code to wait on it too and handle the case when it gets set. The same applies when it e.g. waits for network input, that would need to be rewritten using asynchronous I/O for this.
Title: I need foobar2000 to send message when it is finished playing
Post by: bubbleguuum on 2009-05-20 23:45:36
As Yirkha explained you need to read more on how to have 2 threads both accessing a common resource (an instance of a class for example) safely.
This is a classic threading programming problem not specific to foobar2000 and largely documented. You must understand properly how to protect this common
resource for concurrent access. This is usually done with a mutex (CreateMutex()) or a critical section (EnterCriticalSection() and friends).
When you have understood the above just use a shared variable (object) between the two thread properly protected, have on_playback_stop() write it and your working thread read it.
You may need to store the previous copy to detect the change.
A more complicated and elegant solution would be to write the equivalent of main_thread_callback but the other way round but it assumes to be quite comfortable with threads and synchronization.
Title: I need foobar2000 to send message when it is finished playing
Post by: Wadsbrau on 2009-05-21 00:39:33
As Yirkha explained you need to read more on how to have 2 threads both accessing a common resource (an instance of a class for example) safely.
This is a classic threading programming problem not specific to foobar2000 and largely documented. You must understand properly how to protect this common
resource for concurrent access. This is usually done with a mutex (CreateMutex()) or a critical section (EnterCriticalSection() and friends).
When you have understood the above just use a shared variable (object) between the two thread properly protected, have on_playback_stop() write it and your working thread read it.
You may need to store the previous copy to detect the change.
A more complicated and elegant solution would be to write the equivalent of main_thread_callback but the other way round but it assumes to be quite comfortable with threads and synchronization.


Thank you.  I have already been using a stack to store various information that both threads seem to have no problem reading.  And I have variables for when foobar is playing, paused stopped etc.  I am having no trouble in telling the Foobar main thread what to do.  I just don't know how to go from the Foobar thread back to a function in the UPnP thread that could throw out the AVtransport "STOPPED"

And that works great as long as the Control Point is continuously inquiring using GetPositionInfo() or GetTransportInfo().  When the Nokia n800 (Mediastreamer) goes to sleep, it no longer sends the inquiries.  And the Nokia will not play the next song on it's playlist. So, the only way for Mediastreamer to know that the renderer has stopped playing the current file is to have the renderer itself send the AVTransport "STOPPED" xml without the control point asking for it.  If I prevent the Nokia from sleeping it plays through the playlist just fine.  But kills the battery life.

All along I have known this is the worse possible way to write this and was merely intended as an "exploritory" first attempt.  Once I got everything to work, I would "re-do" the code in a much more elegant and efficient manner.

If you don't mind me asking, are you using a UPnP sdk of any sort?  Do you have to use two or more threads as well?

In the meantime im going to setup your render and test it with all of the device I have available.  Iphone, Nnokia, PC, and an HTC 6700 (which runs Windows mobile 5) with a comple of different control point programs.

Would you have any idea why the LinnGui PC software can "see" your renderer but it can't "see" mine or the Intel test renderer?  I was using the device spy but can't find what i'm missing.

I am really stuck this time.
So:
Quote
When you have understood the above just use a shared variable (object) between the two thread properly protected, have on_playback_stop() write it and your working thread read it.

Wouldnt work unless the control point asks for the status.  Am I right?

Thank you for your help.