Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Foobar as a UPnP renderer (player (Read 20051 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Foobar as a UPnP renderer (player

I am in the initial stages of creating a plugin (my first) that will make Foobar2000 a player for UPnP.  I am not unfamiliar to the general logic of prgramming.  I experience is mainly in C. 

My code for the UPnP will compile and run as a stand alone app.  Although it doesn't have any player capability at this time. 
I have been able to add the UPnP stack code (as dll) to the SDK and can build it and add it to foobar with no errors and no functionality. 

My first step is that I merely need to have foobar launch the UPnP code when it starts up.  Howvever, I have no knowledge of Foobar's objects and functions. 

Can anyone help me get started with the code that is used to initialize my plugin when foobar starts up?

I have tried this but it doesnt work:

Code: [Select]
include "../SDK/foobar2000.h"
DECLARE_COMPONENT_VERSION("Test", "0.1", NULL);

class initquit_handler : public initquit
{
    virtual void on_init()
    {
         UPnPStart();
    }
    virtual void on_quit()
     {
    
     }
};
static initquit_factory_t<initquit_handler> foo_initquit;


After I get it to launch, I merely need to tell foobar to play, pause stop etc.  Then have foobar send the play progress information back to the UPnP control point.

Please help,

Thank you
Darren

Foobar as a UPnP renderer (player

Reply #1
I would recommend specifically not relying on another application in that manner. Do what you can to pull the appropriate code right in to the foobar2000 component. You're only adding complexity and opportunity for bugs. The more tightly you couple your code to foobar2000, the more of its advanced features you will be able to harness.

What's more, not integrating your component tightly into foobar2000 tends to make users avoid it. I'm currently involved in rewriting foo_edcast because a previous developer did roughly what you're talking about doing.

Foobar as a UPnP renderer (player

Reply #2
I would recommend specifically not relying on another application in that manner. Do what you can to pull the appropriate code right in to the foobar2000 component. You're only adding complexity and opportunity for bugs. The more tightly you couple your code to foobar2000, the more of its advanced features you will be able to harness.

What's more, not integrating your component tightly into foobar2000 tends to make users avoid it. I'm currently involved in rewriting foo_edcast because a previous developer did roughly what you're talking about doing.


That sound like a great idea.  Are you talking about adding the plugin code directly into Foobars functions rather than call it from there?  I would need to have a better understanding of how Foobar is working code wise, before I could do that.  Unless there exists a more detailed reference to Foobar2000's code.  Or samples/examples of well commented code (besides the tutorial which i looked at).  There is very little help or documentation regarding the UPnP code either.

  Until then, If I could get this to at lease run this way and get the rest of it working, it will make it much easier for me to "embed" the UPnP code into Foobars functions as a plugin.

So, how do I start my code (if its possible) when Foobar2000 starts up?  For now.

Thank you

Darren

Foobar as a UPnP renderer (player

Reply #3
Code: [Select]
#include "../SDK/foobar2000.h"
DECLARE_COMPONENT_VERSION("Test", "0.1", NULL);

class initquit_handler : public initquit{
    virtual void on_init(){
         UPnPStart();
    }
    virtual void on_quit(){}
};
static service_factory_single_t<initquit_handler> foo_initquit;
Try this instead.

Foobar as a UPnP renderer (player

Reply #4
Code: [Select]
#include "../SDK/foobar2000.h"
DECLARE_COMPONENT_VERSION("Test", "0.1", NULL);

class initquit_handler : public initquit{
    virtual void on_init(){
         UPnPStart();
    }
    virtual void on_quit(){}
};
static service_factory_single_t<initquit_handler> foo_initquit;
Try this instead.


I just didnt know if that was the proper place to initialize a plugin.

When I try that code (which I have before) I get this when I build it:

"error LNK2001: unresolved external symbol "void __cdecl UPnPStart(void)" (?UPnPStart@@YAXXZ)"

If I comment out the reference to the "myheader.h" i get:

"initfoo.cpp(9) : error C3861: 'UPnPStart': identifier not found"

I realize that the error is supposed to indicate that it cant link with the UPnPStart();
I created a header file with reference to "void UPnPStart(void);    with  #include "myheader.h" at the top of this code.  The reason for this is probably simple and I am rusty regarding VS Express 2008.

What simple stupid thing am i forgetting?

Thank you
Darren

Foobar as a UPnP renderer (player

Reply #5
Code: [Select]
static initquit_factory_t<initquit_handler> foo_initquit;

Was correct, no need to change it.

Quote
"error LNK2001: unresolved external symbol "void __cdecl UPnPStart(void)" (?UPnPStart@@YAXXZ)"

You probably forgot to add some library (.lib) to the additional linker dependencies.

 

Foobar as a UPnP renderer (player

Reply #6
Code: [Select]
static initquit_factory_t<initquit_handler> foo_initquit;

Was correct, no need to change it.

Quote
"error LNK2001: unresolved external symbol "void __cdecl UPnPStart(void)" (?UPnPStart@@YAXXZ)"

You probably forgot to add some library (.lib) to the additional linker dependencies.


If I build the UPnP code the way it is now outside of the Foobar2000 SDK.  It builds (as .exe).  If I change main() to UPnPStart().  Create a new main(), have it run only the UPnPStart(); make a header file to declare the UPnPStart() function, add the #include "myheader.h" to the .cpp with main(); I get the same error.  All this outside of the SDK.  Im just not sure where to look for the problem.  I have tried to manualy debug this on my own, but so far it makes no sense.  The code should build....

I figure that I have probaly forgotten what to do in this case.  It has been 7 years since I wrote any code.

Darren

Foobar as a UPnP renderer (player

Reply #7
You can't just call a function that resides in another DLL EXE. It would also be an extremely bad idea to call a function in on_init() that essentially implements the main event loop of a separate application.

Foobar as a UPnP renderer (player

Reply #8
You can't just call a function that resides in another DLL. It would also be an extremely bad idea to call a function in on_init() that essentially implements the main event loop of a separate application.


What do you mean another dll?

Imagine that I have 8 c files of code that were generated by the Intel UPnP device builder.  I meremly need to have that stack running in the background for foobar (and its real small).  So that, when a command is received by the UPnP stack (such as "play"), UPnP gives the URL of the music file to Foobar and plays it etc.  I've received some advice on how not to do this.  Does anyone have an idea regarding how I CAN get this working.  There have been many threads on many forums (old and new) from pppl wanted a way to have UPnP fuctionality with a PC.  No one seems to want to tackle this issue.  So I thought I would dust off my memory for writing code and give it a try.  There just isnt very much documentation regarding either SDK.  Although I have been able to get the UPnP code to run as an exe and figured out most of the functions involved.  I just need to know a few things about getting this to work with Foobar2000.  Although, I really only need to implement code that will start some sort of player that uses ASIO or KS.

I just need some help to get started.

Thank you

Darren

Foobar as a UPnP renderer (player

Reply #9
You should start a separate thread in on_init(), which will then run the UPnP stack asynchronously. That thread would be waiting on the receiving socket (to handle the commands, if I understood that correctly) as well as some kind of "kill event", which would be signaled in on_quit() to stop it gracefully.
Full-quoting makes you scroll past the same junk over and over.

Foobar as a UPnP renderer (player

Reply #10

You can't just call a function that resides in another DLL. It would also be an extremely bad idea to call a function in on_init() that essentially implements the main event loop of a separate application.


What do you mean another dll?
Sorry, I meant to write EXE, not DLL.

Foobar as a UPnP renderer (player

Reply #11
Apparently I hadnt realized that because some of my project is C and some is C++ there was a conflict in naming.  I found a reference "google" that refers to the following code to correct it:

extern "C"
{
#include "myheader.h"
}

Adding this allows me to compile the code.  If anyone knows of a better approach, please let me know

Quote
You should start a separate thread in on_init(), which will then run the UPnP stack asynchronously. That thread would be waiting on the receiving socket (to handle the commands, if I understood that correctly) as well as some kind of "kill event", which would be signaled in on_quit() to stop it gracefully.


It's been a while since I have written code.  Could you please refresh my memory with an example or be able to help me make a thread?  I would greatly appreciate a sample or something.

Although I can compile the code, it doesn't run the stack when I launch foobar2000

Thank you

Darren

Foobar as a UPnP renderer (player

Reply #12
Oh, and BTW, can someone tell me how i can can step through the plugin so i can debug it?

Thank you
Darren

Foobar as a UPnP renderer (player

Reply #13
I was also wondering if it were possible to run Foobar2000's controls from within the UPnP executable instead of as a plugin to Foobar2000?

Darren

Foobar as a UPnP renderer (player

Reply #14
I'm sorry, I don't have time for more exhaustive reply at the moment, so just briefly.

It's been a while since I have written code.  Could you please refresh my memory with an example or be able to help me make a thread?
_beginthread (C/C++)
CreateThread (Win32)
pfc::thread (fb2k)

Oh, and BTW, can someone tell me how i can can step through the plugin so i can debug it?
Set foobar2000.exe executable as debugged process in MSVC++ project's properties. You can then run it from the IDE and debug it in any way you like. Note it would require changing the output path directly to fb2k's component's directory or adding a post-build step to copy the DLL there.

I was also wondering if it were possible to run Foobar2000's controls from within the UPnP executable instead of as a plugin to Foobar2000?
Perhaps using any inter-process communication you want, or even simply by running various /play, /stop, /next, … commands from the commandline.
Full-quoting makes you scroll past the same junk over and over.

Foobar as a UPnP renderer (player

Reply #15
I can get the UPnP code to compile as dll now.  However, it doesnt get launched when foobar loads.  It shows as a component, but when I use the UPnP tools, it isnt being broadcast as a device. 
  If I need to run my code as a seperate thread (or...?), I have no experience doing this.
  I can play pause etc, foobar2000 as an external program from the UPnP code and that works good.  But, I need to be able to get the track length and the play position to send to the UPnP controller.  Any way to do that?

This would work better as a plugin as I can get to all of Foobars controls within the code.  If I can get past the problem of Foobar2000 not running the UPnP code, I could finish this for testing.

I would appreciate any assistance.

Thank you

Darren

Foobar as a UPnP renderer (player

Reply #16
When the UPnP programs runs on its own, it runs in a console window.  Could this be a problem?  Can I fix that? 

I used _beginthread as a test program for just the .exe of the UPnP code.  I see a window flash and dissapear, but the UPnP functionality is not detected by the UPnP device tester from Intel.

It appears that the UPnP thread just runs and then exits.

Looks like the UPnP code creates its own thread:


Code: [Select]
void main(void) 
{
    
    char *protocolInfo;
    DWORD ptid=0;
    DWORD ptid2=0;
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    //////////////////////////////////////////////////////////////////    

    
    MicroStackChain = ILibCreateChain();
    

    /* TODO: Each device must have a unique device identifier (UDN) */
    
    DMR_microStack = DMR_CreateMicroStack(MicroStackChain,"WadsCo Renderer","87e67194-bd02-4f0b-a619-935ac8fa8522","0000001",1800,0);

    
    DMR_FP_AVTransport_GetCurrentTransportActions=(DMR__ActionHandler_AVTransport_GetCurrentTransportActions)&DMR_AVTransport_GetCurrentTransportActions;
    DMR_FP_AVTransport_GetDeviceCapabilities=(DMR__ActionHandler_AVTransport_GetDeviceCapabilities)&DMR_AVTransport_GetDeviceCapabilities;
    DMR_FP_AVTransport_GetMediaInfo=(DMR__ActionHandler_AVTransport_GetMediaInfo)&DMR_AVTransport_GetMediaInfo;
    DMR_FP_AVTransport_GetPositionInfo=(DMR__ActionHandler_AVTransport_GetPositionInfo)&DMR_AVTransport_GetPositionInfo;
    DMR_FP_AVTransport_GetTransportInfo=(DMR__ActionHandler_AVTransport_GetTransportInfo)&DMR_AVTransport_GetTransportInfo;
    DMR_FP_AVTransport_GetTransportSettings=(DMR__ActionHandler_AVTransport_GetTransportSettings)&DMR_AVTransport_GetTransportSettings;
    DMR_FP_AVTransport_Next=(DMR__ActionHandler_AVTransport_Next)&DMR_AVTransport_Next;
    DMR_FP_AVTransport_Pause=(DMR__ActionHandler_AVTransport_Pause)&DMR_AVTransport_Pause;
    DMR_FP_AVTransport_Play=(DMR__ActionHandler_AVTransport_Play)&DMR_AVTransport_Play;
    DMR_FP_AVTransport_Previous=(DMR__ActionHandler_AVTransport_Previous)&DMR_AVTransport_Previous;
    DMR_FP_AVTransport_Seek=(DMR__ActionHandler_AVTransport_Seek)&DMR_AVTransport_Seek;
    DMR_FP_AVTransport_SetAVTransportURI=(DMR__ActionHandler_AVTransport_SetAVTransportURI)&DMR_AVTransport_SetAVTransportURI;
    DMR_FP_AVTransport_SetPlayMode=(DMR__ActionHandler_AVTransport_SetPlayMode)&DMR_AVTransport_SetPlayMode;
    DMR_FP_AVTransport_Stop=(DMR__ActionHandler_AVTransport_Stop)&DMR_AVTransport_Stop;
    DMR_FP_ConnectionManager_GetCurrentConnectionIDs=(DMR__ActionHandler_ConnectionManager_GetCurrentConnectionIDs)&DMR_ConnectionManager_GetCurrentConnectionIDs;
    DMR_FP_ConnectionManager_GetCurrentConnectionInfo=(DMR__ActionHandler_ConnectionManager_GetCurrentConnectionInfo)&DMR_ConnectionManager_GetCurrentConnectionInfo;
    DMR_FP_ConnectionManager_GetProtocolInfo=(DMR__ActionHandler_ConnectionManager_GetProtocolInfo)&DMR_ConnectionManager_GetProtocolInfo;
    DMR_FP_RenderingControl_GetLoudness=(DMR__ActionHandler_RenderingControl_GetLoudness)&DMR_RenderingControl_GetLoudness;
    DMR_FP_RenderingControl_GetMute=(DMR__ActionHandler_RenderingControl_GetMute)&DMR_RenderingControl_GetMute;
    DMR_FP_RenderingControl_GetVolume=(DMR__ActionHandler_RenderingControl_GetVolume)&DMR_RenderingControl_GetVolume;
    DMR_FP_RenderingControl_SetLoudness=(DMR__ActionHandler_RenderingControl_SetLoudness)&DMR_RenderingControl_SetLoudness;
    DMR_FP_RenderingControl_SetMute=(DMR__ActionHandler_RenderingControl_SetMute)&DMR_RenderingControl_SetMute;
    DMR_FP_RenderingControl_SetVolume=(DMR__ActionHandler_RenderingControl_SetVolume)&DMR_RenderingControl_SetVolume;

    
    /* All evented state variables MUST be initialized before DMR_Start is called. */
    protocolInfo = BuildProtocolInfo(ProtocolInfoList);
/*    DMR_SetState_AVTransport_LastChange(DMR_microStack,"Sample String");
    //DMR_SetState_ConnectionManager_SourceProtocolInfo(DMR_microStack,"Sample String");
    DMR_SetState_ConnectionManager_SourceProtocolInfo(DMR_microStack,protocolInfo);
    //DMR_SetState_ConnectionManager_SinkProtocolInfo(DMR_microStack,"Sample String");
    DMR_SetState_ConnectionManager_SinkProtocolInfo(DMR_microStack,protocolInfo);
    DMR_SetState_ConnectionManager_CurrentConnectionIDs(DMR_microStack,"Sample String");
    DMR_SetState_RenderingControl_LastChange(DMR_microStack,"Sample String");
*/
    DMR_SetState_AVTransport_LastChange(DMR_microStack, "&lt;Event xmlns=\"urn:schemas-upnp-org:metadata-1-0/AVT/\"/ &gt;");
    DMR_SetState_ConnectionManager_SourceProtocolInfo(DMR_microStack,protocolInfo);
    DMR_SetState_ConnectionManager_SinkProtocolInfo(DMR_microStack, protocolInfo);
    DMR_SetState_ConnectionManager_CurrentConnectionIDs(DMR_microStack, "0");
    DMR_SetState_RenderingControl_LastChange(DMR_microStack, "&lt;Event xmlns=\"urn:schemas-upnp-org:metadata-1-0/RCS/\"/ &gt;");

    
    printf("Intel MicroStack 1.0 - WadsCo Renderer,\r\n\r\n");

    
    CreateThread(NULL,0,&Run,NULL,0,&ptid);
        
    
    ILib_IPAddressMonitorTerminator = CreateEvent(NULL,TRUE,FALSE,NULL);
    ILib_IPAddressMonitorThread = CreateThread(NULL,0,&ILib_IPAddressMonitorLoop,NULL,0,&ptid2);
        
    ILibStartChain(MicroStackChain);

//    return 0;

}


Please help.

Darren

Foobar as a UPnP renderer (player

Reply #17
Maybe if you posted an archive with all the relevant source code help would be easier.

Foobar as a UPnP renderer (player

Reply #18
I could do that.  Are you saying just put up a .zip or something on a webspace?
I wasnt sure how much help anyone was willing to give. 

But,
I'm not sure what this thread does:

CreateThread(NULL,0,&Run,NULL,0,&ptid);

But, if I comment it out and use _beginthread in on_init() the UPnP stack runs properly. 

Now, I need tell foobar2000 how to play, pause, stop, seek, etc from within the UPnP code ( which is C)
The upnp code has a seperate function for each of these that is standard naming so that the controller can send the right command.  Essentially, In a function like:

void avtransport_play(token, instance_id)
{
    Code here to tell foobar2000 to play the file (http://... that is sent here by the control point
    Code to tell the controller that the play command was successful.
}

Almost all of the functions for control work like the above.

Can I do that from the UPnP code that is now running in another thread?

If I include the foobar.h header on the upnp.c i get the 100+ errors report.

Darren

Foobar as a UPnP renderer (player

Reply #19
Can I do that from the UPnP code that is now running in another thread?
Yes.
If I include the foobar.h header on the upnp.c i get the 100+ errors report.
Because including C++ code from C file won't work. You will need to convert upnp.c to C++.
Full-quoting makes you scroll past the same junk over and over.

Foobar as a UPnP renderer (player

Reply #20
Can I do that from the UPnP code that is now running in another thread?
Yes.
If I include the foobar.h header on the upnp.c i get the 100+ errors report.
Because including C++ code from C file won't work. You will need to convert upnp.c to C++.


Is there any way to do this automatically.  there are many lines of code spanning 10 C files and about the same number of header files in the project.  I am using this code because the Intel code generator which creates the core of UPNP created them that way.  I would hate to have to convert this whole thing manually.
Isnt there a way to wrap the c code so that VS2008 thinks its c++ and vice versa?

Thank you

Darren

Foobar as a UPnP renderer (player

Reply #21
Why? C code usually compiles fine as C++, unless they use some C++ keywords as normal identifier (e.g. class). Just rename them to .cpp, or force "compile as C++" in Project preferences, or change just one file and link it with the rest of the C code with #includes in extern "C" {} clauses, there are many ways how to do that.
Full-quoting makes you scroll past the same junk over and over.

Foobar as a UPnP renderer (player

Reply #22
I used _beginthread as a test program for just the .exe of the UPnP code.  I see a window flash and dissapear, but the UPnP functionality is not detected by the UPnP device tester from Intel.

It appears that the UPnP thread just runs and then exits.
When you do it like that, the main thread finishes executing the main() function, which causes the whole process to terminate, including the UPnP thread.

Foobar as a UPnP renderer (player

Reply #23
I found the trouble, but having issues resolving it.  If I use an extern "C" wrapper for the appropriate #includes and include the foobar.h it compiles with 104 errors.

The trouble seems to come from 2 includes that are being used by the upnp stack:
#include <winsock2.h>
#include <ws2tcpip.h>

These are neccessary.  But, If i comment those out, the only errors i get are from the now undeclared variables etc that rely on those headers. 

Any ideas how i can get past this?

Thank you
Darren

Foobar as a UPnP renderer (player

Reply #24
I figured out that if I put the includes in a different order (winsock on top) i can compile the code