1291 lines
41 KiB
C
1291 lines
41 KiB
C
/*******************************************************************************
|
|
*
|
|
* 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 "tv_ctrlpt.h"
|
|
|
|
#include "upnp.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;
|
|
|
|
const char TvDeviceType[] = "urn:schemas-upnp-org:device:tvdevice:1";
|
|
const char *TvServiceType[] = {
|
|
"urn:schemas-upnp-org:service:tvcontrol:1",
|
|
"urn:schemas-upnp-org:service:tvpicture:1"
|
|
};
|
|
const char *TvServiceName[] = { "Control", "Picture" };
|
|
|
|
/*!
|
|
Global arrays for storing variable names and counts for
|
|
TvControl and TvPicture services
|
|
*/
|
|
const 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\n");
|
|
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\n",
|
|
TvServiceName[service],
|
|
node->device.TvService[service].SID );
|
|
} else {
|
|
SampleUtil_Print
|
|
( "Error unsubscribing to Tv %s EventURL -- %d\n",
|
|
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(const char *UDN)
|
|
{
|
|
struct TvDeviceNode *curdevnode;
|
|
struct TvDeviceNode *prevdevnode;
|
|
|
|
ithread_mutex_lock( &DeviceListMutex );
|
|
|
|
curdevnode = GlobalDeviceList;
|
|
if( !curdevnode ) {
|
|
SampleUtil_Print("WARNING: TvCtrlPointRemoveDevice: Device list empty\n");
|
|
} 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\n", 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, const 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\n", 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,
|
|
const char *actionname,
|
|
const 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\n");
|
|
/*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\n", 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,
|
|
const char *actionName,
|
|
const 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\n", 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:\n");
|
|
tmpdevnode = GlobalDeviceList;
|
|
while( tmpdevnode ) {
|
|
SampleUtil_Print( " %3d -- %s\n", ++i, tmpdevnode->device.UDN );
|
|
tmpdevnode = tmpdevnode->next;
|
|
}
|
|
SampleUtil_Print("\n");
|
|
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\n", devnum);
|
|
return TV_ERROR;
|
|
}
|
|
|
|
ithread_mutex_lock( &DeviceListMutex );
|
|
|
|
SampleUtil_Print("TvCtrlPointPrintDevice:\n");
|
|
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\n", devnum, i);
|
|
} else {
|
|
SampleUtil_Print(" TvDevice -- %d\n", devnum);
|
|
SampleUtil_Print(" | \n");
|
|
SampleUtil_Print(" +- UDN = %s\n" , tmpdevnode->device.UDN);
|
|
SampleUtil_Print(" +- DescDocURL = %s\n", tmpdevnode->device.DescDocURL);
|
|
SampleUtil_Print(" +- FriendlyName = %s\n", tmpdevnode->device.FriendlyName);
|
|
SampleUtil_Print(" +- PresURL = %s\n", tmpdevnode->device.PresURL);
|
|
SampleUtil_Print(" +- Adver. TimeOut = %d\n", 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\n", spacer, tmpdevnode->device.TvService[service].ServiceId);
|
|
SampleUtil_Print("%s+- ServiceType = %s\n", spacer, tmpdevnode->device.TvService[service].ServiceType);
|
|
SampleUtil_Print("%s+- EventURL = %s\n", spacer, tmpdevnode->device.TvService[service].EventURL);
|
|
SampleUtil_Print("%s+- ControlURL = %s\n", spacer, tmpdevnode->device.TvService[service].ControlURL);
|
|
SampleUtil_Print("%s+- SID = %s\n", spacer, tmpdevnode->device.TvService[service].SID);
|
|
SampleUtil_Print("%s+- ServiceStateTable", spacer);
|
|
for( var = 0; var < TvVarCount[service]; var++ ) {
|
|
SampleUtil_Print("%s +- %-10s = %s\n", spacer, TvVarName[service][var],
|
|
tmpdevnode->device.TvService[service].VariableStrVal[var]);
|
|
}
|
|
}
|
|
}
|
|
SampleUtil_Print("\n");
|
|
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,
|
|
const 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;
|
|
int 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\n", baseURL, relURL );
|
|
|
|
if( strcmp( deviceType, TvDeviceType ) == 0 ) {
|
|
SampleUtil_Print("Found Tv device\n");
|
|
|
|
/* 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...\n", 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\n", eventSID[service]);
|
|
} else {
|
|
SampleUtil_Print("Error Subscribing to EventURL -- %d\n", ret);
|
|
strcpy(eventSID[service], "");
|
|
}
|
|
} else {
|
|
SampleUtil_Print("Error: Could not find Service: %s\n", 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):\n", 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'\n", 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(
|
|
const char *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\n",
|
|
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(
|
|
const char *eventURL,
|
|
const 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\n", TvServiceName[service], eventURL );
|
|
strcpy( tmpdevnode->device.TvService[service].SID, sid );
|
|
break;
|
|
}
|
|
}
|
|
|
|
tmpdevnode = tmpdevnode->next;
|
|
}
|
|
|
|
ithread_mutex_unlock( &DeviceListMutex );
|
|
}
|
|
|
|
void TvCtrlPointHandleGetVar(
|
|
const char *controlURL,
|
|
const char *varName,
|
|
const 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)
|
|
{
|
|
/*int errCode = 0;*/
|
|
|
|
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\n",
|
|
d_event->ErrCode);
|
|
}
|
|
ret = UpnpDownloadXmlDoc(d_event->Location, &DescDoc);
|
|
if (ret != UPNP_E_SUCCESS) {
|
|
SampleUtil_Print("Error obtaining device description from %s -- error = %d\n",
|
|
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\n",
|
|
d_event->ErrCode);
|
|
}
|
|
SampleUtil_Print("Received ByeBye for Device: %s\n", d_event->DeviceId);
|
|
TvCtrlPointRemoveDevice(d_event->DeviceId);
|
|
SampleUtil_Print("After byebye:\n");
|
|
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\n",
|
|
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\n",
|
|
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\n",
|
|
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: {
|
|
struct Upnp_Event_Subscribe *es_event = (struct Upnp_Event_Subscribe *)Event;
|
|
int TimeOut = default_timeout;
|
|
Upnp_SID newSID;
|
|
int ret;
|
|
|
|
ret = UpnpSubscribe(
|
|
ctrlpt_handle,
|
|
es_event->PublisherUrl,
|
|
&TimeOut,
|
|
newSID);
|
|
if (ret == UPNP_E_SUCCESS) {
|
|
SampleUtil_Print("Subscribed to EventURL with SID=%s\n", newSID);
|
|
TvCtrlPointHandleSubscribeUpdate(
|
|
es_event->PublisherUrl,
|
|
newSID,
|
|
TimeOut);
|
|
} else {
|
|
SampleUtil_Print("Error Subscribing to EventURL -- %d\n", 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\n",
|
|
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
|
|
*
|
|
********************************************************************************/
|
|
static int TvCtrlPointTimerLoopRun = 1;
|
|
void *TvCtrlPointTimerLoop(void *args)
|
|
{
|
|
int incr = 30; /* how often to verify the timeouts, in seconds */
|
|
|
|
while (TvCtrlPointTimerLoopRun) {
|
|
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;
|
|
unsigned short port = 0;
|
|
char *ip_address = NULL;
|
|
|
|
SampleUtil_Initialize(printFunctionPtr);
|
|
SampleUtil_RegisterUpdateFunction(updateFunctionPtr);
|
|
|
|
ithread_mutex_init(&DeviceListMutex, 0);
|
|
|
|
SampleUtil_Print(
|
|
"Initializing UPnP Sdk with\n"
|
|
"\tipaddress = %s port = %u\n",
|
|
ip_address ? ip_address : "{NULL}",
|
|
port);
|
|
|
|
rc = UpnpInit(ip_address, port);
|
|
if (rc != UPNP_E_SUCCESS) {
|
|
SampleUtil_Print("WinCEStart: UpnpInit() Error: %d\n", rc);
|
|
UpnpFinish();
|
|
return TV_ERROR;
|
|
}
|
|
if (!ip_address) {
|
|
ip_address = UpnpGetServerIpAddress();
|
|
}
|
|
if (!port) {
|
|
port = UpnpGetServerPort();
|
|
}
|
|
|
|
SampleUtil_Print(
|
|
"UPnP Initialized\n"
|
|
"\tipaddress = %s port = %u\n",
|
|
ip_address ? ip_address : "{NULL}",
|
|
port);
|
|
SampleUtil_Print("Registering Control Point\n");
|
|
rc = UpnpRegisterClient(TvCtrlPointCallbackEventHandler,
|
|
&ctrlpt_handle, &ctrlpt_handle);
|
|
if (rc != UPNP_E_SUCCESS) {
|
|
SampleUtil_Print( "Error registering CP: %d\n", rc );
|
|
UpnpFinish();
|
|
|
|
return TV_ERROR;
|
|
}
|
|
|
|
SampleUtil_Print("Control Point Registered\n");
|
|
|
|
TvCtrlPointRefresh();
|
|
|
|
/* start a timer thread */
|
|
ithread_create(&timer_thread, NULL, TvCtrlPointTimerLoop, NULL);
|
|
ithread_detach(timer_thread);
|
|
|
|
return TV_SUCCESS;
|
|
}
|
|
|
|
int TvCtrlPointStop(void)
|
|
{
|
|
TvCtrlPointTimerLoopRun = 0;
|
|
TvCtrlPointRemoveAll();
|
|
UpnpUnRegisterClient( ctrlpt_handle );
|
|
UpnpFinish();
|
|
SampleUtil_Finish();
|
|
|
|
return TV_SUCCESS;
|
|
}
|
|
|