From 468cb2a90827ee8900657b1dc7492e592f97c3ea Mon Sep 17 00:00:00 2001 From: "Nektarios K. Papadopoulos" Date: Thu, 24 May 2007 10:32:40 +0000 Subject: [PATCH] Create tvcombo sample dir to demonstrate coexistance of device and control point in the same application. Copied and merged sources from tvdevice and tvctrlpt. git-svn-id: https://pupnp.svn.sourceforge.net/svnroot/pupnp/trunk@196 119443c7-1b9e-41f8-b6fc-b9c35fce742c --- upnp/sample/Makefile.am | 14 + .../sample/tvcombo/linux/upnp_tv_combo_main.c | 522 +++++ upnp/sample/tvcombo/upnp_tv_ctrlpt.c | 1409 ++++++++++++ upnp/sample/tvcombo/upnp_tv_ctrlpt.h | 158 ++ upnp/sample/tvcombo/upnp_tv_device.c | 2031 +++++++++++++++++ upnp/sample/tvcombo/upnp_tv_device.h | 638 ++++++ upnp/sample/web/tvcombodesc.xml | 37 + 7 files changed, 4809 insertions(+) create mode 100644 upnp/sample/tvcombo/linux/upnp_tv_combo_main.c create mode 100644 upnp/sample/tvcombo/upnp_tv_ctrlpt.c create mode 100644 upnp/sample/tvcombo/upnp_tv_ctrlpt.h create mode 100644 upnp/sample/tvcombo/upnp_tv_device.c create mode 100644 upnp/sample/tvcombo/upnp_tv_device.h create mode 100644 upnp/sample/web/tvcombodesc.xml diff --git a/upnp/sample/Makefile.am b/upnp/sample/Makefile.am index ed06abd..9f43084 100644 --- a/upnp/sample/Makefile.am +++ b/upnp/sample/Makefile.am @@ -28,6 +28,11 @@ upnp_tv_ctrlpt_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(srcdir)/common/ \ -I$(srcdir)/tvctrlpt +if ENABLE_DEVICE +noinst_PROGRAMS += upnp_tv_combo +upnp_tv_combo_CPPFLAGS = $(AM_CPPFLAGS) \ + -I$(srcdir)/tvcombo +endif endif if ENABLE_DEVICE noinst_PROGRAMS += upnp_tv_device @@ -54,6 +59,15 @@ upnp_tv_ctrlpt_SOURCES = \ tvctrlpt/upnp_tv_ctrlpt.h \ tvctrlpt/linux/upnp_tv_ctrlpt_main.c +upnp_tv_combo_SOURCES = \ + common/sample_util.c \ + common/sample_util.h \ + tvcombo/upnp_tv_ctrlpt.c \ + tvcombo/upnp_tv_ctrlpt.h \ + tvcombo/upnp_tv_device.c \ + tvcombo/upnp_tv_device.h \ + tvcombo/linux/upnp_tv_combo_main.c + if WITH_DOCUMENTATION examplesdir = $(docdir)/examples diff --git a/upnp/sample/tvcombo/linux/upnp_tv_combo_main.c b/upnp/sample/tvcombo/linux/upnp_tv_combo_main.c new file mode 100644 index 0000000..6f68f24 --- /dev/null +++ b/upnp/sample/tvcombo/linux/upnp_tv_combo_main.c @@ -0,0 +1,522 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#include +#include "sample_util.h" +#include "upnp_tv_ctrlpt.h" +#include + +/* + Tags for valid commands issued at the command prompt + */ +enum cmdloop_tvcmds { + PRTHELP = 0, PRTFULLHELP, POWON, POWOFF, + SETCHAN, SETVOL, SETCOL, SETTINT, SETCONT, SETBRT, + CTRLACTION, PICTACTION, CTRLGETVAR, PICTGETVAR, + PRTDEV, LSTDEV, REFRESH, EXITCMD +}; + +/* + Data structure for parsing commands from the command line + */ +struct cmdloop_commands { + char *str; // the string + int cmdnum; // the command + int numargs; // the number of arguments + char *args; // the args +} cmdloop_commands; + +/* + Mappings between command text names, command tag, + and required command arguments for command line + commands + */ +static struct cmdloop_commands cmdloop_cmdlist[] = { + {"Help", PRTHELP, 1, ""}, + {"HelpFull", PRTFULLHELP, 1, ""}, + {"ListDev", LSTDEV, 1, ""}, + {"Refresh", REFRESH, 1, ""}, + {"PrintDev", PRTDEV, 2, ""}, + {"PowerOn", POWON, 2, ""}, + {"PowerOff", POWOFF, 2, ""}, + {"SetChannel", SETCHAN, 3, " "}, + {"SetVolume", SETVOL, 3, " "}, + {"SetColor", SETCOL, 3, " "}, + {"SetTint", SETTINT, 3, " "}, + {"SetContrast", SETCONT, 3, " "}, + {"SetBrightness", SETBRT, 3, " "}, + {"CtrlAction", CTRLACTION, 2, " "}, + {"PictAction", PICTACTION, 2, " "}, + {"CtrlGetVar", CTRLGETVAR, 2, " "}, + {"PictGetVar", PICTGETVAR, 2, " "}, + {"Exit", EXITCMD, 1, ""} +}; + +void +linux_print( const char *string ) +{ + puts( string ); +} + +/******************************************************************************** + * TvCtrlPointPrintHelp + * + * Description: + * Print help info for this application. + ********************************************************************************/ +void +TvCtrlPointPrintShortHelp( void ) +{ + SampleUtil_Print( "Commands:" ); + SampleUtil_Print( " Help" ); + SampleUtil_Print( " HelpFull" ); + SampleUtil_Print( " ListDev" ); + SampleUtil_Print( " Refresh" ); + SampleUtil_Print( " PrintDev " ); + SampleUtil_Print( " PowerOn " ); + SampleUtil_Print( " PowerOff " ); + SampleUtil_Print( " SetChannel " ); + SampleUtil_Print( " SetVolume " ); + SampleUtil_Print( " SetColor " ); + SampleUtil_Print( " SetTint " ); + SampleUtil_Print( " SetContrast " ); + SampleUtil_Print( " SetBrightness " ); + SampleUtil_Print( " CtrlAction " ); + SampleUtil_Print( " PictAction " ); + SampleUtil_Print( " CtrlGetVar " ); + SampleUtil_Print( " PictGetVar " ); + SampleUtil_Print( " Exit" ); +} + +void +TvCtrlPointPrintLongHelp( void ) +{ + SampleUtil_Print( "" ); + SampleUtil_Print( "******************************" ); + SampleUtil_Print( "* TV Control Point Help Info *" ); + SampleUtil_Print( "******************************" ); + SampleUtil_Print( "" ); + SampleUtil_Print + ( "This sample control point application automatically searches" ); + SampleUtil_Print + ( "for and subscribes to the services of television device emulator" ); + SampleUtil_Print + ( "devices. While registers a tv device itself." ); + SampleUtil_Print( "" ); + SampleUtil_Print( "Commands:" ); + SampleUtil_Print( " Help" ); + SampleUtil_Print( " Print this help info." ); + SampleUtil_Print( " ListDev" ); + SampleUtil_Print + ( " Print the current list of TV Device Emulators that this" ); + SampleUtil_Print + ( " control point is aware of. Each device is preceded by a" ); + SampleUtil_Print + ( " device number which corresponds to the devnum argument of" ); + SampleUtil_Print( " commands listed below." ); + SampleUtil_Print( " Refresh" ); + SampleUtil_Print + ( " Delete all of the devices from the device list and issue new" ); + SampleUtil_Print + ( " search request to rebuild the list from scratch." ); + SampleUtil_Print( " PrintDev " ); + SampleUtil_Print + ( " Print the state table for the device ." ); + SampleUtil_Print + ( " e.g., 'PrintDev 1' prints the state table for the first" ); + SampleUtil_Print( " device in the device list." ); + SampleUtil_Print( " PowerOn " ); + SampleUtil_Print + ( " Sends the PowerOn action to the Control Service of" ); + SampleUtil_Print( " device ." ); + SampleUtil_Print( " PowerOff " ); + SampleUtil_Print + ( " Sends the PowerOff action to the Control Service of" ); + SampleUtil_Print( " device ." ); + SampleUtil_Print( " SetChannel " ); + SampleUtil_Print + ( " Sends the SetChannel action to the Control Service of" ); + SampleUtil_Print + ( " device , requesting the channel to be changed" ); + SampleUtil_Print( " to ." ); + SampleUtil_Print( " SetVolume " ); + SampleUtil_Print + ( " Sends the SetVolume action to the Control Service of" ); + SampleUtil_Print + ( " device , requesting the volume to be changed" ); + SampleUtil_Print( " to ." ); + SampleUtil_Print( " SetColor " ); + SampleUtil_Print + ( " Sends the SetColor action to the Control Service of" ); + SampleUtil_Print + ( " device , requesting the color to be changed" ); + SampleUtil_Print( " to ." ); + SampleUtil_Print( " SetTint " ); + SampleUtil_Print + ( " Sends the SetTint action to the Control Service of" ); + SampleUtil_Print + ( " device , requesting the tint to be changed" ); + SampleUtil_Print( " to ." ); + SampleUtil_Print( " SetContrast " ); + SampleUtil_Print + ( " Sends the SetContrast action to the Control Service of" ); + SampleUtil_Print + ( " device , requesting the contrast to be changed" ); + SampleUtil_Print( " to ." ); + SampleUtil_Print( " SetBrightness " ); + SampleUtil_Print + ( " Sends the SetBrightness action to the Control Service of" ); + SampleUtil_Print + ( " device , requesting the brightness to be changed" ); + SampleUtil_Print( " to ." ); + SampleUtil_Print( " CtrlAction " ); + SampleUtil_Print + ( " Sends an action request specified by the string " ); + SampleUtil_Print + ( " to the Control Service of device . This command" ); + SampleUtil_Print + ( " only works for actions that have no arguments." ); + SampleUtil_Print + ( " (e.g., \"CtrlAction 1 IncreaseChannel\")" ); + SampleUtil_Print( " PictAction " ); + SampleUtil_Print + ( " Sends an action request specified by the string " ); + SampleUtil_Print + ( " to the Picture Service of device . This command" ); + SampleUtil_Print + ( " only works for actions that have no arguments." ); + SampleUtil_Print + ( " (e.g., \"PictAction 1 DecreaseContrast\")" ); + SampleUtil_Print( " CtrlGetVar " ); + SampleUtil_Print + ( " Requests the value of a variable specified by the string " ); + SampleUtil_Print + ( " from the Control Service of device ." ); + SampleUtil_Print( " (e.g., \"CtrlGetVar 1 Volume\")" ); + SampleUtil_Print( " PictGetVar " ); + SampleUtil_Print + ( " Requests the value of a variable specified by the string " ); + SampleUtil_Print + ( " from the Picture Service of device ." ); + SampleUtil_Print( " (e.g., \"PictGetVar 1 Tint\")" ); + SampleUtil_Print( " Exit" ); + SampleUtil_Print( " Exits the control point application." ); +} + +/******************************************************************************** + * TvCtrlPointPrintCommands + * + * Description: + * Print the list of valid command line commands to the user + * + * Parameters: + * None + * + ********************************************************************************/ +void +TvCtrlPointPrintCommands( ) +{ + int i; + int numofcmds = sizeof( cmdloop_cmdlist ) / sizeof( cmdloop_commands ); + + SampleUtil_Print( "Valid Commands:" ); + for( i = 0; i < numofcmds; i++ ) { + SampleUtil_Print( " %-14s %s", cmdloop_cmdlist[i].str, + cmdloop_cmdlist[i].args ); + } + SampleUtil_Print( "" ); +} + +/******************************************************************************** + * TvCtrlPointCommandLoop + * + * Description: + * Function that receives commands from the user at the command prompt + * during the lifetime of the control point, and calls the appropriate + * functions for those commands. + * + * Parameters: + * None + * + ********************************************************************************/ +void * +TvCtrlPointCommandLoop( void *args ) +{ + char cmdline[100]; + + while( 1 ) { + SampleUtil_Print( "\n>> " ); + fgets( cmdline, 100, stdin ); + TvCtrlPointProcessCommand( cmdline ); + } + + return NULL; +} + +int +TvCtrlPointProcessCommand( char *cmdline ) +{ + char cmd[100]; + char strarg[100]; + int arg_val_err = -99999; + int arg1 = arg_val_err; + int arg2 = arg_val_err; + int cmdnum = -1; + int numofcmds = sizeof( cmdloop_cmdlist ) / sizeof( cmdloop_commands ); + int cmdfound = 0; + int i, + rc; + int invalidargs = 0; + int validargs; + + validargs = sscanf( cmdline, "%s %d %d", cmd, &arg1, &arg2 ); + + for( i = 0; i < numofcmds; i++ ) { + if( strcasecmp( cmd, cmdloop_cmdlist[i].str ) == 0 ) { + cmdnum = cmdloop_cmdlist[i].cmdnum; + cmdfound++; + if( validargs != cmdloop_cmdlist[i].numargs ) + invalidargs++; + break; + } + } + + if( !cmdfound ) { + SampleUtil_Print( "Command not found; try 'Help'" ); + return TV_SUCCESS; + } + + if( invalidargs ) { + SampleUtil_Print( "Invalid arguments; try 'Help'" ); + return TV_SUCCESS; + } + + switch ( cmdnum ) { + case PRTHELP: + TvCtrlPointPrintShortHelp( ); + break; + + case PRTFULLHELP: + TvCtrlPointPrintLongHelp( ); + break; + + case POWON: + TvCtrlPointSendPowerOn( arg1 ); + break; + + case POWOFF: + TvCtrlPointSendPowerOff( arg1 ); + break; + + case SETCHAN: + TvCtrlPointSendSetChannel( arg1, arg2 ); + break; + + case SETVOL: + TvCtrlPointSendSetVolume( arg1, arg2 ); + break; + + case SETCOL: + TvCtrlPointSendSetColor( arg1, arg2 ); + break; + + case SETTINT: + TvCtrlPointSendSetTint( arg1, arg2 ); + break; + + case SETCONT: + TvCtrlPointSendSetContrast( arg1, arg2 ); + break; + + case SETBRT: + TvCtrlPointSendSetBrightness( arg1, arg2 ); + break; + + case CTRLACTION: + /* + re-parse commandline since second arg is string + */ + validargs = sscanf( cmdline, "%s %d %s", cmd, &arg1, strarg ); + if( 3 == validargs ) + TvCtrlPointSendAction( TV_SERVICE_CONTROL, arg1, strarg, + NULL, NULL, 0 ); + else + invalidargs++; + break; + + case PICTACTION: + /* + re-parse commandline since second arg is string + */ + validargs = sscanf( cmdline, "%s %d %s", cmd, &arg1, strarg ); + if( 3 == validargs ) + TvCtrlPointSendAction( TV_SERVICE_PICTURE, arg1, strarg, + NULL, NULL, 0 ); + else + invalidargs++; + break; + + case CTRLGETVAR: + /* + re-parse commandline since second arg is string + */ + validargs = sscanf( cmdline, "%s %d %s", cmd, &arg1, strarg ); + if( 3 == validargs ) + TvCtrlPointGetVar( TV_SERVICE_CONTROL, arg1, strarg ); + else + invalidargs++; + break; + + case PICTGETVAR: + /* + re-parse commandline since second arg is string + */ + validargs = sscanf( cmdline, "%s %d %s", cmd, &arg1, strarg ); + if( 3 == validargs ) + TvCtrlPointGetVar( TV_SERVICE_PICTURE, arg1, strarg ); + else + invalidargs++; + break; + + case PRTDEV: + TvCtrlPointPrintDevice( arg1 ); + break; + + case LSTDEV: + TvCtrlPointPrintList( ); + break; + + case REFRESH: + TvCtrlPointRefresh( ); + break; + + case EXITCMD: + rc = TvCtrlPointStop( ); + exit( rc ); + break; + + default: + SampleUtil_Print( "Command not implemented; see 'Help'" ); + break; + } + + if( invalidargs ) + SampleUtil_Print( "Invalid args in command; see 'Help'" ); + + return TV_SUCCESS; +} + +int +device_main( int argc, + char **argv ) +{ + + unsigned int portTemp = 0; + char *ip_address = NULL, + *desc_doc_name = NULL, + *web_dir_path = NULL; + unsigned int port = 0; + + int i = 0; + + SampleUtil_Initialize( linux_print ); + + //Parse options + for( i = 1; i < argc; i++ ) { + if( strcmp( argv[i], "-ip" ) == 0 ) { + ip_address = argv[++i]; + } else if( strcmp( argv[i], "-port" ) == 0 ) { + sscanf( argv[++i], "%u", &portTemp ); + } else if( strcmp( argv[i], "-desc" ) == 0 ) { + desc_doc_name = argv[++i]; + } else if( strcmp( argv[i], "-webdir" ) == 0 ) { + web_dir_path = argv[++i]; + } else if( strcmp( argv[i], "-help" ) == 0 ) { + SampleUtil_Print( "Usage: %s -ip ipaddress -port port" + " -desc desc_doc_name -webdir web_dir_path" + " -help (this message)\n", argv[0] ); + SampleUtil_Print( "\tipaddress: IP address of the device" + " (must match desc. doc)\n" ); + SampleUtil_Print( "\t\te.g.: 192.168.0.4\n" ); + SampleUtil_Print( "\tport: Port number to use for " + "receiving UPnP messages (must match desc. doc)\n" ); + SampleUtil_Print( "\t\te.g.: 5431\n" ); + SampleUtil_Print + ( "\tdesc_doc_name: name of device description document\n" ); + SampleUtil_Print( "\t\te.g.: tvcombodesc.xml\n" ); + SampleUtil_Print + ( "\tweb_dir_path: Filesystem path where web files " + "related to the device are stored\n" ); + SampleUtil_Print( "\t\te.g.: /upnp/sample/web\n" ); + exit( 1 ); + } + } + + port = ( unsigned short )portTemp; + + TvDeviceStart( ip_address, port, desc_doc_name, web_dir_path, + linux_print ); + +} + +int +main( int argc, + char **argv ) +{ + int rc; + ithread_t cmdloop_thread; + int sig; + sigset_t sigs_to_catch; + int code; + + device_main(argc, argv); + rc = TvCtrlPointStart( linux_print, NULL ); + if( rc != TV_SUCCESS ) { + SampleUtil_Print( "Error starting UPnP TV Control Point" ); + exit( rc ); + } + // start a command loop thread + code = + ithread_create( &cmdloop_thread, NULL, TvCtrlPointCommandLoop, + NULL ); + + /* + Catch Ctrl-C and properly shutdown + */ + sigemptyset( &sigs_to_catch ); + sigaddset( &sigs_to_catch, SIGINT ); + sigwait( &sigs_to_catch, &sig ); + + SampleUtil_Print( "Shutting down on signal %d...", sig ); + TvDeviceStop( ); + rc = TvCtrlPointStop( ); + exit( rc ); +} diff --git a/upnp/sample/tvcombo/upnp_tv_ctrlpt.c b/upnp/sample/tvcombo/upnp_tv_ctrlpt.c new file mode 100644 index 0000000..45ceee5 --- /dev/null +++ b/upnp/sample/tvcombo/upnp_tv_ctrlpt.c @@ -0,0 +1,1409 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#include "upnp_tv_ctrlpt.h" + +/* + Mutex for protecting the global device list + in a multi-threaded, asynchronous environment. + All functions should lock this mutex before reading + or writing the device list. + */ +ithread_mutex_t DeviceListMutex; + +UpnpClient_Handle ctrlpt_handle = -1; + +char TvDeviceType[] = "urn:schemas-upnp-org:device:tvdevice:1"; +char *TvServiceType[] = { + "urn:schemas-upnp-org:service:tvcontrol:1", + "urn:schemas-upnp-org:service:tvpicture:1" +}; +char *TvServiceName[] = { "Control", "Picture" }; + +/* + Global arrays for storing variable names and counts for + TvControl and TvPicture services + */ +char *TvVarName[TV_SERVICE_SERVCOUNT][TV_MAXVARS] = { + {"Power", "Channel", "Volume", ""}, + {"Color", "Tint", "Contrast", "Brightness"} +}; +char TvVarCount[TV_SERVICE_SERVCOUNT] = + { TV_CONTROL_VARCOUNT, TV_PICTURE_VARCOUNT }; + +/* + Timeout to request during subscriptions + */ +int default_timeout = 1801; + +/* + The first node in the global device list, or NULL if empty + */ +struct TvDeviceNode *GlobalDeviceList = NULL; + +/******************************************************************************** + * TvCtrlPointDeleteNode + * + * Description: + * Delete a device node from the global device list. Note that this + * function is NOT thread safe, and should be called from another + * function that has already locked the global device list. + * + * Parameters: + * node -- The device node + * + ********************************************************************************/ +int +TvCtrlPointDeleteNode( struct TvDeviceNode *node ) +{ + int rc, + service, + var; + + if( NULL == node ) { + SampleUtil_Print( "ERROR: TvCtrlPointDeleteNode: Node is empty" ); + return TV_ERROR; + } + + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + /* + If we have a valid control SID, then unsubscribe + */ + if( strcmp( node->device.TvService[service].SID, "" ) != 0 ) { + rc = UpnpUnSubscribe( ctrlpt_handle, + node->device.TvService[service].SID ); + if( UPNP_E_SUCCESS == rc ) { + SampleUtil_Print + ( "Unsubscribed from Tv %s EventURL with SID=%s", + TvServiceName[service], + node->device.TvService[service].SID ); + } else { + SampleUtil_Print + ( "Error unsubscribing to Tv %s EventURL -- %d", + TvServiceName[service], rc ); + } + } + + for( var = 0; var < TvVarCount[service]; var++ ) { + if( node->device.TvService[service].VariableStrVal[var] ) { + free( node->device.TvService[service]. + VariableStrVal[var] ); + } + } + } + + //Notify New Device Added + SampleUtil_StateUpdate( NULL, NULL, node->device.UDN, DEVICE_REMOVED ); + free( node ); + node = NULL; + + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointRemoveDevice + * + * Description: + * Remove a device from the global device list. + * + * Parameters: + * UDN -- The Unique Device Name for the device to remove + * + ********************************************************************************/ +int +TvCtrlPointRemoveDevice( char *UDN ) +{ + struct TvDeviceNode *curdevnode, + *prevdevnode; + + ithread_mutex_lock( &DeviceListMutex ); + + curdevnode = GlobalDeviceList; + if( !curdevnode ) { + SampleUtil_Print + ( "WARNING: TvCtrlPointRemoveDevice: Device list empty" ); + } else { + if( 0 == strcmp( curdevnode->device.UDN, UDN ) ) { + GlobalDeviceList = curdevnode->next; + TvCtrlPointDeleteNode( curdevnode ); + } else { + prevdevnode = curdevnode; + curdevnode = curdevnode->next; + + while( curdevnode ) { + if( strcmp( curdevnode->device.UDN, UDN ) == 0 ) { + prevdevnode->next = curdevnode->next; + TvCtrlPointDeleteNode( curdevnode ); + break; + } + + prevdevnode = curdevnode; + curdevnode = curdevnode->next; + } + } + } + + ithread_mutex_unlock( &DeviceListMutex ); + + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointRemoveAll + * + * Description: + * Remove all devices from the global device list. + * + * Parameters: + * None + * + ********************************************************************************/ +int +TvCtrlPointRemoveAll( void ) +{ + struct TvDeviceNode *curdevnode, + *next; + + ithread_mutex_lock( &DeviceListMutex ); + + curdevnode = GlobalDeviceList; + GlobalDeviceList = NULL; + + while( curdevnode ) { + next = curdevnode->next; + TvCtrlPointDeleteNode( curdevnode ); + curdevnode = next; + } + + ithread_mutex_unlock( &DeviceListMutex ); + + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointRefresh + * + * Description: + * Clear the current global device list and issue new search + * requests to build it up again from scratch. + * + * Parameters: + * None + * + ********************************************************************************/ +int +TvCtrlPointRefresh( void ) +{ + int rc; + + TvCtrlPointRemoveAll( ); + + /* + Search for all devices of type tvdevice version 1, + waiting for up to 5 seconds for the response + */ + rc = UpnpSearchAsync( ctrlpt_handle, 5, TvDeviceType, NULL ); + if( UPNP_E_SUCCESS != rc ) { + SampleUtil_Print( "Error sending search request%d", rc ); + return TV_ERROR; + } + + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointGetVar + * + * Description: + * Send a GetVar request to the specified service of a device. + * + * Parameters: + * service -- The service + * devnum -- The number of the device (order in the list, + * starting with 1) + * varname -- The name of the variable to request. + * + ********************************************************************************/ +int +TvCtrlPointGetVar( int service, + int devnum, + char *varname ) +{ + struct TvDeviceNode *devnode; + int rc; + + ithread_mutex_lock( &DeviceListMutex ); + + rc = TvCtrlPointGetDevice( devnum, &devnode ); + + if( TV_SUCCESS == rc ) { + rc = UpnpGetServiceVarStatusAsync( ctrlpt_handle, + devnode->device. + TvService[service].ControlURL, + varname, + TvCtrlPointCallbackEventHandler, + NULL ); + if( rc != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error in UpnpGetServiceVarStatusAsync -- %d", rc ); + rc = TV_ERROR; + } + } + + ithread_mutex_unlock( &DeviceListMutex ); + + return rc; +} + +int +TvCtrlPointGetPower( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_CONTROL, devnum, "Power" ); +} + +int +TvCtrlPointGetChannel( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_CONTROL, devnum, "Channel" ); +} + +int +TvCtrlPointGetVolume( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_CONTROL, devnum, "Volume" ); +} + +int +TvCtrlPointGetColor( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_PICTURE, devnum, "Color" ); +} + +int +TvCtrlPointGetTint( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_PICTURE, devnum, "Tint" ); +} + +int +TvCtrlPointGetContrast( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_PICTURE, devnum, "Contrast" ); +} + +int +TvCtrlPointGetBrightness( int devnum ) +{ + return TvCtrlPointGetVar( TV_SERVICE_PICTURE, devnum, "Brightness" ); +} + +/******************************************************************************** + * TvCtrlPointSendAction + * + * Description: + * Send an Action request to the specified service of a device. + * + * Parameters: + * service -- The service + * devnum -- The number of the device (order in the list, + * starting with 1) + * actionname -- The name of the action. + * param_name -- An array of parameter names + * param_val -- The corresponding parameter values + * param_count -- The number of parameters + * + ********************************************************************************/ +int +TvCtrlPointSendAction( int service, + int devnum, + char *actionname, + char **param_name, + char **param_val, + int param_count ) +{ + struct TvDeviceNode *devnode; + IXML_Document *actionNode = NULL; + int rc = TV_SUCCESS; + int param; + + ithread_mutex_lock( &DeviceListMutex ); + + rc = TvCtrlPointGetDevice( devnum, &devnode ); + if( TV_SUCCESS == rc ) { + if( 0 == param_count ) { + actionNode = + UpnpMakeAction( actionname, TvServiceType[service], 0, + NULL ); + } else { + for( param = 0; param < param_count; param++ ) { + if( UpnpAddToAction + ( &actionNode, actionname, TvServiceType[service], + param_name[param], + param_val[param] ) != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "ERROR: TvCtrlPointSendAction: Trying to add action param" ); + //return -1; // TBD - BAD! leaves mutex locked + } + } + } + + rc = UpnpSendActionAsync( ctrlpt_handle, + devnode->device.TvService[service]. + ControlURL, TvServiceType[service], + NULL, actionNode, + TvCtrlPointCallbackEventHandler, NULL ); + + if( rc != UPNP_E_SUCCESS ) { + SampleUtil_Print( "Error in UpnpSendActionAsync -- %d", rc ); + rc = TV_ERROR; + } + } + + ithread_mutex_unlock( &DeviceListMutex ); + + if( actionNode ) + ixmlDocument_free( actionNode ); + + return rc; +} + +/******************************************************************************** + * TvCtrlPointSendActionNumericArg + * + * Description:Send an action with one argument to a device in the global device list. + * + * Parameters: + * devnum -- The number of the device (order in the list, starting with 1) + * service -- TV_SERVICE_CONTROL or TV_SERVICE_PICTURE + * actionName -- The device action, i.e., "SetChannel" + * paramName -- The name of the parameter that is being passed + * paramValue -- Actual value of the parameter being passed + * + ********************************************************************************/ +int +TvCtrlPointSendActionNumericArg( int devnum, + int service, + char *actionName, + char *paramName, + int paramValue ) +{ + char param_val_a[50]; + char *param_val = param_val_a; + + sprintf( param_val_a, "%d", paramValue ); + + return TvCtrlPointSendAction( service, devnum, actionName, ¶mName, + ¶m_val, 1 ); +} + +int +TvCtrlPointSendPowerOn( int devnum ) +{ + return TvCtrlPointSendAction( TV_SERVICE_CONTROL, devnum, "PowerOn", + NULL, NULL, 0 ); +} + +int +TvCtrlPointSendPowerOff( int devnum ) +{ + return TvCtrlPointSendAction( TV_SERVICE_CONTROL, devnum, "PowerOff", + NULL, NULL, 0 ); +} + +int +TvCtrlPointSendSetChannel( int devnum, + int channel ) +{ + return TvCtrlPointSendActionNumericArg( devnum, TV_SERVICE_CONTROL, + "SetChannel", "Channel", + channel ); +} + +int +TvCtrlPointSendSetVolume( int devnum, + int volume ) +{ + return TvCtrlPointSendActionNumericArg( devnum, TV_SERVICE_CONTROL, + "SetVolume", "Volume", + volume ); +} + +int +TvCtrlPointSendSetColor( int devnum, + int color ) +{ + return TvCtrlPointSendActionNumericArg( devnum, TV_SERVICE_PICTURE, + "SetColor", "Color", color ); +} + +int +TvCtrlPointSendSetTint( int devnum, + int tint ) +{ + return TvCtrlPointSendActionNumericArg( devnum, TV_SERVICE_PICTURE, + "SetTint", "Tint", tint ); +} + +int +TvCtrlPointSendSetContrast( int devnum, + int contrast ) +{ + return TvCtrlPointSendActionNumericArg( devnum, TV_SERVICE_PICTURE, + "SetContrast", "Contrast", + contrast ); +} + +int +TvCtrlPointSendSetBrightness( int devnum, + int brightness ) +{ + return TvCtrlPointSendActionNumericArg( devnum, TV_SERVICE_PICTURE, + "SetBrightness", "Brightness", + brightness ); +} + +/******************************************************************************** + * TvCtrlPointGetDevice + * + * Description: + * Given a list number, returns the pointer to the device + * node at that position in the global device list. Note + * that this function is not thread safe. It must be called + * from a function that has locked the global device list. + * + * Parameters: + * devnum -- The number of the device (order in the list, + * starting with 1) + * devnode -- The output device node pointer + * + ********************************************************************************/ +int +TvCtrlPointGetDevice( int devnum, + struct TvDeviceNode **devnode ) +{ + int count = devnum; + struct TvDeviceNode *tmpdevnode = NULL; + + if( count ) + tmpdevnode = GlobalDeviceList; + + while( --count && tmpdevnode ) { + tmpdevnode = tmpdevnode->next; + } + + if( !tmpdevnode ) { + SampleUtil_Print( "Error finding TvDevice number -- %d", devnum ); + return TV_ERROR; + } + + *devnode = tmpdevnode; + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointPrintList + * + * Description: + * Print the universal device names for each device in the global device list + * + * Parameters: + * None + * + ********************************************************************************/ +int +TvCtrlPointPrintList( ) +{ + struct TvDeviceNode *tmpdevnode; + int i = 0; + + ithread_mutex_lock( &DeviceListMutex ); + + SampleUtil_Print( "TvCtrlPointPrintList:" ); + tmpdevnode = GlobalDeviceList; + while( tmpdevnode ) { + SampleUtil_Print( " %3d -- %s", ++i, tmpdevnode->device.UDN ); + tmpdevnode = tmpdevnode->next; + } + SampleUtil_Print( "" ); + ithread_mutex_unlock( &DeviceListMutex ); + + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointPrintDevice + * + * Description: + * Print the identifiers and state table for a device from + * the global device list. + * + * Parameters: + * devnum -- The number of the device (order in the list, + * starting with 1) + * + ********************************************************************************/ +int +TvCtrlPointPrintDevice( int devnum ) +{ + struct TvDeviceNode *tmpdevnode; + int i = 0, + service, + var; + char spacer[15]; + + if( devnum <= 0 ) { + SampleUtil_Print + ( "Error in TvCtrlPointPrintDevice: invalid devnum = %d", + devnum ); + return TV_ERROR; + } + + ithread_mutex_lock( &DeviceListMutex ); + + SampleUtil_Print( "TvCtrlPointPrintDevice:" ); + tmpdevnode = GlobalDeviceList; + while( tmpdevnode ) { + i++; + if( i == devnum ) + break; + tmpdevnode = tmpdevnode->next; + } + + if( !tmpdevnode ) { + SampleUtil_Print + ( "Error in TvCtrlPointPrintDevice: invalid devnum = %d -- actual device count = %d", + devnum, i ); + } else { + SampleUtil_Print( " TvDevice -- %d", devnum ); + SampleUtil_Print( " | " ); + SampleUtil_Print( " +- UDN = %s", + tmpdevnode->device.UDN ); + SampleUtil_Print( " +- DescDocURL = %s", + tmpdevnode->device.DescDocURL ); + SampleUtil_Print( " +- FriendlyName = %s", + tmpdevnode->device.FriendlyName ); + SampleUtil_Print( " +- PresURL = %s", + tmpdevnode->device.PresURL ); + SampleUtil_Print( " +- Adver. TimeOut = %d", + tmpdevnode->device.AdvrTimeOut ); + + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + if( service < TV_SERVICE_SERVCOUNT - 1 ) + sprintf( spacer, " | " ); + else + sprintf( spacer, " " ); + SampleUtil_Print( " | " ); + SampleUtil_Print( " +- Tv %s Service", + TvServiceName[service] ); + SampleUtil_Print( "%s+- ServiceId = %s", spacer, + tmpdevnode->device.TvService[service]. + ServiceId ); + SampleUtil_Print( "%s+- ServiceType = %s", spacer, + tmpdevnode->device.TvService[service]. + ServiceType ); + SampleUtil_Print( "%s+- EventURL = %s", spacer, + tmpdevnode->device.TvService[service]. + EventURL ); + SampleUtil_Print( "%s+- ControlURL = %s", spacer, + tmpdevnode->device.TvService[service]. + ControlURL ); + SampleUtil_Print( "%s+- SID = %s", spacer, + tmpdevnode->device.TvService[service].SID ); + SampleUtil_Print( "%s+- ServiceStateTable", spacer ); + + for( var = 0; var < TvVarCount[service]; var++ ) { + SampleUtil_Print( "%s +- %-10s = %s", spacer, + TvVarName[service][var], + tmpdevnode->device.TvService[service]. + VariableStrVal[var] ); + } + } + } + + SampleUtil_Print( "" ); + ithread_mutex_unlock( &DeviceListMutex ); + + return TV_SUCCESS; +} + +/******************************************************************************** + * TvCtrlPointAddDevice + * + * Description: + * If the device is not already included in the global device list, + * add it. Otherwise, update its advertisement expiration timeout. + * + * Parameters: + * DescDoc -- The description document for the device + * location -- The location of the description document URL + * expires -- The expiration time for this advertisement + * + ********************************************************************************/ +void +TvCtrlPointAddDevice( IXML_Document * DescDoc, + char *location, + int expires ) +{ + char *deviceType = NULL; + char *friendlyName = NULL; + char presURL[200]; + char *baseURL = NULL; + char *relURL = NULL; + char *UDN = NULL; + char *serviceId[TV_SERVICE_SERVCOUNT] = { NULL, NULL }; + char *eventURL[TV_SERVICE_SERVCOUNT] = { NULL, NULL }; + char *controlURL[TV_SERVICE_SERVCOUNT] = { NULL, NULL }; + Upnp_SID eventSID[TV_SERVICE_SERVCOUNT]; + int TimeOut[TV_SERVICE_SERVCOUNT] = + { default_timeout, default_timeout }; + struct TvDeviceNode *deviceNode; + struct TvDeviceNode *tmpdevnode; + int ret = 1; + int found = 0; + int service, + var; + + ithread_mutex_lock( &DeviceListMutex ); + + /* + Read key elements from description document + */ + UDN = SampleUtil_GetFirstDocumentItem( DescDoc, "UDN" ); + deviceType = SampleUtil_GetFirstDocumentItem( DescDoc, "deviceType" ); + friendlyName = + SampleUtil_GetFirstDocumentItem( DescDoc, "friendlyName" ); + baseURL = SampleUtil_GetFirstDocumentItem( DescDoc, "URLBase" ); + relURL = SampleUtil_GetFirstDocumentItem( DescDoc, "presentationURL" ); + + ret = + UpnpResolveURL( ( baseURL ? baseURL : location ), relURL, + presURL ); + + if( UPNP_E_SUCCESS != ret ) + SampleUtil_Print( "Error generating presURL from %s + %s", baseURL, + relURL ); + + if( strcmp( deviceType, TvDeviceType ) == 0 ) { + SampleUtil_Print( "Found Tv device" ); + + // Check if this device is already in the list + tmpdevnode = GlobalDeviceList; + while( tmpdevnode ) { + if( strcmp( tmpdevnode->device.UDN, UDN ) == 0 ) { + found = 1; + break; + } + tmpdevnode = tmpdevnode->next; + } + + if( found ) { + // The device is already there, so just update + // the advertisement timeout field + tmpdevnode->device.AdvrTimeOut = expires; + } else { + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + if( SampleUtil_FindAndParseService + ( DescDoc, location, TvServiceType[service], + &serviceId[service], &eventURL[service], + &controlURL[service] ) ) { + SampleUtil_Print( "Subscribing to EventURL %s...", + eventURL[service] ); + + ret = + UpnpSubscribe( ctrlpt_handle, eventURL[service], + &TimeOut[service], + eventSID[service] ); + + if( ret == UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Subscribed to EventURL with SID=%s", + eventSID[service] ); + } else { + SampleUtil_Print + ( "Error Subscribing to EventURL -- %d", ret ); + strcpy( eventSID[service], "" ); + } + } else { + SampleUtil_Print( "Error: Could not find Service: %s", + TvServiceType[service] ); + } + } + + /* + Create a new device node + */ + deviceNode = + ( struct TvDeviceNode * ) + malloc( sizeof( struct TvDeviceNode ) ); + strcpy( deviceNode->device.UDN, UDN ); + strcpy( deviceNode->device.DescDocURL, location ); + strcpy( deviceNode->device.FriendlyName, friendlyName ); + strcpy( deviceNode->device.PresURL, presURL ); + deviceNode->device.AdvrTimeOut = expires; + + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + strcpy( deviceNode->device.TvService[service].ServiceId, + serviceId[service] ); + strcpy( deviceNode->device.TvService[service].ServiceType, + TvServiceType[service] ); + strcpy( deviceNode->device.TvService[service].ControlURL, + controlURL[service] ); + strcpy( deviceNode->device.TvService[service].EventURL, + eventURL[service] ); + strcpy( deviceNode->device.TvService[service].SID, + eventSID[service] ); + + for( var = 0; var < TvVarCount[service]; var++ ) { + deviceNode->device.TvService[service]. + VariableStrVal[var] = + ( char * )malloc( TV_MAX_VAL_LEN ); + strcpy( deviceNode->device.TvService[service]. + VariableStrVal[var], "" ); + } + } + + deviceNode->next = NULL; + + // Insert the new device node in the list + if( ( tmpdevnode = GlobalDeviceList ) ) { + + while( tmpdevnode ) { + if( tmpdevnode->next ) { + tmpdevnode = tmpdevnode->next; + } else { + tmpdevnode->next = deviceNode; + break; + } + } + } else { + GlobalDeviceList = deviceNode; + } + + //Notify New Device Added + SampleUtil_StateUpdate( NULL, NULL, deviceNode->device.UDN, + DEVICE_ADDED ); + } + } + + ithread_mutex_unlock( &DeviceListMutex ); + + if( deviceType ) + free( deviceType ); + if( friendlyName ) + free( friendlyName ); + if( UDN ) + free( UDN ); + if( baseURL ) + free( baseURL ); + if( relURL ) + free( relURL ); + + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + if( serviceId[service] ) + free( serviceId[service] ); + if( controlURL[service] ) + free( controlURL[service] ); + if( eventURL[service] ) + free( eventURL[service] ); + } +} + +/******************************************************************************** + * TvStateUpdate + * + * Description: + * Update a Tv state table. Called when an event is + * received. Note: this function is NOT thread save. It must be + * called from another function that has locked the global device list. + * + * Parameters: + * UDN -- The UDN of the parent device. + * Service -- The service state table to update + * ChangedVariables -- DOM document representing the XML received + * with the event + * State -- pointer to the state table for the Tv service + * to update + * + ********************************************************************************/ +void +TvStateUpdate( char *UDN, + int Service, + IXML_Document * ChangedVariables, + char **State ) +{ + IXML_NodeList *properties, + *variables; + IXML_Element *property, + *variable; + int length, + length1; + int i, + j; + char *tmpstate = NULL; + + SampleUtil_Print( "Tv State Update (service %d): ", Service ); + + /* + Find all of the e:property tags in the document + */ + properties = + ixmlDocument_getElementsByTagName( ChangedVariables, + "e:property" ); + if( NULL != properties ) { + length = ixmlNodeList_length( properties ); + for( i = 0; i < length; i++ ) { /* Loop through each property change found */ + property = + ( IXML_Element * ) ixmlNodeList_item( properties, i ); + + /* + For each variable name in the state table, check if this + is a corresponding property change + */ + for( j = 0; j < TvVarCount[Service]; j++ ) { + variables = + ixmlElement_getElementsByTagName( property, + TvVarName[Service] + [j] ); + + /* + If a match is found, extract the value, and update the state table + */ + if( variables ) { + length1 = ixmlNodeList_length( variables ); + if( length1 ) { + variable = + ( IXML_Element * ) + ixmlNodeList_item( variables, 0 ); + tmpstate = SampleUtil_GetElementValue( variable ); + + if( tmpstate ) { + strcpy( State[j], tmpstate ); + SampleUtil_Print + ( " Variable Name: %s New Value:'%s'", + TvVarName[Service][j], State[j] ); + } + + if( tmpstate ) + free( tmpstate ); + tmpstate = NULL; + } + + ixmlNodeList_free( variables ); + variables = NULL; + } + } + + } + ixmlNodeList_free( properties ); + } +} + +/******************************************************************************** + * TvCtrlPointHandleEvent + * + * Description: + * Handle a UPnP event that was received. Process the event and update + * the appropriate service state table. + * + * Parameters: + * sid -- The subscription id for the event + * eventkey -- The eventkey number for the event + * changes -- The DOM document representing the changes + * + ********************************************************************************/ +void +TvCtrlPointHandleEvent( Upnp_SID sid, + int evntkey, + IXML_Document * changes ) +{ + struct TvDeviceNode *tmpdevnode; + int service; + + ithread_mutex_lock( &DeviceListMutex ); + + tmpdevnode = GlobalDeviceList; + while( tmpdevnode ) { + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + if( strcmp( tmpdevnode->device.TvService[service].SID, sid ) == + 0 ) { + SampleUtil_Print( "Received Tv %s Event: %d for SID %s", + TvServiceName[service], evntkey, sid ); + + TvStateUpdate( tmpdevnode->device.UDN, service, changes, + ( char ** )&tmpdevnode->device. + TvService[service].VariableStrVal ); + break; + } + } + tmpdevnode = tmpdevnode->next; + } + + ithread_mutex_unlock( &DeviceListMutex ); +} + +/******************************************************************************** + * TvCtrlPointHandleSubscribeUpdate + * + * Description: + * Handle a UPnP subscription update that was received. Find the + * service the update belongs to, and update its subscription + * timeout. + * + * Parameters: + * eventURL -- The event URL for the subscription + * sid -- The subscription id for the subscription + * timeout -- The new timeout for the subscription + * + ********************************************************************************/ +void +TvCtrlPointHandleSubscribeUpdate( char *eventURL, + Upnp_SID sid, + int timeout ) +{ + struct TvDeviceNode *tmpdevnode; + int service; + + ithread_mutex_lock( &DeviceListMutex ); + + tmpdevnode = GlobalDeviceList; + while( tmpdevnode ) { + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + + if( strcmp + ( tmpdevnode->device.TvService[service].EventURL, + eventURL ) == 0 ) { + SampleUtil_Print + ( "Received Tv %s Event Renewal for eventURL %s", + TvServiceName[service], eventURL ); + strcpy( tmpdevnode->device.TvService[service].SID, sid ); + break; + } + } + + tmpdevnode = tmpdevnode->next; + } + + ithread_mutex_unlock( &DeviceListMutex ); +} + +void +TvCtrlPointHandleGetVar( char *controlURL, + char *varName, + DOMString varValue ) +{ + + struct TvDeviceNode *tmpdevnode; + int service; + + ithread_mutex_lock( &DeviceListMutex ); + + tmpdevnode = GlobalDeviceList; + while( tmpdevnode ) { + for( service = 0; service < TV_SERVICE_SERVCOUNT; service++ ) { + if( strcmp + ( tmpdevnode->device.TvService[service].ControlURL, + controlURL ) == 0 ) { + SampleUtil_StateUpdate( varName, varValue, + tmpdevnode->device.UDN, + GET_VAR_COMPLETE ); + break; + } + } + tmpdevnode = tmpdevnode->next; + } + + ithread_mutex_unlock( &DeviceListMutex ); +} + +/******************************************************************************** + * TvCtrlPointCallbackEventHandler + * + * Description: + * The callback handler registered with the SDK while registering + * the control point. Detects the type of callback, and passes the + * request on to the appropriate function. + * + * Parameters: + * EventType -- The type of callback event + * Event -- Data structure containing event data + * Cookie -- Optional data specified during callback registration + * + ********************************************************************************/ +int +TvCtrlPointCallbackEventHandler( Upnp_EventType EventType, + void *Event, + void *Cookie ) +{ + SampleUtil_PrintEvent( EventType, Event ); + + switch ( EventType ) { + /* + SSDP Stuff + */ + case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: + case UPNP_DISCOVERY_SEARCH_RESULT: + { + struct Upnp_Discovery *d_event = + ( struct Upnp_Discovery * )Event; + IXML_Document *DescDoc = NULL; + int ret; + + if( d_event->ErrCode != UPNP_E_SUCCESS ) { + SampleUtil_Print( "Error in Discovery Callback -- %d", + d_event->ErrCode ); + } + + if( ( ret = + UpnpDownloadXmlDoc( d_event->Location, + &DescDoc ) ) != + UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error obtaining device description from %s -- error = %d", + d_event->Location, ret ); + } else { + TvCtrlPointAddDevice( DescDoc, d_event->Location, + d_event->Expires ); + } + + if( DescDoc ) + ixmlDocument_free( DescDoc ); + + TvCtrlPointPrintList( ); + break; + } + + case UPNP_DISCOVERY_SEARCH_TIMEOUT: + /* + Nothing to do here... + */ + break; + + case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: + { + struct Upnp_Discovery *d_event = + ( struct Upnp_Discovery * )Event; + + if( d_event->ErrCode != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error in Discovery ByeBye Callback -- %d", + d_event->ErrCode ); + } + + SampleUtil_Print( "Received ByeBye for Device: %s", + d_event->DeviceId ); + TvCtrlPointRemoveDevice( d_event->DeviceId ); + + SampleUtil_Print( "After byebye:" ); + TvCtrlPointPrintList( ); + + break; + } + + /* + SOAP Stuff + */ + case UPNP_CONTROL_ACTION_COMPLETE: + { + struct Upnp_Action_Complete *a_event = + ( struct Upnp_Action_Complete * )Event; + + if( a_event->ErrCode != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error in Action Complete Callback -- %d", + a_event->ErrCode ); + } + + /* + No need for any processing here, just print out results. Service state + table updates are handled by events. + */ + + break; + } + + case UPNP_CONTROL_GET_VAR_COMPLETE: + { + struct Upnp_State_Var_Complete *sv_event = + ( struct Upnp_State_Var_Complete * )Event; + + if( sv_event->ErrCode != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error in Get Var Complete Callback -- %d", + sv_event->ErrCode ); + } else { + TvCtrlPointHandleGetVar( sv_event->CtrlUrl, + sv_event->StateVarName, + sv_event->CurrentVal ); + } + + break; + } + + /* + GENA Stuff + */ + case UPNP_EVENT_RECEIVED: + { + struct Upnp_Event *e_event = ( struct Upnp_Event * )Event; + + TvCtrlPointHandleEvent( e_event->Sid, e_event->EventKey, + e_event->ChangedVariables ); + break; + } + + case UPNP_EVENT_SUBSCRIBE_COMPLETE: + case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: + case UPNP_EVENT_RENEWAL_COMPLETE: + { + struct Upnp_Event_Subscribe *es_event = + ( struct Upnp_Event_Subscribe * )Event; + + if( es_event->ErrCode != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error in Event Subscribe Callback -- %d", + es_event->ErrCode ); + } else { + TvCtrlPointHandleSubscribeUpdate( es_event-> + PublisherUrl, + es_event->Sid, + es_event->TimeOut ); + } + + break; + } + + case UPNP_EVENT_AUTORENEWAL_FAILED: + case UPNP_EVENT_SUBSCRIPTION_EXPIRED: + { + int TimeOut = default_timeout; + Upnp_SID newSID; + int ret; + + struct Upnp_Event_Subscribe *es_event = + ( struct Upnp_Event_Subscribe * )Event; + + ret = + UpnpSubscribe( ctrlpt_handle, es_event->PublisherUrl, + &TimeOut, newSID ); + + if( ret == UPNP_E_SUCCESS ) { + SampleUtil_Print( "Subscribed to EventURL with SID=%s", + newSID ); + TvCtrlPointHandleSubscribeUpdate( es_event-> + PublisherUrl, newSID, + TimeOut ); + } else { + SampleUtil_Print + ( "Error Subscribing to EventURL -- %d", ret ); + } + break; + } + + /* + ignore these cases, since this is not a device + */ + case UPNP_EVENT_SUBSCRIPTION_REQUEST: + case UPNP_CONTROL_GET_VAR_REQUEST: + case UPNP_CONTROL_ACTION_REQUEST: + break; + } + + return 0; +} + +/******************************************************************************** + * TvCtrlPointVerifyTimeouts + * + * Description: + * Checks the advertisement each device + * in the global device list. If an advertisement expires, + * the device is removed from the list. If an advertisement is about to + * expire, a search request is sent for that device. + * + * Parameters: + * incr -- The increment to subtract from the timeouts each time the + * function is called. + * + ********************************************************************************/ +void +TvCtrlPointVerifyTimeouts( int incr ) +{ + struct TvDeviceNode *prevdevnode, + *curdevnode; + int ret; + + ithread_mutex_lock( &DeviceListMutex ); + + prevdevnode = NULL; + curdevnode = GlobalDeviceList; + + while( curdevnode ) { + curdevnode->device.AdvrTimeOut -= incr; + //SampleUtil_Print("Advertisement Timeout: %d\n", curdevnode->device.AdvrTimeOut); + + if( curdevnode->device.AdvrTimeOut <= 0 ) { + /* + This advertisement has expired, so we should remove the device + from the list + */ + + if( GlobalDeviceList == curdevnode ) + GlobalDeviceList = curdevnode->next; + else + prevdevnode->next = curdevnode->next; + TvCtrlPointDeleteNode( curdevnode ); + if( prevdevnode ) + curdevnode = prevdevnode->next; + else + curdevnode = GlobalDeviceList; + } else { + + if( curdevnode->device.AdvrTimeOut < 2 * incr ) { + /* + This advertisement is about to expire, so send + out a search request for this device UDN to + try to renew + */ + ret = UpnpSearchAsync( ctrlpt_handle, incr, + curdevnode->device.UDN, NULL ); + if( ret != UPNP_E_SUCCESS ) + SampleUtil_Print + ( "Error sending search request for Device UDN: %s -- err = %d", + curdevnode->device.UDN, ret ); + } + + prevdevnode = curdevnode; + curdevnode = curdevnode->next; + } + + } + ithread_mutex_unlock( &DeviceListMutex ); + +} + +/******************************************************************************** + * TvCtrlPointTimerLoop + * + * Description: + * Function that runs in its own thread and monitors advertisement + * and subscription timeouts for devices in the global device list. + * + * Parameters: + * None + * + ********************************************************************************/ +void * +TvCtrlPointTimerLoop( void *args ) +{ + int incr = 30; // how often to verify the timeouts, in seconds + + while( 1 ) { + isleep( incr ); + TvCtrlPointVerifyTimeouts( incr ); + } + + return NULL; +} + +/******************************************************************************** + * TvCtrlPointStart + * + * Description: + * Call this function to initialize the UPnP library and start the TV Control + * Point. This function creates a timer thread and provides a callback + * handler to process any UPnP events that are received. + * + * Parameters: + * None + * + * Returns: + * TV_SUCCESS if everything went well, else TV_ERROR + * + ********************************************************************************/ +int +TvCtrlPointStart( print_string printFunctionPtr, + state_update updateFunctionPtr ) +{ + ithread_t timer_thread; + int rc; + short int port = 0; + char *ip_address = NULL; + + SampleUtil_Initialize( printFunctionPtr ); + SampleUtil_RegisterUpdateFunction( updateFunctionPtr ); + + ithread_mutex_init( &DeviceListMutex, 0 ); + + SampleUtil_Print( "Intializing UPnP with ipaddress=%s port=%d", + ip_address, port ); + rc = UpnpInit( ip_address, port ); + if( UPNP_E_SUCCESS != rc ) { + SampleUtil_Print( "WinCEStart: UpnpInit() Error: %d", rc ); + //UpnpFinish( ); + //return TV_ERROR; + } + + if( NULL == ip_address ) + ip_address = UpnpGetServerIpAddress( ); + if( 0 == port ) + port = UpnpGetServerPort( ); + + SampleUtil_Print( "UPnP Initialized (%s:%d)", ip_address, port ); + + SampleUtil_Print( "Registering Control Point" ); + rc = UpnpRegisterClient( TvCtrlPointCallbackEventHandler, + &ctrlpt_handle, &ctrlpt_handle ); + if( UPNP_E_SUCCESS != rc ) { + SampleUtil_Print( "Error registering CP: %d", rc ); + UpnpFinish( ); + return TV_ERROR; + } + + SampleUtil_Print( "Control Point Registered" ); + + TvCtrlPointRefresh( ); + + // start a timer thread + ithread_create( &timer_thread, NULL, TvCtrlPointTimerLoop, NULL ); + + return TV_SUCCESS; +} + +int +TvCtrlPointStop( void ) +{ + TvCtrlPointRemoveAll( ); + UpnpUnRegisterClient( ctrlpt_handle ); + UpnpFinish( ); + SampleUtil_Finish( ); + + return TV_SUCCESS; +} diff --git a/upnp/sample/tvcombo/upnp_tv_ctrlpt.h b/upnp/sample/tvcombo/upnp_tv_ctrlpt.h new file mode 100644 index 0000000..b47f5c6 --- /dev/null +++ b/upnp/sample/tvcombo/upnp_tv_ctrlpt.h @@ -0,0 +1,158 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef UPNP_TV_CTRLPT_H +#define UPNP_TV_CTRLPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "ithread.h" +#include +#include +#include +#include +#include + +#include "upnp.h" +#include "upnptools.h" +#include "sample_util.h" + +#define TV_SERVICE_SERVCOUNT 2 +#define TV_SERVICE_CONTROL 0 +#define TV_SERVICE_PICTURE 1 + +#define TV_CONTROL_VARCOUNT 3 +#define TV_CONTROL_POWER 0 +#define TV_CONTROL_CHANNEL 1 +#define TV_CONTROL_VOLUME 2 + +#define TV_PICTURE_VARCOUNT 4 +#define TV_PICTURE_COLOR 0 +#define TV_PICTURE_TINT 1 +#define TV_PICTURE_CONTRAST 2 +#define TV_PICTURE_BRIGHTNESS 3 + +#define TV_MAX_VAL_LEN 5 + +#define TV_SUCCESS 0 +#define TV_ERROR (-1) +#define TV_WARNING 1 + +/* This should be the maximum VARCOUNT from above */ +#define TV_MAXVARS TV_PICTURE_VARCOUNT + +extern char TvDeviceType[]; +extern char *TvServiceType[]; +extern char *TvServiceName[]; +extern char *TvVarName[TV_SERVICE_SERVCOUNT][TV_MAXVARS]; +extern char TvVarCount[]; + +struct tv_service { + char ServiceId[NAME_SIZE]; + char ServiceType[NAME_SIZE]; + char *VariableStrVal[TV_MAXVARS]; + char EventURL[NAME_SIZE]; + char ControlURL[NAME_SIZE]; + char SID[NAME_SIZE]; +}; + +extern struct TvDeviceNode *GlobalDeviceList; + +struct TvDevice { + char UDN[250]; + char DescDocURL[250]; + char FriendlyName[250]; + char PresURL[250]; + int AdvrTimeOut; + struct tv_service TvService[TV_SERVICE_SERVCOUNT]; +}; + +struct TvDeviceNode { + struct TvDevice device; + struct TvDeviceNode *next; +}; + +extern ithread_mutex_t DeviceListMutex; + +extern UpnpClient_Handle ctrlpt_handle; + +void TvCtrlPointPrintHelp( void ); +int TvCtrlPointDeleteNode(struct TvDeviceNode*); +int TvCtrlPointRemoveDevice(char*); +int TvCtrlPointRemoveAll( void ); +int TvCtrlPointRefresh( void ); + + +int TvCtrlPointSendAction(int, int, char *, char **, char **, int); +int TvCtrlPointSendActionNumericArg(int devnum, int service, char *actionName, char *paramName, int paramValue); +int TvCtrlPointSendPowerOn(int devnum); +int TvCtrlPointSendPowerOff(int devnum); +int TvCtrlPointSendSetChannel(int, int); +int TvCtrlPointSendSetVolume(int, int); +int TvCtrlPointSendSetColor(int, int); +int TvCtrlPointSendSetTint(int, int); +int TvCtrlPointSendSetContrast(int, int); +int TvCtrlPointSendSetBrightness(int, int); + +int TvCtrlPointGetVar(int, int, char*); +int TvCtrlPointGetPower(int devnum); +int TvCtrlPointGetChannel(int); +int TvCtrlPointGetVolume(int); +int TvCtrlPointGetColor(int); +int TvCtrlPointGetTint(int); +int TvCtrlPointGetContrast(int); +int TvCtrlPointGetBrightness(int); + +int TvCtrlPointGetDevice(int, struct TvDeviceNode **); +int TvCtrlPointPrintList( void ); +int TvCtrlPointPrintDevice(int); +void TvCtrlPointAddDevice (IXML_Document *, char *, int); +void TvCtrlPointHandleGetVar(char *,char *,DOMString); +void TvStateUpdate(char*,int, IXML_Document * , char **); +void TvCtrlPointHandleEvent(Upnp_SID, int, IXML_Document *); +void TvCtrlPointHandleSubscribeUpdate(char *, Upnp_SID, int); +int TvCtrlPointCallbackEventHandler(Upnp_EventType, void *, void *); +void TvCtrlPointVerifyTimeouts(int); +void TvCtrlPointPrintCommands( void ); +void* TvCtrlPointCommandLoop( void* ); +int TvCtrlPointStart( print_string printFunctionPtr, state_update updateFunctionPtr ); +int TvCtrlPointStop( void ); +int TvCtrlPointProcessCommand( char *cmdline ); + +#ifdef __cplusplus +}; +#endif + +#endif //UPNP_TV_CTRLPT_H diff --git a/upnp/sample/tvcombo/upnp_tv_device.c b/upnp/sample/tvcombo/upnp_tv_device.c new file mode 100644 index 0000000..ad459b6 --- /dev/null +++ b/upnp/sample/tvcombo/upnp_tv_device.c @@ -0,0 +1,2031 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#include "upnp_tv_device.h" + +#define DEFAULT_WEB_DIR "./web" + +#define DESC_URL_SIZE 200 + +/* + Device type for tv device + */ +extern char TvDeviceType[]; + +/* + Service types for tv services + */ +extern char *TvServiceType[]; + +/* + Global arrays for storing Tv Control Service + variable names, values, and defaults + */ +char *tvc_varname[] = { "Power", "Channel", "Volume" }; +char tvc_varval[TV_CONTROL_VARCOUNT][TV_MAX_VAL_LEN]; +char *tvc_varval_def[] = { "1", "1", "5" }; + +/* + Global arrays for storing Tv Picture Service + variable names, values, and defaults + */ +char *tvp_varname[] = { "Color", "Tint", "Contrast", "Brightness" }; +char tvp_varval[TV_PICTURE_VARCOUNT][TV_MAX_VAL_LEN]; +char *tvp_varval_def[] = { "5", "5", "5", "5" }; + +/* + The amount of time (in seconds) before advertisements + will expire + */ +int default_advr_expire = 100; + +/* + Global structure for storing the state table for this device + */ +struct TvService tv_service_table[2]; + +/* + Device handle supplied by UPnP SDK + */ +UpnpDevice_Handle device_handle = -1; + +/* + Mutex for protecting the global state table data + in a multi-threaded, asynchronous environment. + All functions should lock this mutex before reading + or writing the state table data. + */ +ithread_mutex_t TVDevMutex; + +//Color constants +#define MAX_COLOR 10 +#define MIN_COLOR 1 + +//Brightness constants +#define MAX_BRIGHTNESS 10 +#define MIN_BRIGHTNESS 1 + +//Power constants +#define POWER_ON 1 +#define POWER_OFF 0 + +//Tint constants +#define MAX_TINT 10 +#define MIN_TINT 1 + +//Volume constants +#define MAX_VOLUME 10 +#define MIN_VOLUME 1 + +//Contrast constants +#define MAX_CONTRAST 10 +#define MIN_CONTRAST 1 + +//Channel constants +#define MAX_CHANNEL 100 +#define MIN_CHANNEL 1 + +/****************************************************************************** + * SetServiceTable + * + * Description: + * Initializes the service table for the specified service. + * Note that + * knowledge of the service description is + * assumed. + * Parameters: + * int serviceType - one of TV_SERVICE_CONTROL or, TV_SERVICE_PICTURE + * const char * UDN - UDN of device containing service + * const char * serviceId - serviceId of service + * const char * serviceTypeS - service type (as specified in Description + * Document) + * struct TvService *out - service containing table to be set. + * + *****************************************************************************/ +int +SetServiceTable( IN int serviceType, + IN const char *UDN, + IN const char *serviceId, + IN const char *serviceTypeS, + INOUT struct TvService *out ) +{ + unsigned int i = 0; + + strcpy( out->UDN, UDN ); + strcpy( out->ServiceId, serviceId ); + strcpy( out->ServiceType, serviceTypeS ); + + switch ( serviceType ) { + case TV_SERVICE_CONTROL: + out->VariableCount = TV_CONTROL_VARCOUNT; + for( i = 0; + i < tv_service_table[TV_SERVICE_CONTROL].VariableCount; + i++ ) { + tv_service_table[TV_SERVICE_CONTROL].VariableName[i] + = tvc_varname[i]; + tv_service_table[TV_SERVICE_CONTROL].VariableStrVal[i] + = tvc_varval[i]; + strcpy( tv_service_table[TV_SERVICE_CONTROL]. + VariableStrVal[i], tvc_varval_def[i] ); + } + + break; + case TV_SERVICE_PICTURE: + out->VariableCount = TV_PICTURE_VARCOUNT; + + for( i = 0; + i < tv_service_table[TV_SERVICE_PICTURE].VariableCount; + i++ ) { + tv_service_table[TV_SERVICE_PICTURE].VariableName[i] = + tvp_varname[i]; + tv_service_table[TV_SERVICE_PICTURE].VariableStrVal[i] = + tvp_varval[i]; + strcpy( tv_service_table[TV_SERVICE_PICTURE]. + VariableStrVal[i], tvp_varval_def[i] ); + } + + break; + default: + assert( 0 ); + } + + return SetActionTable( serviceType, out ); + +} + +/****************************************************************************** + * SetActionTable + * + * Description: + * Initializes the action table for the specified service. + * Note that + * knowledge of the service description is + * assumed. Action names are hardcoded. + * Parameters: + * int serviceType - one of TV_SERVICE_CONTROL or, TV_SERVICE_PICTURE + * struct TvService *out - service containing action table to set. + * + *****************************************************************************/ +int +SetActionTable( IN int serviceType, + INOUT struct TvService *out ) +{ + if( serviceType == TV_SERVICE_CONTROL ) { + out->ActionNames[0] = "PowerOn"; + out->actions[0] = TvDevicePowerOn; + out->ActionNames[1] = "PowerOff"; + out->actions[1] = TvDevicePowerOff; + out->ActionNames[2] = "SetChannel"; + out->actions[2] = TvDeviceSetChannel; + out->ActionNames[3] = "IncreaseChannel"; + out->actions[3] = TvDeviceIncreaseChannel; + out->ActionNames[4] = "DecreaseChannel"; + out->actions[4] = TvDeviceDecreaseChannel; + out->ActionNames[5] = "SetVolume"; + out->actions[5] = TvDeviceSetVolume; + out->ActionNames[6] = "IncreaseVolume"; + out->actions[6] = TvDeviceIncreaseVolume; + out->ActionNames[7] = "DecreaseVolume"; + out->actions[7] = TvDeviceDecreaseVolume; + out->ActionNames[8] = NULL; + return 1; + } else if( serviceType == TV_SERVICE_PICTURE ) { + out->ActionNames[0] = "SetColor"; + out->ActionNames[1] = "IncreaseColor"; + out->ActionNames[2] = "DecreaseColor"; + out->actions[0] = TvDeviceSetColor; + out->actions[1] = TvDeviceIncreaseColor; + out->actions[2] = TvDeviceDecreaseColor; + out->ActionNames[3] = "SetTint"; + out->ActionNames[4] = "IncreaseTint"; + out->ActionNames[5] = "DecreaseTint"; + out->actions[3] = TvDeviceSetTint; + out->actions[4] = TvDeviceIncreaseTint; + out->actions[5] = TvDeviceDecreaseTint; + + out->ActionNames[6] = "SetBrightness"; + out->ActionNames[7] = "IncreaseBrightness"; + out->ActionNames[8] = "DecreaseBrightness"; + out->actions[6] = TvDeviceSetBrightness; + out->actions[7] = TvDeviceIncreaseBrightness; + out->actions[8] = TvDeviceDecreaseBrightness; + + out->ActionNames[9] = "SetContrast"; + out->ActionNames[10] = "IncreaseContrast"; + out->ActionNames[11] = "DecreaseContrast"; + + out->actions[9] = TvDeviceSetContrast; + out->actions[10] = TvDeviceIncreaseContrast; + out->actions[11] = TvDeviceDecreaseContrast; + return 1; + } + + return 0; + +} + +/****************************************************************************** + * TvDeviceStateTableInit + * + * Description: + * Initialize the device state table for + * this TvDevice, pulling identifier info + * from the description Document. Note that + * knowledge of the service description is + * assumed. State table variables and default + * values are currently hardcoded in this file + * rather than being read from service description + * documents. + * + * Parameters: + * DescDocURL -- The description document URL + * + *****************************************************************************/ +int +TvDeviceStateTableInit( IN char *DescDocURL ) +{ + IXML_Document *DescDoc = NULL; + int ret = UPNP_E_SUCCESS; + char *servid_ctrl = NULL, + *evnturl_ctrl = NULL, + *ctrlurl_ctrl = NULL; + char *servid_pict = NULL, + *evnturl_pict = NULL, + *ctrlurl_pict = NULL; + char *udn = NULL; + + //Download description document + if( UpnpDownloadXmlDoc( DescDocURL, &DescDoc ) != UPNP_E_SUCCESS ) { + SampleUtil_Print( "TvDeviceStateTableInit -- Error Parsing %s\n", + DescDocURL ); + ret = UPNP_E_INVALID_DESC; + goto error_handler; + } + + udn = SampleUtil_GetFirstDocumentItem( DescDoc, "UDN" ); + + /* + Find the Tv Control Service identifiers + */ + if( !SampleUtil_FindAndParseService( DescDoc, DescDocURL, + TvServiceType[TV_SERVICE_CONTROL], + &servid_ctrl, &evnturl_ctrl, + &ctrlurl_ctrl ) ) { + SampleUtil_Print( "TvDeviceStateTableInit -- Error: Could not find" + " Service: %s\n", + TvServiceType[TV_SERVICE_CONTROL] ); + + ret = UPNP_E_INVALID_DESC; + goto error_handler; + } + + //set control service table + SetServiceTable( TV_SERVICE_CONTROL, udn, servid_ctrl, + TvServiceType[TV_SERVICE_CONTROL], + &tv_service_table[TV_SERVICE_CONTROL] ); + + /* + Find the Tv Picture Service identifiers + */ + if( !SampleUtil_FindAndParseService( DescDoc, DescDocURL, + TvServiceType[TV_SERVICE_PICTURE], + &servid_pict, &evnturl_pict, + &ctrlurl_pict ) ) { + SampleUtil_Print( "TvDeviceStateTableInit -- Error: Could not find" + " Service: %s\n", + TvServiceType[TV_SERVICE_PICTURE] ); + + ret = UPNP_E_INVALID_DESC; + goto error_handler; + } + //set picture service table + SetServiceTable( TV_SERVICE_PICTURE, udn, servid_pict, + TvServiceType[TV_SERVICE_PICTURE], + &tv_service_table[TV_SERVICE_PICTURE] ); + + error_handler: + + //clean up + if( udn ) + free( udn ); + if( servid_ctrl ) + free( servid_ctrl ); + if( evnturl_ctrl ) + free( evnturl_ctrl ); + if( ctrlurl_ctrl ) + free( ctrlurl_ctrl ); + if( servid_pict ) + free( servid_pict ); + if( evnturl_pict ) + free( evnturl_pict ); + if( ctrlurl_pict ) + free( ctrlurl_pict ); + if( DescDoc ) + ixmlDocument_free( DescDoc ); + + return ( ret ); +} + +/****************************************************************************** + * TvDeviceHandleSubscriptionRequest + * + * Description: + * Called during a subscription request callback. If the + * subscription request is for this device and either its + * control service or picture service, then accept it. + * + * Parameters: + * sr_event -- The subscription request event structure + * + *****************************************************************************/ +int +TvDeviceHandleSubscriptionRequest( IN struct Upnp_Subscription_Request + *sr_event ) +{ + unsigned int i = 0; //,j=0; + + // IXML_Document *PropSet=NULL; + + //lock state mutex + ithread_mutex_lock( &TVDevMutex ); + + for( i = 0; i < TV_SERVICE_SERVCOUNT; i++ ) { + if( ( strcmp( sr_event->UDN, tv_service_table[i].UDN ) == 0 ) && + ( strcmp( sr_event->ServiceId, tv_service_table[i].ServiceId ) + == 0 ) ) { + + /* + PropSet = NULL; + + for (j=0; j< tv_service_table[i].VariableCount; j++) + { + //add each variable to the property set + //for initial state dump + UpnpAddToPropertySet(&PropSet, + tv_service_table[i].VariableName[j], + tv_service_table[i].VariableStrVal[j]); + } + + //dump initial state + UpnpAcceptSubscriptionExt(device_handle, sr_event->UDN, + sr_event->ServiceId, + PropSet,sr_event->Sid); + //free document + Document_free(PropSet); + + */ + + UpnpAcceptSubscription( device_handle, + sr_event->UDN, + sr_event->ServiceId, + ( const char ** )tv_service_table[i]. + VariableName, + ( const char ** )tv_service_table[i]. + VariableStrVal, + tv_service_table[i].VariableCount, + sr_event->Sid ); + + } + } + + ithread_mutex_unlock( &TVDevMutex ); + + return ( 1 ); +} + +/****************************************************************************** + * TvDeviceHandleGetVarRequest + * + * Description: + * Called during a get variable request callback. If the + * request is for this device and either its control service + * or picture service, then respond with the variable value. + * + * Parameters: + * cgv_event -- The control get variable request event structure + * + *****************************************************************************/ +int +TvDeviceHandleGetVarRequest( INOUT struct Upnp_State_Var_Request + *cgv_event ) +{ + unsigned int i = 0, + j = 0; + int getvar_succeeded = 0; + + cgv_event->CurrentVal = NULL; + + ithread_mutex_lock( &TVDevMutex ); + + for( i = 0; i < TV_SERVICE_SERVCOUNT; i++ ) { + //check udn and service id + if( ( strcmp( cgv_event->DevUDN, tv_service_table[i].UDN ) == 0 ) + && + ( strcmp( cgv_event->ServiceID, tv_service_table[i].ServiceId ) + == 0 ) ) { + //check variable name + for( j = 0; j < tv_service_table[i].VariableCount; j++ ) { + if( strcmp( cgv_event->StateVarName, + tv_service_table[i].VariableName[j] ) == 0 ) { + getvar_succeeded = 1; + cgv_event->CurrentVal = + ixmlCloneDOMString( tv_service_table[i]. + VariableStrVal[j] ); + break; + } + } + } + } + + if( getvar_succeeded ) { + cgv_event->ErrCode = UPNP_E_SUCCESS; + } else { + SampleUtil_Print + ( "Error in UPNP_CONTROL_GET_VAR_REQUEST callback:\n" ); + SampleUtil_Print( " Unknown variable name = %s\n", + cgv_event->StateVarName ); + cgv_event->ErrCode = 404; + strcpy( cgv_event->ErrStr, "Invalid Variable" ); + } + + ithread_mutex_unlock( &TVDevMutex ); + + return ( cgv_event->ErrCode == UPNP_E_SUCCESS ); +} + +/****************************************************************************** + * TvDeviceHandleActionRequest + * + * Description: + * Called during an action request callback. If the + * request is for this device and either its control service + * or picture service, then perform the action and respond. + * + * Parameters: + * ca_event -- The control action request event structure + * + *****************************************************************************/ +int +TvDeviceHandleActionRequest( INOUT struct Upnp_Action_Request *ca_event ) +{ + + /* + Defaults if action not found + */ + int action_found = 0; + int i = 0; + int service = -1; + int retCode = 0; + char *errorString = NULL; + + ca_event->ErrCode = 0; + ca_event->ActionResult = NULL; + + if( ( strcmp( ca_event->DevUDN, + tv_service_table[TV_SERVICE_CONTROL].UDN ) == 0 ) && + ( strcmp + ( ca_event->ServiceID, + tv_service_table[TV_SERVICE_CONTROL].ServiceId ) == 0 ) ) { + /* + Request for action in the TvDevice Control Service + */ + service = TV_SERVICE_CONTROL; + } else if( ( strcmp( ca_event->DevUDN, + tv_service_table[TV_SERVICE_PICTURE].UDN ) == 0 ) + && + ( strcmp + ( ca_event->ServiceID, + tv_service_table[TV_SERVICE_PICTURE].ServiceId ) == + 0 ) ) { + /* + Request for action in the TvDevice Picture Service + */ + service = TV_SERVICE_PICTURE; + } + //Find and call appropriate procedure based on action name + //Each action name has an associated procedure stored in the + //service table. These are set at initialization. + + for( i = 0; ( ( i < TV_MAXACTIONS ) && + ( tv_service_table[service].ActionNames[i] != NULL ) ); + i++ ) { + + if( !strcmp( ca_event->ActionName, + tv_service_table[service].ActionNames[i] ) ) { + + if( ( !strcmp( tv_service_table[TV_SERVICE_CONTROL]. + VariableStrVal[TV_CONTROL_POWER], "1" ) ) + || ( !strcmp( ca_event->ActionName, "PowerOn" ) ) ) { + retCode = + tv_service_table[service].actions[i] ( ca_event-> + ActionRequest, + &ca_event-> + ActionResult, + &errorString ); + } else { + errorString = "Power is Off"; + retCode = UPNP_E_INTERNAL_ERROR; + } + action_found = 1; + break; + } + } + + if( !action_found ) { + ca_event->ActionResult = NULL; + strcpy( ca_event->ErrStr, "Invalid Action" ); + ca_event->ErrCode = 401; + } else { + if( retCode == UPNP_E_SUCCESS ) { + ca_event->ErrCode = UPNP_E_SUCCESS; + } else { + //copy the error string + strcpy( ca_event->ErrStr, errorString ); + switch ( retCode ) { + case UPNP_E_INVALID_PARAM: + { + ca_event->ErrCode = 402; + break; + } + case UPNP_E_INTERNAL_ERROR: + default: + { + ca_event->ErrCode = 501; + break; + } + + } + } + } + + return ( ca_event->ErrCode ); +} + +/****************************************************************************** + * TvDeviceSetServiceTableVar + * + * Description: + * Update the TvDevice service state table, and notify all subscribed + * control points of the updated state. Note that since this function + * blocks on the mutex TVDevMutex, to avoid a hang this function should + * not be called within any other function that currently has this mutex + * locked. + * + * Parameters: + * service -- The service number (TV_SERVICE_CONTROL or TV_SERVICE_PICTURE) + * variable -- The variable number (TV_CONTROL_POWER, TV_CONTROL_CHANNEL, + * TV_CONTROL_VOLUME, TV_PICTURE_COLOR, TV_PICTURE_TINT, + * TV_PICTURE_CONTRAST, or TV_PICTURE_BRIGHTNESS) + * value -- The string representation of the new value + * + *****************************************************************************/ +int +TvDeviceSetServiceTableVar( IN unsigned int service, + IN unsigned int variable, + IN char *value ) +{ + //IXML_Document *PropSet= NULL; + + if( ( service >= TV_SERVICE_SERVCOUNT ) + || ( variable >= tv_service_table[service].VariableCount ) + || ( strlen( value ) >= TV_MAX_VAL_LEN ) ) { + return ( 0 ); + } + + ithread_mutex_lock( &TVDevMutex ); + + strcpy( tv_service_table[service].VariableStrVal[variable], value ); + + /* + //Using utility api + PropSet= UpnpCreatePropertySet(1,tv_service_table[service]. + VariableName[variable], + tv_service_table[service]. + VariableStrVal[variable]); + + UpnpNotifyExt(device_handle, tv_service_table[service].UDN, + tv_service_table[service].ServiceId,PropSet); + + //Free created property set + Document_free(PropSet); + */ + + UpnpNotify( device_handle, + tv_service_table[service].UDN, + tv_service_table[service].ServiceId, + ( const char ** )&tv_service_table[service]. + VariableName[variable], + ( const char ** )&tv_service_table[service]. + VariableStrVal[variable], 1 ); + + ithread_mutex_unlock( &TVDevMutex ); + + return ( 1 ); + +} + +/****************************************************************************** + * TvDeviceSetPower + * + * Description: + * Turn the power on/off, update the TvDevice control service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * on -- If 1, turn power on. If 0, turn power off. + * + *****************************************************************************/ +int +TvDeviceSetPower( IN int on ) +{ + char value[TV_MAX_VAL_LEN]; + int ret = 0; + + if( on != POWER_ON && on != POWER_OFF ) { + SampleUtil_Print( "error: can't set power to value %d\n", on ); + return ( 0 ); + } + + /* + Vendor-specific code to turn the power on/off goes here + */ + + sprintf( value, "%d", on ); + ret = TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL, TV_CONTROL_POWER, + value ); + + return ( ret ); +} + +/****************************************************************************** + * TvDevicePowerOn + * + * Description: + * Turn the power on. + * + * Parameters: + * + * IXML_Document * in - document of action request + * IXML_Document **out - action result + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDevicePowerOn( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + ( *out ) = NULL; + ( *errorString ) = NULL; + + if( TvDeviceSetPower( POWER_ON ) ) { + //create a response + + if( UpnpAddToActionResponse( out, "PowerOn", + TvServiceType[TV_SERVICE_CONTROL], + "Power", "1" ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * TvDevicePowerOff + * + * Description: + * Turn the power off. + * + * Parameters: + * + * IXML_Document * in - document of action request + * IXML_Document **out - action result + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDevicePowerOff( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + ( *out ) = NULL; + ( *errorString ) = NULL; + if( TvDeviceSetPower( POWER_OFF ) ) { + //create a response + + if( UpnpAddToActionResponse( out, "PowerOff", + TvServiceType[TV_SERVICE_CONTROL], + "Power", "0" ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + + return UPNP_E_SUCCESS; + } + + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; +} + +/****************************************************************************** + * TvDeviceSetChannel + * + * Description: + * Change the channel, update the TvDevice control service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceSetChannel( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + char *value = NULL; + + int channel = 0; + + ( *out ) = NULL; + ( *errorString ) = NULL; + + if( !( value = SampleUtil_GetFirstDocumentItem( in, "Channel" ) ) ) { + ( *errorString ) = "Invalid Channel"; + return UPNP_E_INVALID_PARAM; + } + + channel = atoi( value ); + + if( channel < MIN_CHANNEL || channel > MAX_CHANNEL ) { + + free( value ); + SampleUtil_Print( "error: can't change to channel %d\n", channel ); + ( *errorString ) = "Invalid Channel"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL, + TV_CONTROL_CHANNEL, value ) ) { + if( UpnpAddToActionResponse( out, "SetChannel", + TvServiceType[TV_SERVICE_CONTROL], + "NewChannel", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + free( value ); + return UPNP_E_INTERNAL_ERROR; + } + free( value ); + return UPNP_E_SUCCESS; + } else { + free( value ); + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * IncrementChannel + * + * Description: + * Increment the channel. Read the current channel from the state + * table, add the increment, and then change the channel. + * + * Parameters: + * incr -- The increment by which to change the channel. + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +IncrementChannel( IN int incr, + IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + int curchannel, + newchannel; + + char *actionName = NULL; + char value[TV_MAX_VAL_LEN]; + + if( incr > 0 ) { + actionName = "IncreaseChannel"; + } else { + actionName = "DecreaseChannel"; + } + + ithread_mutex_lock( &TVDevMutex ); + curchannel = atoi( tv_service_table[TV_SERVICE_CONTROL]. + VariableStrVal[TV_CONTROL_CHANNEL] ); + ithread_mutex_unlock( &TVDevMutex ); + + newchannel = curchannel + incr; + + if( newchannel < MIN_CHANNEL || newchannel > MAX_CHANNEL ) { + SampleUtil_Print( "error: can't change to channel %d\n", + newchannel ); + ( *errorString ) = "Invalid Channel"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + sprintf( value, "%d", newchannel ); + + if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL, + TV_CONTROL_CHANNEL, value ) ) { + if( UpnpAddToActionResponse( out, actionName, + TvServiceType[TV_SERVICE_CONTROL], + "Channel", value ) != UPNP_E_SUCCESS ) + { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } +} + +/****************************************************************************** + * TvDeviceDecreaseChannel + * + * Description: + * Decrease the channel. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceDecreaseChannel( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + return IncrementChannel( -1, in, out, errorString ); + +} + +/****************************************************************************** + * TvDeviceIncreaseChannel + * + * Description: + * Increase the channel. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceIncreaseChannel( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + return IncrementChannel( 1, in, out, errorString ); + +} + +/****************************************************************************** + * TvDeviceSetVolume + * + * Description: + * Change the volume, update the TvDevice control service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceSetVolume( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + char *value = NULL; + + int volume = 0; + + ( *out ) = NULL; + ( *errorString ) = NULL; + + if( !( value = SampleUtil_GetFirstDocumentItem( in, "Volume" ) ) ) { + ( *errorString ) = "Invalid Volume"; + return UPNP_E_INVALID_PARAM; + } + + volume = atoi( value ); + + if( volume < MIN_VOLUME || volume > MAX_VOLUME ) { + SampleUtil_Print( "error: can't change to volume %d\n", volume ); + ( *errorString ) = "Invalid Volume"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the volume goes here + */ + + if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL, + TV_CONTROL_VOLUME, value ) ) { + if( UpnpAddToActionResponse( out, "SetVolume", + TvServiceType[TV_SERVICE_CONTROL], + "NewVolume", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + free( value ); + return UPNP_E_INTERNAL_ERROR; + } + free( value ); + return UPNP_E_SUCCESS; + } else { + free( value ); + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * IncrementVolume + * + * Description: + * Increment the volume. Read the current volume from the state + * table, add the increment, and then change the volume. + * + * Parameters: + * incr -- The increment by which to change the volume. + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +IncrementVolume( IN int incr, + IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + int curvolume, + newvolume; + char *actionName = NULL; + char value[TV_MAX_VAL_LEN]; + + if( incr > 0 ) { + actionName = "IncreaseVolume"; + } else { + actionName = "DecreaseVolume"; + } + + ithread_mutex_lock( &TVDevMutex ); + curvolume = atoi( tv_service_table[TV_SERVICE_CONTROL]. + VariableStrVal[TV_CONTROL_VOLUME] ); + ithread_mutex_unlock( &TVDevMutex ); + + newvolume = curvolume + incr; + + if( newvolume < MIN_VOLUME || newvolume > MAX_VOLUME ) { + SampleUtil_Print( "error: can't change to volume %d\n", + newvolume ); + ( *errorString ) = "Invalid Volume"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + sprintf( value, "%d", newvolume ); + + if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL, + TV_CONTROL_VOLUME, value ) ) { + if( UpnpAddToActionResponse( out, actionName, + TvServiceType[TV_SERVICE_CONTROL], + "Volume", value ) != UPNP_E_SUCCESS ) + { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * TvDeviceIncrVolume + * + * Description: + * Increase the volume. + * + * Parameters: + * + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +TvDeviceIncreaseVolume( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementVolume( 1, in, out, errorString ); + +} + +/****************************************************************************** + * TvDeviceDecreaseVolume + * + * Description: + * Decrease the volume. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceDecreaseVolume( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementVolume( -1, in, out, errorString ); + +} + +/****************************************************************************** + * TvDeviceSetColor + * + * Description: + * Change the color, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceSetColor( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + char *value = NULL; + + int color = 0; + + ( *out ) = NULL; + ( *errorString ) = NULL; + if( !( value = SampleUtil_GetFirstDocumentItem( in, "Color" ) ) ) { + ( *errorString ) = "Invalid Color"; + return UPNP_E_INVALID_PARAM; + } + + color = atoi( value ); + + if( color < MIN_COLOR || color > MAX_COLOR ) { + SampleUtil_Print( "error: can't change to color %d\n", color ); + ( *errorString ) = "Invalid Color"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the volume goes here + */ + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_COLOR, value ) ) { + if( UpnpAddToActionResponse( out, "SetColor", + TvServiceType[TV_SERVICE_PICTURE], + "NewColor", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + free( value ); + return UPNP_E_INTERNAL_ERROR; + } + free( value ); + return UPNP_E_SUCCESS; + } else { + free( value ); + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * IncrementColor + * + * Description: + * Increment the color. Read the current color from the state + * table, add the increment, and then change the color. + * + * Parameters: + * incr -- The increment by which to change the color. + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ + +int +IncrementColor( IN int incr, + IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + int curcolor, + newcolor; + + char *actionName; + char value[TV_MAX_VAL_LEN]; + + if( incr > 0 ) { + actionName = "IncreaseColor"; + } else { + actionName = "DecreaseColor"; + } + + ithread_mutex_lock( &TVDevMutex ); + curcolor = atoi( tv_service_table[TV_SERVICE_PICTURE]. + VariableStrVal[TV_PICTURE_COLOR] ); + ithread_mutex_unlock( &TVDevMutex ); + + newcolor = curcolor + incr; + + if( newcolor < MIN_COLOR || newcolor > MAX_COLOR ) { + SampleUtil_Print( "error: can't change to color %d\n", newcolor ); + ( *errorString ) = "Invalid Color"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + sprintf( value, "%d", newcolor ); + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_COLOR, value ) ) { + if( UpnpAddToActionResponse( out, actionName, + TvServiceType[TV_SERVICE_PICTURE], + "Color", value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } +} + +/****************************************************************************** + * TvDeviceDecreaseColor + * + * Description: + * Decrease the color. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +TvDeviceDecreaseColor( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementColor( -1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceIncreaseColor + * + * Description: + * Increase the color. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +TvDeviceIncreaseColor( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementColor( 1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceSetTint + * + * Description: + * Change the tint, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceSetTint( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + char *value = NULL; + + int tint = -1; + + ( *out ) = NULL; + ( *errorString ) = NULL; + + if( !( value = SampleUtil_GetFirstDocumentItem( in, "Tint" ) ) ) { + ( *errorString ) = "Invalid Tint"; + return UPNP_E_INVALID_PARAM; + } + + tint = atoi( value ); + + if( tint < MIN_TINT || tint > MAX_TINT ) { + SampleUtil_Print( "error: can't change to tint %d\n", tint ); + ( *errorString ) = "Invalid Tint"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the volume goes here + */ + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_TINT, value ) ) { + if( UpnpAddToActionResponse( out, "SetTint", + TvServiceType[TV_SERVICE_PICTURE], + "NewTint", value ) != UPNP_E_SUCCESS ) + { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + free( value ); + return UPNP_E_INTERNAL_ERROR; + } + free( value ); + return UPNP_E_SUCCESS; + } else { + free( value ); + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * IncrementTint + * + * Description: + * Increment the tint. Read the current tint from the state + * table, add the increment, and then change the tint. + * + * Parameters: + * incr -- The increment by which to change the tint. + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +IncrementTint( IN int incr, + IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + int curtint, + newtint; + + char *actionName = NULL; + char value[TV_MAX_VAL_LEN]; + + if( incr > 0 ) { + actionName = "IncreaseTint"; + } else { + actionName = "DecreaseTint"; + } + + ithread_mutex_lock( &TVDevMutex ); + curtint = atoi( tv_service_table[TV_SERVICE_PICTURE]. + VariableStrVal[TV_PICTURE_TINT] ); + ithread_mutex_unlock( &TVDevMutex ); + + newtint = curtint + incr; + + if( newtint < MIN_TINT || newtint > MAX_TINT ) { + SampleUtil_Print( "error: can't change to tint %d\n", newtint ); + ( *errorString ) = "Invalid Tint"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + sprintf( value, "%d", newtint ); + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_TINT, value ) ) { + if( UpnpAddToActionResponse( out, actionName, + TvServiceType[TV_SERVICE_PICTURE], + "Tint", value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * TvDeviceIncreaseTint + * + * Description: + * Increase tint. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceIncreaseTint( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementTint( 1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceDecreaseTint + * + * Description: + * Decrease tint. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceDecreaseTint( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementTint( -1, in, out, errorString ); +} + +/***************************************************************************** + * TvDeviceSetContrast + * + * Description: + * Change the contrast, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + ****************************************************************************/ +int +TvDeviceSetContrast( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + char *value = NULL; + int contrast = -1; + + ( *out ) = NULL; + ( *errorString ) = NULL; + + if( !( value = SampleUtil_GetFirstDocumentItem( in, "Contrast" ) ) ) { + ( *errorString ) = "Invalid Contrast"; + return UPNP_E_INVALID_PARAM; + } + + contrast = atoi( value ); + + if( contrast < MIN_CONTRAST || contrast > MAX_CONTRAST ) { + SampleUtil_Print( "error: can't change to contrast %d\n", + contrast ); + ( *errorString ) = "Invalid Contrast"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the volume goes here + */ + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_CONTRAST, value ) ) { + if( UpnpAddToActionResponse( out, "SetContrast", + TvServiceType[TV_SERVICE_PICTURE], + "NewContrast", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + free( value ); + return UPNP_E_INTERNAL_ERROR; + } + free( value ); + return UPNP_E_SUCCESS; + } else { + free( value ); + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * IncrementContrast + * + * Description: + * Increment the contrast. Read the current contrast from the state + * table, add the increment, and then change the contrast. + * + * Parameters: + * incr -- The increment by which to change the contrast. + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +IncrementContrast( IN int incr, + IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + int curcontrast, + newcontrast; + + char *actionName = NULL; + char value[TV_MAX_VAL_LEN]; + + if( incr > 0 ) { + actionName = "IncreaseContrast"; + } else { + actionName = "DecreaseContrast"; + } + + ithread_mutex_lock( &TVDevMutex ); + curcontrast = atoi( tv_service_table[TV_SERVICE_PICTURE]. + VariableStrVal[TV_PICTURE_CONTRAST] ); + ithread_mutex_unlock( &TVDevMutex ); + + newcontrast = curcontrast + incr; + + if( newcontrast < MIN_CONTRAST || newcontrast > MAX_CONTRAST ) { + SampleUtil_Print( "error: can't change to contrast %d\n", + newcontrast ); + ( *errorString ) = "Invalid Contrast"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + sprintf( value, "%d", newcontrast ); + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_CONTRAST, value ) ) { + if( UpnpAddToActionResponse( out, actionName, + TvServiceType[TV_SERVICE_PICTURE], + "Contrast", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } +} + +/****************************************************************************** + * TvDeviceIncreaseContrast + * + * Description: + * + * Increase the contrast. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceIncreaseContrast( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + return IncrementContrast( 1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceDecreaseContrast + * + * Description: + * Decrease the contrast. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceDecreaseContrast( IXML_Document * in, + IXML_Document ** out, + char **errorString ) +{ + return IncrementContrast( -1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceSetBrightness + * + * Description: + * Change the brightness, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * brightness -- The brightness value to change to. + * + *****************************************************************************/ +int +TvDeviceSetBrightness( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + + char *value = NULL; + int brightness = -1; + + ( *out ) = NULL; + ( *errorString ) = NULL; + + if( !( value = SampleUtil_GetFirstDocumentItem( in, "Brightness" ) ) ) { + ( *errorString ) = "Invalid Brightness"; + return UPNP_E_INVALID_PARAM; + } + + brightness = atoi( value ); + + if( brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS ) { + SampleUtil_Print( "error: can't change to brightness %d\n", + brightness ); + ( *errorString ) = "Invalid Brightness"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the volume goes here + */ + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_BRIGHTNESS, value ) ) { + if( UpnpAddToActionResponse( out, "SetBrightness", + TvServiceType[TV_SERVICE_PICTURE], + "NewBrightness", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + free( value ); + return UPNP_E_INTERNAL_ERROR; + } + free( value ); + return UPNP_E_SUCCESS; + } else { + free( value ); + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + +} + +/****************************************************************************** + * IncrementBrightness + * + * Description: + * Increment the brightness. Read the current brightness from the state + * table, add the increment, and then change the brightness. + * + * Parameters: + * incr -- The increment by which to change the brightness. + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int +IncrementBrightness( IN int incr, + IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + int curbrightness, + newbrightness; + char *actionName = NULL; + char value[TV_MAX_VAL_LEN]; + + if( incr > 0 ) { + actionName = "IncreaseBrightness"; + } else { + actionName = "DecreaseBrightness"; + } + + ithread_mutex_lock( &TVDevMutex ); + curbrightness = atoi( tv_service_table[TV_SERVICE_PICTURE]. + VariableStrVal[TV_PICTURE_BRIGHTNESS] ); + ithread_mutex_unlock( &TVDevMutex ); + + newbrightness = curbrightness + incr; + + if( newbrightness < MIN_BRIGHTNESS || newbrightness > MAX_BRIGHTNESS ) { + SampleUtil_Print( "error: can't change to brightness %d\n", + newbrightness ); + ( *errorString ) = "Invalid Brightness"; + return UPNP_E_INVALID_PARAM; + } + + /* + Vendor-specific code to set the channel goes here + */ + + sprintf( value, "%d", newbrightness ); + + if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE, + TV_PICTURE_BRIGHTNESS, value ) ) { + if( UpnpAddToActionResponse( out, actionName, + TvServiceType[TV_SERVICE_PICTURE], + "Brightness", + value ) != UPNP_E_SUCCESS ) { + ( *out ) = NULL; + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } + return UPNP_E_SUCCESS; + } else { + ( *errorString ) = "Internal Error"; + return UPNP_E_INTERNAL_ERROR; + } +} + +/****************************************************************************** + * TvDeviceIncreaseBrightness + * + * Description: + * Increase brightness. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceIncreaseBrightness( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + return IncrementBrightness( 1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceDecreaseBrightness + * + * Description: + * Decrease brightnesss. + * + * Parameters: + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int +TvDeviceDecreaseBrightness( IN IXML_Document * in, + OUT IXML_Document ** out, + OUT char **errorString ) +{ + return IncrementBrightness( -1, in, out, errorString ); +} + +/****************************************************************************** + * TvDeviceCallbackEventHandler + * + * Description: + * The callback handler registered with the SDK while registering + * root device. Dispatches the request to the appropriate procedure + * based on the value of EventType. The four requests handled by the + * device are: + * 1) Event Subscription requests. + * 2) Get Variable requests. + * 3) Action requests. + * + * Parameters: + * + * EventType -- The type of callback event + * Event -- Data structure containing event data + * Cookie -- Optional data specified during callback registration + * + *****************************************************************************/ +int +TvDeviceCallbackEventHandler( Upnp_EventType EventType, + void *Event, + void *Cookie ) +{ + + switch ( EventType ) { + + case UPNP_EVENT_SUBSCRIPTION_REQUEST: + + TvDeviceHandleSubscriptionRequest( ( struct + Upnp_Subscription_Request + * )Event ); + break; + + case UPNP_CONTROL_GET_VAR_REQUEST: + TvDeviceHandleGetVarRequest( ( struct Upnp_State_Var_Request + * )Event ); + break; + + case UPNP_CONTROL_ACTION_REQUEST: + TvDeviceHandleActionRequest( ( struct Upnp_Action_Request * ) + Event ); + break; + + /* + ignore these cases, since this is not a control point + */ + case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: + case UPNP_DISCOVERY_SEARCH_RESULT: + case UPNP_DISCOVERY_SEARCH_TIMEOUT: + case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: + case UPNP_CONTROL_ACTION_COMPLETE: + case UPNP_CONTROL_GET_VAR_COMPLETE: + case UPNP_EVENT_RECEIVED: + case UPNP_EVENT_RENEWAL_COMPLETE: + case UPNP_EVENT_SUBSCRIBE_COMPLETE: + case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: + break; + + default: + SampleUtil_Print + ( "Error in TvDeviceCallbackEventHandler: unknown event type %d\n", + EventType ); + } + + /* + Print a summary of the event received + */ + SampleUtil_PrintEvent( EventType, Event ); + + return ( 0 ); +} + +/****************************************************************************** + * TvDeviceStop + * + * Description: + * Stops the device. Uninitializes the sdk. + * + * Parameters: + * + *****************************************************************************/ +int +TvDeviceStop( ) +{ + UpnpUnRegisterRootDevice( device_handle ); + UpnpFinish( ); + SampleUtil_Finish( ); + ithread_mutex_destroy( &TVDevMutex ); + return UPNP_E_SUCCESS; +} + +/****************************************************************************** + * TvDeviceStart + * + * Description: + * Initializes the UPnP Sdk, registers the device, and sends out + * advertisements. + * + * Parameters: + * + * ip_address - ip address to initialize the sdk (may be NULL) + * if null, then the first non null loopback address is used. + * port - port number to initialize the sdk (may be 0) + * if zero, then a random number is used. + * desc_doc_name - name of description document. + * may be NULL. Default is tvcombodesc.xml + * web_dir_path - path of web directory. + * may be NULL. Default is ./web (for Linux) or ../tvdevice/web + * for windows. + * pfun - print function to use. + * + *****************************************************************************/ +int +TvDeviceStart( char *ip_address, + unsigned short port, + char *desc_doc_name, + char *web_dir_path, + print_string pfun ) +{ + int ret = UPNP_E_SUCCESS; + + char desc_doc_url[DESC_URL_SIZE]; + + ithread_mutex_init( &TVDevMutex, NULL ); + + SampleUtil_Initialize( pfun ); + + SampleUtil_Print + ( "Initializing UPnP Sdk with \n \t ipaddress = %s port = %d\n", + ip_address, port ); + + if( ( ret = UpnpInit( ip_address, port ) ) != UPNP_E_SUCCESS ) { + SampleUtil_Print( "Error with UpnpInit -- %d\n", ret ); + UpnpFinish( ); + return ret; + } + + if( ip_address == NULL ) { + ip_address = UpnpGetServerIpAddress( ); + } + + if( port == 0 ) { + port = UpnpGetServerPort( ); + } + + SampleUtil_Print( "UPnP Initialized\n \t ipaddress= %s port = %d\n", + ip_address, port ); + + if( desc_doc_name == NULL ) + desc_doc_name = "tvcombodesc.xml"; + + if( web_dir_path == NULL ) + web_dir_path = DEFAULT_WEB_DIR; + + snprintf( desc_doc_url, DESC_URL_SIZE, "http://%s:%d/%s", ip_address, + port, desc_doc_name ); + + SampleUtil_Print( "Specifying the webserver root directory -- %s\n", + web_dir_path ); + if( ( ret = + UpnpSetWebServerRootDir( web_dir_path ) ) != UPNP_E_SUCCESS ) { + SampleUtil_Print + ( "Error specifying webserver root directory -- %s: %d\n", + web_dir_path, ret ); + UpnpFinish( ); + return ret; + } + + SampleUtil_Print + ( "Registering the RootDevice\n\t with desc_doc_url: %s\n", + desc_doc_url ); + + if( ( ret = UpnpRegisterRootDevice( desc_doc_url, + TvDeviceCallbackEventHandler, + &device_handle, &device_handle ) ) + != UPNP_E_SUCCESS ) { + SampleUtil_Print( "Error registering the rootdevice : %d\n", ret ); + UpnpFinish( ); + return ret; + } else { + SampleUtil_Print( "RootDevice Registered\n" ); + + SampleUtil_Print( "Initializing State Table\n" ); + TvDeviceStateTableInit( desc_doc_url ); + SampleUtil_Print( "State Table Initialized\n" ); + + if( ( ret = + UpnpSendAdvertisement( device_handle, default_advr_expire ) ) + != UPNP_E_SUCCESS ) { + SampleUtil_Print( "Error sending advertisements : %d\n", ret ); + UpnpFinish( ); + return ret; + } + + SampleUtil_Print( "Advertisements Sent\n" ); + } + return UPNP_E_SUCCESS; +} diff --git a/upnp/sample/tvcombo/upnp_tv_device.h b/upnp/sample/tvcombo/upnp_tv_device.h new file mode 100644 index 0000000..c797409 --- /dev/null +++ b/upnp/sample/tvcombo/upnp_tv_device.h @@ -0,0 +1,638 @@ +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef UPNP_TV_DEVICE_H +#define UPNP_TV_DEVICE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ithread.h" +#include +#include +#include +#include "upnp.h" +#include "sample_util.h" + +//Color constants +#define MAX_COLOR 10 +#define MIN_COLOR 1 + +//Brightness constants +#define MAX_BRIGHTNESS 10 +#define MIN_BRIGHTNESS 1 + +//Power constants +#define POWER_ON 1 +#define POWER_OFF 0 + +//Tint constants +#define MAX_TINT 10 +#define MIN_TINT 1 + +//Volume constants +#define MAX_VOLUME 10 +#define MIN_VOLUME 1 + +//Contrast constants +#define MAX_CONTRAST 10 +#define MIN_CONTRAST 1 + +//Channel constants +#define MAX_CHANNEL 100 +#define MIN_CHANNEL 1 + +//Number of services. +#define TV_SERVICE_SERVCOUNT 2 + +//Index of control service +#define TV_SERVICE_CONTROL 0 + +//Index of picture service +#define TV_SERVICE_PICTURE 1 + +//Number of control variables +#define TV_CONTROL_VARCOUNT 3 + +//Index of power variable +#define TV_CONTROL_POWER 0 + +//Index of channel variable +#define TV_CONTROL_CHANNEL 1 + +//Index of volume variable +#define TV_CONTROL_VOLUME 2 + +//Number of picture variables +#define TV_PICTURE_VARCOUNT 4 + +//Index of color variable +#define TV_PICTURE_COLOR 0 + +//Index of tint variable +#define TV_PICTURE_TINT 1 + +//Index of contrast variable +#define TV_PICTURE_CONTRAST 2 + +//Index of brightness variable +#define TV_PICTURE_BRIGHTNESS 3 + +//Max value length +#define TV_MAX_VAL_LEN 5 + +//Max actions +#define TV_MAXACTIONS 12 + +/* This should be the maximum VARCOUNT from above */ +#define TV_MAXVARS TV_PICTURE_VARCOUNT + + +extern char TvDeviceType[]; + +extern char *TvServiceType[]; + + + +/****************************************************************************** + * upnp_action + * + * Description: + * Prototype for all actions. For each action that a service + * implements, there is a corresponding function with this prototype. + * Pointers to these functions, along with action names, are stored + * in the service table. When an action request comes in the action + * name is matched, and the appropriate function is called. + * Each function returns UPNP_E_SUCCESS, on success, and a nonzero + * error code on failure. + * + * Parameters: + * + * IXML_Document * request - document of action request + * IXML_Document **out - action result + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ + +typedef int (*upnp_action) (IXML_Document *request, IXML_Document **out, + char **errorString); + +/* Structure for storing Tv Service + identifiers and state table */ +struct TvService { + + char UDN[NAME_SIZE]; /* Universally Unique Device Name */ + char ServiceId[NAME_SIZE]; + char ServiceType[NAME_SIZE]; + char *VariableName[TV_MAXVARS]; + char *VariableStrVal[TV_MAXVARS]; + char *ActionNames[TV_MAXACTIONS]; + upnp_action actions[TV_MAXACTIONS]; + unsigned int VariableCount; +}; + +//Array of service structures +extern struct TvService tv_service_table[]; + +//Device handle returned from sdk +extern UpnpDevice_Handle device_handle; + + +/* Mutex for protecting the global state table data + in a multi-threaded, asynchronous environment. + All functions should lock this mutex before reading + or writing the state table data. */ +extern ithread_mutex_t TVDevMutex; + + + +/****************************************************************************** + * SetActionTable + * + * Description: + * Initializes the action table for the specified service. + * Note that + * knowledge of the service description is + * assumed. Action names are hardcoded. + * Parameters: + * int serviceType - one of TV_SERVICE_CONTROL or, TV_SERVICE_PICTURE + * struct TvService *out - service containing action table to set. + * + *****************************************************************************/ +int SetActionTable(int serviceType, struct TvService * out); + +/****************************************************************************** + * TvDeviceStateTableInit + * + * Description: + * Initialize the device state table for + * this TvDevice, pulling identifier info + * from the description Document. Note that + * knowledge of the service description is + * assumed. State table variables and default + * values are currently hardcoded in this file + * rather than being read from service description + * documents. + * + * Parameters: + * DescDocURL -- The description document URL + * + *****************************************************************************/ +int TvDeviceStateTableInit(char*); + + +/****************************************************************************** + * TvDeviceHandleSubscriptionRequest + * + * Description: + * Called during a subscription request callback. If the + * subscription request is for this device and either its + * control service or picture service, then accept it. + * + * Parameters: + * sr_event -- The subscription request event structure + * + *****************************************************************************/ +int TvDeviceHandleSubscriptionRequest(struct Upnp_Subscription_Request *); + +/****************************************************************************** + * TvDeviceHandleGetVarRequest + * + * Description: + * Called during a get variable request callback. If the + * request is for this device and either its control service + * or picture service, then respond with the variable value. + * + * Parameters: + * cgv_event -- The control get variable request event structure + * + *****************************************************************************/ +int TvDeviceHandleGetVarRequest(struct Upnp_State_Var_Request *); + +/****************************************************************************** + * TvDeviceHandleActionRequest + * + * Description: + * Called during an action request callback. If the + * request is for this device and either its control service + * or picture service, then perform the action and respond. + * + * Parameters: + * ca_event -- The control action request event structure + * + *****************************************************************************/ +int TvDeviceHandleActionRequest(struct Upnp_Action_Request *); + +/****************************************************************************** + * TvDeviceCallbackEventHandler + * + * Description: + * The callback handler registered with the SDK while registering + * root device. Dispatches the request to the appropriate procedure + * based on the value of EventType. The four requests handled by the + * device are: + * 1) Event Subscription requests. + * 2) Get Variable requests. + * 3) Action requests. + * + * Parameters: + * + * EventType -- The type of callback event + * Event -- Data structure containing event data + * Cookie -- Optional data specified during callback registration + * + *****************************************************************************/ +int TvDeviceCallbackEventHandler(Upnp_EventType, void*, void*); + +/****************************************************************************** + * TvDeviceSetServiceTableVar + * + * Description: + * Update the TvDevice service state table, and notify all subscribed + * control points of the updated state. Note that since this function + * blocks on the mutex TVDevMutex, to avoid a hang this function should + * not be called within any other function that currently has this mutex + * locked. + * + * Parameters: + * service -- The service number (TV_SERVICE_CONTROL or TV_SERVICE_PICTURE) + * variable -- The variable number (TV_CONTROL_POWER, TV_CONTROL_CHANNEL, + * TV_CONTROL_VOLUME, TV_PICTURE_COLOR, TV_PICTURE_TINT, + * TV_PICTURE_CONTRAST, or TV_PICTURE_BRIGHTNESS) + * value -- The string representation of the new value + * + *****************************************************************************/ +int TvDeviceSetServiceTableVar(unsigned int, unsigned int, char*); + +//Control Service Actions + +/****************************************************************************** + * TvDevicePowerOn + * + * Description: + * Turn the power on. + * + * Parameters: + * + * IXML_Document * in - document of action request + * IXML_Document **out - action result + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDevicePowerOn(IN IXML_Document * in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDevicePowerOff + * + * Description: + * Turn the power off. + * + * Parameters: + * + * IXML_Document * in - document of action request + * IXML_Document **out - action result + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDevicePowerOff(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceSetChannel + * + * Description: + * Change the channel, update the TvDevice control service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceSetChannel(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceIncreaseChannel + * + * Description: + * Increase the channel. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceIncreaseChannel(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); +/****************************************************************************** + * TvDeviceDecreaseChannel + * + * Description: + * Decrease the channel. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceDecreaseChannel(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); +/****************************************************************************** + * TvDeviceSetVolume + * + * Description: + * Change the volume, update the TvDevice control service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceSetVolume(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceIncreaseVolume + * + * Description: + * Increase the volume. + * + * Parameters: + * + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int TvDeviceIncreaseVolume(IN IXML_Document *in, OUT IXML_Document**out, + OUT char **errorString); + + +/****************************************************************************** + * TvDeviceDecreaseVolume + * + * Description: + * Decrease the volume. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceDecreaseVolume(IN IXML_Document *in, OUT IXML_Document**out, + OUT char **errorString); + + +//Picture Service Actions + +/****************************************************************************** + * TvDeviceSetColor + * + * Description: + * Change the color, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceSetColor(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + + +/****************************************************************************** + * TvDeviceIncreaseColor + * + * Description: + * Increase the color. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int TvDeviceIncreaseColor(IN IXML_Document * in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceDecreaseColor + * + * Description: + * Decrease the color. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + *****************************************************************************/ +int TvDeviceDecreaseColor(IN IXML_Document * in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceSetTint + * + * Description: + * Change the tint, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceSetTint(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceIncreaseTint + * + * Description: + * Increase tint. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceIncreaseTint(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceDecreaseTint + * + * Description: + * Decrease tint. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceDecreaseTint(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/***************************************************************************** + * TvDeviceSetContrast + * + * Description: + * Change the contrast, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + ****************************************************************************/ +int TvDeviceSetContrast(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceIncreaseContrast + * + * Description: + * + * Increase the contrast. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceIncreaseContrast(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); +/****************************************************************************** + * TvDeviceDecreaseContrast + * + * Description: + * Decrease the contrast. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceDecreaseContrast(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceSetBrightness + * + * Description: + * Change the brightness, update the TvDevice picture service + * state table, and notify all subscribed control points of the + * updated state. + * + * Parameters: + * brightness -- The brightness value to change to. + * + *****************************************************************************/ +int TvDeviceSetBrightness(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceIncreaseBrightness + * + * Description: + * Increase brightness. + * + * Parameters: + * + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceIncreaseBrightness(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +/****************************************************************************** + * TvDeviceDecreaseBrightness + * + * Description: + * Decrease brightnesss. + * + * Parameters: + * IXML_Document * in - action request document + * IXML_Document **out - action result document + * char **errorString - errorString (in case action was unsuccessful) + * + *****************************************************************************/ +int TvDeviceDecreaseBrightness(IN IXML_Document *in, OUT IXML_Document **out, + OUT char **errorString); + +int TvDeviceStart(char * ip_address, unsigned short port,char * desc_doc_name, + char *web_dir_path, print_string pfun); +int TvDeviceStop(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/upnp/sample/web/tvcombodesc.xml b/upnp/sample/web/tvcombodesc.xml new file mode 100644 index 0000000..e14d854 --- /dev/null +++ b/upnp/sample/web/tvcombodesc.xml @@ -0,0 +1,37 @@ + + + + 1 + 0 + + + urn:schemas-upnp-org:device:tvdevice:1 + UPnP Television Emulator + TV Manufacturer Name + http://www.manufacturer.com + UPnP Television Device Emulator 1.0 + TVEmulator + 1.0 + http://www.manufacturer.com/TVEmulator/ + 123456789001 + uuid:Upnp-TVEmulator-1_0-1234567890001 + 123456789 + + + urn:schemas-upnp-org:service:tvcontrol:1 + urn:upnp-org:serviceId:tvcontrol1 + /upnp/control/tvcontrol1 + /upnp/event/tvcontrol1 + /tvcontrolSCPD.xml + + + urn:schemas-upnp-org:service:tvpicture:1 + urn:upnp-org:serviceId:tvpicture1 + /upnp/control/tvpicture1 + /upnp/event/tvpicture1 + /tvpictureSCPD.xml + + + /tvdevicepres.html + +