pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / sample / tvdevice / upnp_tv_device.c
1 /*******************************************************************************
2  *
3  * Copyright (c) 2000-2003 Intel Corporation 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met: 
8  *
9  * - Redistributions of source code must retain the above copyright notice, 
10  * this list of conditions and the following disclaimer. 
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  * this list of conditions and the following disclaimer in the documentation 
13  * and/or other materials provided with the distribution. 
14  * - Neither name of Intel Corporation nor the names of its contributors 
15  * may be used to endorse or promote products derived from this software 
16  * without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  ******************************************************************************/
31
32
33 #include "upnp_tv_device.h"
34
35
36 #include <assert.h>
37
38
39 #define DEFAULT_WEB_DIR "./web"
40
41
42 #define DESC_URL_SIZE 200
43
44
45 /*
46    Device type for tv device 
47  */
48 char TvDeviceType[] = "urn:schemas-upnp-org:device:tvdevice:1";
49
50 /*
51    Service types for tv services
52  */
53 char *TvServiceType[] = { "urn:schemas-upnp-org:service:tvcontrol:1",
54     "urn:schemas-upnp-org:service:tvpicture:1"
55 };
56
57 /*
58    Global arrays for storing Tv Control Service
59    variable names, values, and defaults 
60  */
61 char *tvc_varname[] = { "Power", "Channel", "Volume" };
62 char tvc_varval[TV_CONTROL_VARCOUNT][TV_MAX_VAL_LEN];
63 char *tvc_varval_def[] = { "1", "1", "5" };
64
65 /*
66    Global arrays for storing Tv Picture Service
67    variable names, values, and defaults 
68  */
69 char *tvp_varname[] = { "Color", "Tint", "Contrast", "Brightness" };
70 char tvp_varval[TV_PICTURE_VARCOUNT][TV_MAX_VAL_LEN];
71 char *tvp_varval_def[] = { "5", "5", "5", "5" };
72
73 /*
74    The amount of time (in seconds) before advertisements
75    will expire 
76  */
77 int default_advr_expire = 100;
78
79 /*
80    Global structure for storing the state table for this device 
81  */
82 struct TvService tv_service_table[2];
83
84 /*
85    Device handle supplied by UPnP SDK 
86  */
87 UpnpDevice_Handle device_handle = -1;
88
89 /*
90    Mutex for protecting the global state table data
91    in a multi-threaded, asynchronous environment.
92    All functions should lock this mutex before reading
93    or writing the state table data. 
94  */
95 ithread_mutex_t TVDevMutex;
96
97 //Color constants
98 #define MAX_COLOR 10
99 #define MIN_COLOR 1
100
101 //Brightness constants
102 #define MAX_BRIGHTNESS 10
103 #define MIN_BRIGHTNESS 1
104
105 //Power constants
106 #define POWER_ON 1
107 #define POWER_OFF 0
108
109 //Tint constants
110 #define MAX_TINT 10
111 #define MIN_TINT 1
112
113 //Volume constants
114 #define MAX_VOLUME 10
115 #define MIN_VOLUME 1
116
117 //Contrast constants
118 #define MAX_CONTRAST 10
119 #define MIN_CONTRAST 1
120
121 //Channel constants
122 #define MAX_CHANNEL 100
123 #define MIN_CHANNEL 1
124
125 /******************************************************************************
126  * SetServiceTable
127  *
128  * Description: 
129  *       Initializes the service table for the specified service.
130  *       Note that 
131  *       knowledge of the service description is
132  *       assumed. 
133  * Parameters:
134  *   int serviceType - one of TV_SERVICE_CONTROL or, TV_SERVICE_PICTURE
135  *   const char * UDN - UDN of device containing service
136  *   const char * serviceId - serviceId of service
137  *   const char * serviceTypeS - service type (as specified in Description
138  *                                             Document) 
139  *   struct TvService *out - service containing table to be set.
140  *
141  *****************************************************************************/
142 int
143 SetServiceTable( IN int serviceType,
144                  IN const char *UDN,
145                  IN const char *serviceId,
146                  IN const char *serviceTypeS,
147                  INOUT struct TvService *out )
148 {
149     unsigned int i = 0;
150
151     strcpy( out->UDN, UDN );
152     strcpy( out->ServiceId, serviceId );
153     strcpy( out->ServiceType, serviceTypeS );
154
155     switch ( serviceType ) {
156         case TV_SERVICE_CONTROL:
157             out->VariableCount = TV_CONTROL_VARCOUNT;
158             for( i = 0;
159                  i < tv_service_table[TV_SERVICE_CONTROL].VariableCount;
160                  i++ ) {
161                 tv_service_table[TV_SERVICE_CONTROL].VariableName[i]
162                     = tvc_varname[i];
163                 tv_service_table[TV_SERVICE_CONTROL].VariableStrVal[i]
164                     = tvc_varval[i];
165                 strcpy( tv_service_table[TV_SERVICE_CONTROL].
166                         VariableStrVal[i], tvc_varval_def[i] );
167             }
168
169             break;
170         case TV_SERVICE_PICTURE:
171             out->VariableCount = TV_PICTURE_VARCOUNT;
172
173             for( i = 0;
174                  i < tv_service_table[TV_SERVICE_PICTURE].VariableCount;
175                  i++ ) {
176                 tv_service_table[TV_SERVICE_PICTURE].VariableName[i] =
177                     tvp_varname[i];
178                 tv_service_table[TV_SERVICE_PICTURE].VariableStrVal[i] =
179                     tvp_varval[i];
180                 strcpy( tv_service_table[TV_SERVICE_PICTURE].
181                         VariableStrVal[i], tvp_varval_def[i] );
182             }
183
184             break;
185         default:
186             assert( 0 );
187     }
188
189     return SetActionTable( serviceType, out );
190 }
191
192 /******************************************************************************
193  * SetActionTable
194  *
195  * Description: 
196  *       Initializes the action table for the specified service.
197  *       Note that 
198  *       knowledge of the service description is
199  *       assumed.  Action names are hardcoded.
200  * Parameters:
201  *   int serviceType - one of TV_SERVICE_CONTROL or, TV_SERVICE_PICTURE
202  *   struct TvService *out - service containing action table to set.
203  *
204  *****************************************************************************/
205 int
206 SetActionTable( IN int serviceType,
207                 INOUT struct TvService *out )
208 {
209     if( serviceType == TV_SERVICE_CONTROL ) {
210         out->ActionNames[0] = "PowerOn";
211         out->actions[0] = TvDevicePowerOn;
212         out->ActionNames[1] = "PowerOff";
213         out->actions[1] = TvDevicePowerOff;
214         out->ActionNames[2] = "SetChannel";
215         out->actions[2] = TvDeviceSetChannel;
216         out->ActionNames[3] = "IncreaseChannel";
217         out->actions[3] = TvDeviceIncreaseChannel;
218         out->ActionNames[4] = "DecreaseChannel";
219         out->actions[4] = TvDeviceDecreaseChannel;
220         out->ActionNames[5] = "SetVolume";
221         out->actions[5] = TvDeviceSetVolume;
222         out->ActionNames[6] = "IncreaseVolume";
223         out->actions[6] = TvDeviceIncreaseVolume;
224         out->ActionNames[7] = "DecreaseVolume";
225         out->actions[7] = TvDeviceDecreaseVolume;
226         out->ActionNames[8] = NULL;
227         return 1;
228     } else if( serviceType == TV_SERVICE_PICTURE ) {
229         out->ActionNames[0] = "SetColor";
230         out->ActionNames[1] = "IncreaseColor";
231         out->ActionNames[2] = "DecreaseColor";
232         out->actions[0] = TvDeviceSetColor;
233         out->actions[1] = TvDeviceIncreaseColor;
234         out->actions[2] = TvDeviceDecreaseColor;
235         out->ActionNames[3] = "SetTint";
236         out->ActionNames[4] = "IncreaseTint";
237         out->ActionNames[5] = "DecreaseTint";
238         out->actions[3] = TvDeviceSetTint;
239         out->actions[4] = TvDeviceIncreaseTint;
240         out->actions[5] = TvDeviceDecreaseTint;
241
242         out->ActionNames[6] = "SetBrightness";
243         out->ActionNames[7] = "IncreaseBrightness";
244         out->ActionNames[8] = "DecreaseBrightness";
245         out->actions[6] = TvDeviceSetBrightness;
246         out->actions[7] = TvDeviceIncreaseBrightness;
247         out->actions[8] = TvDeviceDecreaseBrightness;
248
249         out->ActionNames[9] = "SetContrast";
250         out->ActionNames[10] = "IncreaseContrast";
251         out->ActionNames[11] = "DecreaseContrast";
252
253         out->actions[9] = TvDeviceSetContrast;
254         out->actions[10] = TvDeviceIncreaseContrast;
255         out->actions[11] = TvDeviceDecreaseContrast;
256         return 1;
257     }
258
259     return 0;
260 }
261
262 /******************************************************************************
263  * TvDeviceStateTableInit
264  *
265  * Description: 
266  *       Initialize the device state table for 
267  *       this TvDevice, pulling identifier info
268  *       from the description Document.  Note that 
269  *       knowledge of the service description is
270  *       assumed.  State table variables and default
271  *       values are currently hardcoded in this file
272  *       rather than being read from service description
273  *       documents.
274  *
275  * Parameters:
276  *   DescDocURL -- The description document URL
277  *
278  *****************************************************************************/
279 int
280 TvDeviceStateTableInit( IN char *DescDocURL )
281 {
282     IXML_Document *DescDoc = NULL;
283     int ret = UPNP_E_SUCCESS;
284     char *servid_ctrl = NULL,
285      *evnturl_ctrl = NULL,
286      *ctrlurl_ctrl = NULL;
287     char *servid_pict = NULL,
288      *evnturl_pict = NULL,
289      *ctrlurl_pict = NULL;
290     char *udn = NULL;
291
292     //Download description document
293     if( UpnpDownloadXmlDoc( DescDocURL, &DescDoc ) != UPNP_E_SUCCESS ) {
294         SampleUtil_Print( "TvDeviceStateTableInit -- Error Parsing %s\n",
295                           DescDocURL );
296         ret = UPNP_E_INVALID_DESC;
297         goto error_handler;
298     }
299
300     udn = SampleUtil_GetFirstDocumentItem( DescDoc, "UDN" );
301
302     /*
303        Find the Tv Control Service identifiers 
304      */
305     if( !SampleUtil_FindAndParseService( DescDoc, DescDocURL,
306                                          TvServiceType[TV_SERVICE_CONTROL],
307                                          &servid_ctrl, &evnturl_ctrl,
308                                          &ctrlurl_ctrl ) ) {
309         SampleUtil_Print( "TvDeviceStateTableInit -- Error: Could not find"
310                           " Service: %s\n",
311                           TvServiceType[TV_SERVICE_CONTROL] );
312
313         ret = UPNP_E_INVALID_DESC;
314         goto error_handler;
315     }
316
317     //set control service table
318     SetServiceTable( TV_SERVICE_CONTROL, udn, servid_ctrl,
319                      TvServiceType[TV_SERVICE_CONTROL],
320                      &tv_service_table[TV_SERVICE_CONTROL] );
321
322     /*
323        Find the Tv Picture Service identifiers 
324      */
325     if( !SampleUtil_FindAndParseService( DescDoc, DescDocURL,
326                                          TvServiceType[TV_SERVICE_PICTURE],
327                                          &servid_pict, &evnturl_pict,
328                                          &ctrlurl_pict ) ) {
329         SampleUtil_Print( "TvDeviceStateTableInit -- Error: Could not find"
330                           " Service: %s\n",
331                           TvServiceType[TV_SERVICE_PICTURE] );
332
333         ret = UPNP_E_INVALID_DESC;
334         goto error_handler;
335     }
336     //set picture service table
337     SetServiceTable( TV_SERVICE_PICTURE, udn, servid_pict,
338                      TvServiceType[TV_SERVICE_PICTURE],
339                      &tv_service_table[TV_SERVICE_PICTURE] );
340
341   error_handler:
342
343     //clean up
344     if( udn )
345         free( udn );
346     if( servid_ctrl )
347         free( servid_ctrl );
348     if( evnturl_ctrl )
349         free( evnturl_ctrl );
350     if( ctrlurl_ctrl )
351         free( ctrlurl_ctrl );
352     if( servid_pict )
353         free( servid_pict );
354     if( evnturl_pict )
355         free( evnturl_pict );
356     if( ctrlurl_pict )
357         free( ctrlurl_pict );
358     if( DescDoc )
359         ixmlDocument_free( DescDoc );
360
361     return ( ret );
362 }
363
364 /******************************************************************************
365  * TvDeviceHandleSubscriptionRequest
366  *
367  * Description: 
368  *       Called during a subscription request callback.  If the
369  *       subscription request is for this device and either its
370  *       control service or picture service, then accept it.
371  *
372  * Parameters:
373  *   sr_event -- The subscription request event structure
374  *
375  *****************************************************************************/
376 int
377 TvDeviceHandleSubscriptionRequest( IN struct Upnp_Subscription_Request
378                                    *sr_event )
379 {
380     unsigned int i = 0;         //,j=0;
381
382         // IXML_Document *PropSet = NULL;
383
384         // lock state mutex
385         ithread_mutex_lock( &TVDevMutex );
386
387     for( i = 0; i < TV_SERVICE_SERVCOUNT; i++ ) {
388         if( ( strcmp( sr_event->UDN, tv_service_table[i].UDN ) == 0 ) &&
389             ( strcmp( sr_event->ServiceId, tv_service_table[i].ServiceId )
390               == 0 ) ) {
391
392             /*
393                         PropSet = NULL;
394
395                         for (j = 0; j< tv_service_table[i].VariableCount; ++j) {
396                                 // add each variable to the property set
397                                 // for initial state dump
398                                 UpnpAddToPropertySet(
399                                         &PropSet, 
400                                         tv_service_table[i].VariableName[j],
401                                         tv_service_table[i].VariableStrVal[j]);
402                         }
403
404                         // dump initial state 
405                         UpnpAcceptSubscriptionExt(
406                                 device_handle,
407                                 sr_event->UDN, 
408                                 sr_event->ServiceId,
409                                 PropSet,
410                                 sr_event->Sid);
411                         // free document
412                         Document_free(PropSet);
413
414              */
415
416                         UpnpAcceptSubscription( device_handle,
417                                 sr_event->UDN,
418                                 sr_event->ServiceId,
419                                 (const char **)tv_service_table[i].
420                                 VariableName,
421                                 (const char **)tv_service_table[i].
422                                 VariableStrVal,
423                                 tv_service_table[i].VariableCount,
424                                 sr_event->Sid);
425
426                 }
427         }
428
429         ithread_mutex_unlock( &TVDevMutex );
430
431         return 1;
432 }
433
434
435 /******************************************************************************
436  * TvDeviceHandleGetVarRequest
437  *
438  * Description: 
439  *       Called during a get variable request callback.  If the
440  *       request is for this device and either its control service
441  *       or picture service, then respond with the variable value.
442  *
443  * Parameters:
444  *   cgv_event -- The control get variable request event structure
445  *
446  *****************************************************************************/
447 int
448 TvDeviceHandleGetVarRequest( INOUT struct Upnp_State_Var_Request
449                              *cgv_event )
450 {
451     unsigned int i = 0;
452     unsigned int j = 0;
453     int getvar_succeeded = 0;
454
455     cgv_event->CurrentVal = NULL;
456
457     ithread_mutex_lock( &TVDevMutex );
458
459     for( i = 0; i < TV_SERVICE_SERVCOUNT; i++ ) {
460         // check udn and service id
461         if( ( strcmp( cgv_event->DevUDN, tv_service_table[i].UDN ) == 0 )
462             &&
463             ( strcmp( cgv_event->ServiceID, tv_service_table[i].ServiceId )
464               == 0 ) ) {
465             // check variable name
466             for( j = 0; j < tv_service_table[i].VariableCount; j++ ) {
467                 if( strcmp( cgv_event->StateVarName,
468                             tv_service_table[i].VariableName[j] ) == 0 ) {
469                     getvar_succeeded = 1;
470                     cgv_event->CurrentVal =
471                         ixmlCloneDOMString( tv_service_table[i].
472                                             VariableStrVal[j] );
473                     break;
474                 }
475             }
476         }
477     }
478
479     if( getvar_succeeded ) {
480         cgv_event->ErrCode = UPNP_E_SUCCESS;
481     } else {
482         SampleUtil_Print
483             ( "Error in UPNP_CONTROL_GET_VAR_REQUEST callback:\n" );
484         SampleUtil_Print( "   Unknown variable name = %s\n",
485                           cgv_event->StateVarName );
486         cgv_event->ErrCode = 404;
487         strcpy( cgv_event->ErrStr, "Invalid Variable" );
488     }
489
490     ithread_mutex_unlock( &TVDevMutex );
491
492     return ( cgv_event->ErrCode == UPNP_E_SUCCESS );
493 }
494
495 /******************************************************************************
496  * TvDeviceHandleActionRequest
497  *
498  * Description: 
499  *       Called during an action request callback.  If the
500  *       request is for this device and either its control service
501  *       or picture service, then perform the action and respond.
502  *
503  * Parameters:
504  *   ca_event -- The control action request event structure
505  *
506  *****************************************************************************/
507 int
508 TvDeviceHandleActionRequest( INOUT struct Upnp_Action_Request *ca_event )
509 {
510     /*
511        Defaults if action not found 
512      */
513     int action_found = 0;
514     int i = 0;
515     int service = -1;
516     int retCode = 0;
517     char *errorString = NULL;
518
519     ca_event->ErrCode = 0;
520     ca_event->ActionResult = NULL;
521
522     if( ( strcmp( ca_event->DevUDN,
523                   tv_service_table[TV_SERVICE_CONTROL].UDN ) == 0 ) &&
524         ( strcmp
525           ( ca_event->ServiceID,
526             tv_service_table[TV_SERVICE_CONTROL].ServiceId ) == 0 ) ) {
527         /*
528            Request for action in the TvDevice Control Service 
529          */
530         service = TV_SERVICE_CONTROL;
531     } else if( ( strcmp( ca_event->DevUDN,
532                          tv_service_table[TV_SERVICE_PICTURE].UDN ) == 0 )
533                &&
534                ( strcmp
535                  ( ca_event->ServiceID,
536                    tv_service_table[TV_SERVICE_PICTURE].ServiceId ) ==
537                  0 ) ) {
538         /*
539            Request for action in the TvDevice Picture Service 
540          */
541         service = TV_SERVICE_PICTURE;
542     }
543     //Find and call appropriate procedure based on action name
544     //Each action name has an associated procedure stored in the
545     //service table. These are set at initialization.
546
547     for( i = 0; ( ( i < TV_MAXACTIONS ) &&
548                   ( tv_service_table[service].ActionNames[i] != NULL ) );
549          i++ ) {
550
551         if( !strcmp( ca_event->ActionName,
552                      tv_service_table[service].ActionNames[i] ) ) {
553
554             if( ( !strcmp( tv_service_table[TV_SERVICE_CONTROL].
555                            VariableStrVal[TV_CONTROL_POWER], "1" ) )
556                 || ( !strcmp( ca_event->ActionName, "PowerOn" ) ) ) {
557                 retCode =
558                     tv_service_table[service].actions[i] ( ca_event->
559                                                            ActionRequest,
560                                                            &ca_event->
561                                                            ActionResult,
562                     &errorString );
563             } else {
564                 errorString = "Power is Off";
565                 retCode = UPNP_E_INTERNAL_ERROR;
566             }
567             action_found = 1;
568             break;
569         }
570     }
571
572     if( !action_found ) {
573         ca_event->ActionResult = NULL;
574         strcpy( ca_event->ErrStr, "Invalid Action" );
575         ca_event->ErrCode = 401;
576     } else {
577         if( retCode == UPNP_E_SUCCESS ) {
578             ca_event->ErrCode = UPNP_E_SUCCESS;
579         } else {
580             // copy the error string
581             strcpy( ca_event->ErrStr, errorString );
582             switch ( retCode ) {
583                 case UPNP_E_INVALID_PARAM:
584                     {
585                         ca_event->ErrCode = 402;
586                         break;
587                     }
588                 case UPNP_E_INTERNAL_ERROR:
589                 default:
590                     {
591                         ca_event->ErrCode = 501;
592                         break;
593                     }
594
595             }
596         }
597     }
598
599     return ( ca_event->ErrCode );
600 }
601
602 /******************************************************************************
603  * TvDeviceSetServiceTableVar
604  *
605  * Description: 
606  *       Update the TvDevice service state table, and notify all subscribed 
607  *       control points of the updated state.  Note that since this function
608  *       blocks on the mutex TVDevMutex, to avoid a hang this function should 
609  *       not be called within any other function that currently has this mutex 
610  *       locked.
611  *
612  * Parameters:
613  *   service -- The service number (TV_SERVICE_CONTROL or TV_SERVICE_PICTURE)
614  *   variable -- The variable number (TV_CONTROL_POWER, TV_CONTROL_CHANNEL,
615  *                   TV_CONTROL_VOLUME, TV_PICTURE_COLOR, TV_PICTURE_TINT,
616  *                   TV_PICTURE_CONTRAST, or TV_PICTURE_BRIGHTNESS)
617  *   value -- The string representation of the new value
618  *
619  *****************************************************************************/
620 int
621 TvDeviceSetServiceTableVar( IN unsigned int service,
622                             IN unsigned int variable,
623                             IN char *value )
624 {
625     //IXML_Document  *PropSet= NULL;
626
627     if( ( service >= TV_SERVICE_SERVCOUNT )
628         || ( variable >= tv_service_table[service].VariableCount )
629         || ( strlen( value ) >= TV_MAX_VAL_LEN ) ) {
630         return ( 0 );
631     }
632
633     ithread_mutex_lock( &TVDevMutex );
634
635     strcpy( tv_service_table[service].VariableStrVal[variable], value );
636
637     /*
638        //Using utility api
639        PropSet= UpnpCreatePropertySet(1,tv_service_table[service].
640        VariableName[variable], 
641        tv_service_table[service].
642        VariableStrVal[variable]);
643
644        UpnpNotifyExt(device_handle, tv_service_table[service].UDN, 
645        tv_service_table[service].ServiceId,PropSet);
646
647        //Free created property set
648        Document_free(PropSet);
649      */
650
651     UpnpNotify( device_handle,
652                 tv_service_table[service].UDN,
653                 tv_service_table[service].ServiceId,
654                 ( const char ** )&tv_service_table[service].
655                 VariableName[variable],
656                 ( const char ** )&tv_service_table[service].
657                 VariableStrVal[variable], 1 );
658
659     ithread_mutex_unlock( &TVDevMutex );
660
661     return ( 1 );
662 }
663
664 /******************************************************************************
665  * TvDeviceSetPower
666  *
667  * Description: 
668  *       Turn the power on/off, update the TvDevice control service
669  *       state table, and notify all subscribed control points of the
670  *       updated state.
671  *
672  * Parameters:
673  *   on -- If 1, turn power on.  If 0, turn power off.
674  *
675  *****************************************************************************/
676 int
677 TvDeviceSetPower( IN int on )
678 {
679     char value[TV_MAX_VAL_LEN];
680     int ret = 0;
681
682     if( on != POWER_ON && on != POWER_OFF ) {
683         SampleUtil_Print( "error: can't set power to value %d\n", on );
684         return 0;
685     }
686
687     /*
688        Vendor-specific code to turn the power on/off goes here 
689      */
690
691     sprintf( value, "%d", on );
692     ret = TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL, TV_CONTROL_POWER,
693                                       value );
694
695     return ret;
696 }
697
698 /******************************************************************************
699  * TvDevicePowerOn
700  *
701  * Description: 
702  *       Turn the power on.
703  *
704  * Parameters:
705  *
706  *    IXML_Document * in - document of action request
707  *    IXML_Document **out - action result
708  *    char **errorString - errorString (in case action was unsuccessful)
709  *
710  *****************************************************************************/
711 int
712 TvDevicePowerOn( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
713 {
714     ( *out ) = NULL;
715     ( *errorString ) = NULL;
716
717     if( TvDeviceSetPower( POWER_ON ) ) {
718         //create a response
719
720         if( UpnpAddToActionResponse( out, "PowerOn",
721                                      TvServiceType[TV_SERVICE_CONTROL],
722                                      "Power", "1" ) != UPNP_E_SUCCESS ) {
723             ( *out ) = NULL;
724             ( *errorString ) = "Internal Error";
725             return UPNP_E_INTERNAL_ERROR;
726         }
727         return UPNP_E_SUCCESS;
728     } else {
729         ( *errorString ) = "Internal Error";
730         return UPNP_E_INTERNAL_ERROR;
731     }
732 }
733
734 /******************************************************************************
735  * TvDevicePowerOff
736  *
737  * Description: 
738  *       Turn the power off.
739  *
740  * Parameters:
741  *    
742  *    IXML_Document * in - document of action request
743  *    IXML_Document **out - action result
744  *    char **errorString - errorString (in case action was unsuccessful)
745  *
746  *****************************************************************************/
747 int
748 TvDevicePowerOff( IN IXML_Document * in,
749                   OUT IXML_Document **out,
750                   OUT char **errorString )
751 {
752     ( *out ) = NULL;
753     ( *errorString ) = NULL;
754     if( TvDeviceSetPower( POWER_OFF ) ) {
755         //create a response
756
757         if( UpnpAddToActionResponse( out, "PowerOff",
758                                      TvServiceType[TV_SERVICE_CONTROL],
759                                      "Power", "0" ) != UPNP_E_SUCCESS ) {
760             ( *out ) = NULL;
761             ( *errorString ) = "Internal Error";
762             return UPNP_E_INTERNAL_ERROR;
763         }
764
765         return UPNP_E_SUCCESS;
766     }
767
768     ( *errorString ) = "Internal Error";
769     return UPNP_E_INTERNAL_ERROR;
770 }
771
772 /******************************************************************************
773  * TvDeviceSetChannel
774  *
775  * Description: 
776  *       Change the channel, update the TvDevice control service
777  *       state table, and notify all subscribed control points of the
778  *       updated state.
779  *
780  * Parameters:
781  *    
782  *    IXML_Document * in -  action request document
783  *    IXML_Document **out - action result document
784  *    char **errorString - errorString (in case action was unsuccessful)
785  *
786  *****************************************************************************/
787 int
788 TvDeviceSetChannel( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
789 {
790     char *value = NULL;
791
792     int channel = 0;
793
794     ( *out ) = NULL;
795     ( *errorString ) = NULL;
796
797     if( !( value = SampleUtil_GetFirstDocumentItem( in, "Channel" ) ) ) {
798         ( *errorString ) = "Invalid Channel";
799         return UPNP_E_INVALID_PARAM;
800     }
801
802     channel = atoi( value );
803
804     if( channel < MIN_CHANNEL || channel > MAX_CHANNEL ) {
805
806         free( value );
807         SampleUtil_Print( "error: can't change to channel %d\n", channel );
808         ( *errorString ) = "Invalid Channel";
809         return UPNP_E_INVALID_PARAM;
810     }
811
812     /*
813        Vendor-specific code to set the channel goes here 
814      */
815
816     if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL,
817                                     TV_CONTROL_CHANNEL, value ) ) {
818         if( UpnpAddToActionResponse( out, "SetChannel",
819                                      TvServiceType[TV_SERVICE_CONTROL],
820                                      "NewChannel",
821                                      value ) != UPNP_E_SUCCESS ) {
822             ( *out ) = NULL;
823             ( *errorString ) = "Internal Error";
824             free( value );
825             return UPNP_E_INTERNAL_ERROR;
826         }
827         free( value );
828         return UPNP_E_SUCCESS;
829     } else {
830         free( value );
831         ( *errorString ) = "Internal Error";
832         return UPNP_E_INTERNAL_ERROR;
833     }
834 }
835
836 /******************************************************************************
837  * IncrementChannel
838  *
839  * Description: 
840  *       Increment the channel.  Read the current channel from the state
841  *       table, add the increment, and then change the channel.
842  *
843  * Parameters:
844  *   incr -- The increment by which to change the channel.
845  *      
846  *    IXML_Document * in -  action request document
847  *    IXML_Document **out - action result document
848  *    char **errorString - errorString (in case action was unsuccessful)
849  *****************************************************************************/
850 int
851 IncrementChannel( IN int incr, IN IXML_Document * in, OUT IXML_Document **out, OUT char **errorString )
852 {
853     int curchannel;
854     int newchannel;
855
856     char *actionName = NULL;
857     char value[TV_MAX_VAL_LEN];
858
859     if( incr > 0 ) {
860         actionName = "IncreaseChannel";
861     } else {
862         actionName = "DecreaseChannel";
863     }
864
865     ithread_mutex_lock( &TVDevMutex );
866     curchannel = atoi( tv_service_table[TV_SERVICE_CONTROL].
867                        VariableStrVal[TV_CONTROL_CHANNEL] );
868     ithread_mutex_unlock( &TVDevMutex );
869
870     newchannel = curchannel + incr;
871
872     if( newchannel < MIN_CHANNEL || newchannel > MAX_CHANNEL ) {
873         SampleUtil_Print( "error: can't change to channel %d\n",
874                           newchannel );
875         ( *errorString ) = "Invalid Channel";
876         return UPNP_E_INVALID_PARAM;
877     }
878
879     /*
880        Vendor-specific code to set the channel goes here 
881      */
882
883     sprintf( value, "%d", newchannel );
884
885     if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL,
886                                     TV_CONTROL_CHANNEL, value ) ) {
887         if( UpnpAddToActionResponse( out, actionName,
888                                      TvServiceType[TV_SERVICE_CONTROL],
889                                      "Channel", value ) != UPNP_E_SUCCESS )
890         {
891             ( *out ) = NULL;
892             ( *errorString ) = "Internal Error";
893             return UPNP_E_INTERNAL_ERROR;
894         }
895         return UPNP_E_SUCCESS;
896     } else {
897         ( *errorString ) = "Internal Error";
898         return UPNP_E_INTERNAL_ERROR;
899     }
900 }
901
902 /******************************************************************************
903  * TvDeviceDecreaseChannel
904  *
905  * Description: 
906  *       Decrease the channel.  
907  *
908  * Parameters:
909  *   
910  *    IXML_Document * in -  action request document
911  *    IXML_Document **out - action result document
912  *    char **errorString - errorString (in case action was unsuccessful)
913  *
914  *****************************************************************************/
915 int
916 TvDeviceDecreaseChannel( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
917 {
918     return IncrementChannel( -1, in, out, errorString );
919 }
920
921 /******************************************************************************
922  * TvDeviceIncreaseChannel
923  *
924  * Description: 
925  *       Increase the channel.  
926  *
927  * Parameters:
928  *   
929  *    IXML_Document * in -  action request document
930  *    IXML_Document **out - action result document
931  *    char **errorString - errorString (in case action was unsuccessful)
932  *
933  *****************************************************************************/
934 int
935 TvDeviceIncreaseChannel( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
936 {
937     return IncrementChannel( 1, in, out, errorString );
938 }
939
940 /******************************************************************************
941  * TvDeviceSetVolume
942  *
943  * Description: 
944  *       Change the volume, update the TvDevice control service
945  *       state table, and notify all subscribed control points of the
946  *       updated state.
947  *
948  * Parameters:
949  *  
950  *    IXML_Document * in -  action request document
951  *    IXML_Document **out - action result document
952  *    char **errorString - errorString (in case action was unsuccessful)
953  *
954  *****************************************************************************/
955 int
956 TvDeviceSetVolume( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
957 {
958     char *value = NULL;
959     int volume = 0;
960
961     ( *out ) = NULL;
962     ( *errorString ) = NULL;
963
964     if( !( value = SampleUtil_GetFirstDocumentItem( in, "Volume" ) ) ) {
965         ( *errorString ) = "Invalid Volume";
966         return UPNP_E_INVALID_PARAM;
967     }
968
969     volume = atoi( value );
970
971     if( volume < MIN_VOLUME || volume > MAX_VOLUME ) {
972         SampleUtil_Print( "error: can't change to volume %d\n", volume );
973         ( *errorString ) = "Invalid Volume";
974         return UPNP_E_INVALID_PARAM;
975     }
976
977     /*
978        Vendor-specific code to set the volume goes here 
979      */
980
981     if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL,
982                                     TV_CONTROL_VOLUME, value ) ) {
983         if( UpnpAddToActionResponse( out, "SetVolume",
984                                      TvServiceType[TV_SERVICE_CONTROL],
985                                      "NewVolume",
986                                      value ) != UPNP_E_SUCCESS ) {
987             ( *out ) = NULL;
988             ( *errorString ) = "Internal Error";
989             free( value );
990             return UPNP_E_INTERNAL_ERROR;
991         }
992         free( value );
993         return UPNP_E_SUCCESS;
994     } else {
995         free( value );
996         ( *errorString ) = "Internal Error";
997         return UPNP_E_INTERNAL_ERROR;
998     }
999 }
1000
1001 /******************************************************************************
1002  * IncrementVolume
1003  *
1004  * Description: 
1005  *       Increment the volume.  Read the current volume from the state
1006  *       table, add the increment, and then change the volume.
1007  *
1008  * Parameters:
1009  *   incr -- The increment by which to change the volume.
1010  *      
1011  *    IXML_Document * in -  action request document
1012  *    IXML_Document **out - action result document
1013  *    char **errorString - errorString (in case action was unsuccessful)
1014  *
1015  *****************************************************************************/
1016 int
1017 IncrementVolume( IN int incr, IN IXML_Document *in,OUT IXML_Document **out, OUT char **errorString )
1018 {
1019     int curvolume,
1020       newvolume;
1021     char *actionName = NULL;
1022     char value[TV_MAX_VAL_LEN];
1023
1024     if( incr > 0 ) {
1025         actionName = "IncreaseVolume";
1026     } else {
1027         actionName = "DecreaseVolume";
1028     }
1029
1030     ithread_mutex_lock( &TVDevMutex );
1031     curvolume = atoi( tv_service_table[TV_SERVICE_CONTROL].
1032                       VariableStrVal[TV_CONTROL_VOLUME] );
1033     ithread_mutex_unlock( &TVDevMutex );
1034
1035     newvolume = curvolume + incr;
1036
1037     if( newvolume < MIN_VOLUME || newvolume > MAX_VOLUME ) {
1038         SampleUtil_Print( "error: can't change to volume %d\n",
1039                           newvolume );
1040         ( *errorString ) = "Invalid Volume";
1041         return UPNP_E_INVALID_PARAM;
1042     }
1043
1044     /*
1045        Vendor-specific code to set the channel goes here 
1046      */
1047
1048     sprintf( value, "%d", newvolume );
1049
1050     if( TvDeviceSetServiceTableVar( TV_SERVICE_CONTROL,
1051                                     TV_CONTROL_VOLUME, value ) ) {
1052         if( UpnpAddToActionResponse( out, actionName,
1053                                      TvServiceType[TV_SERVICE_CONTROL],
1054                                      "Volume", value ) != UPNP_E_SUCCESS ) {
1055             ( *out ) = NULL;
1056             ( *errorString ) = "Internal Error";
1057             return UPNP_E_INTERNAL_ERROR;
1058         }
1059         return UPNP_E_SUCCESS;
1060     } else {
1061         ( *errorString ) = "Internal Error";
1062         return UPNP_E_INTERNAL_ERROR;
1063     }
1064 }
1065
1066 /******************************************************************************
1067  * TvDeviceIncrVolume
1068  *
1069  * Description: 
1070  *       Increase the volume. 
1071  *
1072  * Parameters:
1073  *   
1074  *
1075  *    IXML_Document * in -  action request document
1076  *    IXML_Document **out - action result document
1077  *    char **errorString - errorString (in case action was unsuccessful)
1078  *****************************************************************************/
1079 int
1080 TvDeviceIncreaseVolume( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1081 {
1082     return IncrementVolume( 1, in, out, errorString );
1083 }
1084
1085 /******************************************************************************
1086  * TvDeviceDecreaseVolume
1087  *
1088  * Description: 
1089  *       Decrease the volume.
1090  *
1091  * Parameters:
1092  *   
1093  *    IXML_Document * in -  action request document
1094  *    IXML_Document **out - action result document
1095  *    char **errorString - errorString (in case action was unsuccessful)
1096  *
1097  *****************************************************************************/
1098 int
1099 TvDeviceDecreaseVolume( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1100 {
1101     return IncrementVolume( -1, in, out, errorString );
1102 }
1103
1104 /******************************************************************************
1105  * TvDeviceSetColor
1106  *
1107  * Description: 
1108  *       Change the color, update the TvDevice picture service
1109  *       state table, and notify all subscribed control points of the
1110  *       updated state.
1111  *
1112  * Parameters:
1113  *   
1114  *    IXML_Document * in -  action request document
1115  *    IXML_Document **out - action result document
1116  *    char **errorString - errorString (in case action was unsuccessful)
1117  *
1118  *****************************************************************************/
1119 int
1120 TvDeviceSetColor( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1121 {
1122     char *value = NULL;
1123     int color = 0;
1124
1125     ( *out ) = NULL;
1126     ( *errorString ) = NULL;
1127     if( !( value = SampleUtil_GetFirstDocumentItem( in, "Color" ) ) ) {
1128         ( *errorString ) = "Invalid Color";
1129         return UPNP_E_INVALID_PARAM;
1130     }
1131
1132     color = atoi( value );
1133
1134     if( color < MIN_COLOR || color > MAX_COLOR ) {
1135         SampleUtil_Print( "error: can't change to color %d\n", color );
1136         ( *errorString ) = "Invalid Color";
1137         return UPNP_E_INVALID_PARAM;
1138     }
1139
1140     /*
1141        Vendor-specific code to set the volume goes here 
1142      */
1143
1144     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1145                                     TV_PICTURE_COLOR, value ) ) {
1146         if( UpnpAddToActionResponse( out, "SetColor",
1147                                      TvServiceType[TV_SERVICE_PICTURE],
1148                                      "NewColor",
1149                                      value ) != UPNP_E_SUCCESS ) {
1150             ( *out ) = NULL;
1151             ( *errorString ) = "Internal Error";
1152             free( value );
1153             return UPNP_E_INTERNAL_ERROR;
1154         }
1155         free( value );
1156         return UPNP_E_SUCCESS;
1157     } else {
1158         free( value );
1159         ( *errorString ) = "Internal Error";
1160         return UPNP_E_INTERNAL_ERROR;
1161     }
1162 }
1163
1164 /******************************************************************************
1165  * IncrementColor
1166  *
1167  * Description: 
1168  *       Increment the color.  Read the current color from the state
1169  *       table, add the increment, and then change the color.
1170  *
1171  * Parameters:
1172  *   incr -- The increment by which to change the color.
1173  *   
1174  *    IXML_Document * in -  action request document
1175  *    IXML_Document **out - action result document
1176  *    char **errorString - errorString (in case action was unsuccessful)
1177  *****************************************************************************/
1178 int
1179 IncrementColor( IN int incr, IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1180 {
1181     int curcolor;
1182     int newcolor;
1183     char *actionName;
1184     char value[TV_MAX_VAL_LEN];
1185
1186     if( incr > 0 ) {
1187         actionName = "IncreaseColor";
1188     } else {
1189         actionName = "DecreaseColor";
1190     }
1191
1192     ithread_mutex_lock( &TVDevMutex );
1193     curcolor = atoi( tv_service_table[TV_SERVICE_PICTURE].
1194                      VariableStrVal[TV_PICTURE_COLOR] );
1195     ithread_mutex_unlock( &TVDevMutex );
1196
1197     newcolor = curcolor + incr;
1198
1199     if( newcolor < MIN_COLOR || newcolor > MAX_COLOR ) {
1200         SampleUtil_Print( "error: can't change to color %d\n", newcolor );
1201         ( *errorString ) = "Invalid Color";
1202         return UPNP_E_INVALID_PARAM;
1203     }
1204
1205     /*
1206        Vendor-specific code to set the channel goes here 
1207      */
1208
1209     sprintf( value, "%d", newcolor );
1210
1211     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1212                                     TV_PICTURE_COLOR, value ) ) {
1213         if( UpnpAddToActionResponse( out, actionName,
1214                                      TvServiceType[TV_SERVICE_PICTURE],
1215                                      "Color", value ) != UPNP_E_SUCCESS ) {
1216             ( *out ) = NULL;
1217             ( *errorString ) = "Internal Error";
1218             return UPNP_E_INTERNAL_ERROR;
1219         }
1220         return UPNP_E_SUCCESS;
1221     } else {
1222         ( *errorString ) = "Internal Error";
1223         return UPNP_E_INTERNAL_ERROR;
1224     }
1225 }
1226
1227 /******************************************************************************
1228  * TvDeviceDecreaseColor
1229  *
1230  * Description: 
1231  *       Decrease the color.  
1232  *
1233  * Parameters:
1234  *   
1235  *    IXML_Document * in -  action request document
1236  *    IXML_Document **out - action result document
1237  *    char **errorString - errorString (in case action was unsuccessful)
1238  *****************************************************************************/
1239 int
1240 TvDeviceDecreaseColor( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1241 {
1242     return IncrementColor( -1, in, out, errorString );
1243 }
1244
1245 /******************************************************************************
1246  * TvDeviceIncreaseColor
1247  *
1248  * Description: 
1249  *       Increase the color.
1250  *
1251  * Parameters:
1252  *
1253  *    IXML_Document * in -  action request document
1254  *    IXML_Document **out - action result document
1255  *    char **errorString - errorString (in case action was unsuccessful)
1256  *****************************************************************************/
1257 int
1258 TvDeviceIncreaseColor( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1259 {
1260     return IncrementColor( 1, in, out, errorString );
1261 }
1262
1263 /******************************************************************************
1264  * TvDeviceSetTint
1265  *
1266  * Description: 
1267  *       Change the tint, update the TvDevice picture service
1268  *       state table, and notify all subscribed control points of the
1269  *       updated state.
1270  *
1271  * Parameters:
1272  *
1273  *    IXML_Document * in -  action request document
1274  *    IXML_Document **out - action result document
1275  *    char **errorString - errorString (in case action was unsuccessful)
1276  *
1277  *****************************************************************************/
1278 int
1279 TvDeviceSetTint( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1280 {
1281     char *value = NULL;
1282     int tint = -1;
1283
1284     ( *out ) = NULL;
1285     ( *errorString ) = NULL;
1286
1287     if( !( value = SampleUtil_GetFirstDocumentItem( in, "Tint" ) ) ) {
1288         ( *errorString ) = "Invalid Tint";
1289         return UPNP_E_INVALID_PARAM;
1290     }
1291
1292     tint = atoi( value );
1293
1294     if( tint < MIN_TINT || tint > MAX_TINT ) {
1295         SampleUtil_Print( "error: can't change to tint %d\n", tint );
1296         ( *errorString ) = "Invalid Tint";
1297         return UPNP_E_INVALID_PARAM;
1298     }
1299
1300     /*
1301        Vendor-specific code to set the volume goes here 
1302      */
1303
1304     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1305                                     TV_PICTURE_TINT, value ) ) {
1306         if( UpnpAddToActionResponse( out, "SetTint",
1307                                      TvServiceType[TV_SERVICE_PICTURE],
1308                                      "NewTint", value ) != UPNP_E_SUCCESS )
1309         {
1310             ( *out ) = NULL;
1311             ( *errorString ) = "Internal Error";
1312             free( value );
1313             return UPNP_E_INTERNAL_ERROR;
1314         }
1315         free( value );
1316         return UPNP_E_SUCCESS;
1317     } else {
1318         free( value );
1319         ( *errorString ) = "Internal Error";
1320         return UPNP_E_INTERNAL_ERROR;
1321     }
1322
1323 }
1324
1325 /******************************************************************************
1326  * IncrementTint
1327  *
1328  * Description: 
1329  *       Increment the tint.  Read the current tint from the state
1330  *       table, add the increment, and then change the tint.
1331  *
1332  * Parameters:
1333  *   incr -- The increment by which to change the tint.
1334  *   
1335  *    IXML_Document * in -  action request document
1336  *    IXML_Document **out - action result document
1337  *    char **errorString - errorString (in case action was unsuccessful)
1338  *****************************************************************************/
1339 int
1340 IncrementTint( IN int incr, IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1341 {
1342     int curtint;
1343     int newtint;
1344     char *actionName = NULL;
1345     char value[TV_MAX_VAL_LEN];
1346
1347     if( incr > 0 ) {
1348         actionName = "IncreaseTint";
1349     } else {
1350         actionName = "DecreaseTint";
1351     }
1352
1353     ithread_mutex_lock( &TVDevMutex );
1354     curtint = atoi( tv_service_table[TV_SERVICE_PICTURE].
1355                     VariableStrVal[TV_PICTURE_TINT] );
1356     ithread_mutex_unlock( &TVDevMutex );
1357
1358     newtint = curtint + incr;
1359
1360     if( newtint < MIN_TINT || newtint > MAX_TINT ) {
1361         SampleUtil_Print( "error: can't change to tint %d\n", newtint );
1362         ( *errorString ) = "Invalid Tint";
1363         return UPNP_E_INVALID_PARAM;
1364     }
1365
1366     /*
1367        Vendor-specific code to set the channel goes here 
1368      */
1369
1370     sprintf( value, "%d", newtint );
1371
1372     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1373                                     TV_PICTURE_TINT, value ) ) {
1374         if( UpnpAddToActionResponse( out, actionName,
1375                                      TvServiceType[TV_SERVICE_PICTURE],
1376                                      "Tint", value ) != UPNP_E_SUCCESS ) {
1377             ( *out ) = NULL;
1378             ( *errorString ) = "Internal Error";
1379             return UPNP_E_INTERNAL_ERROR;
1380         }
1381         return UPNP_E_SUCCESS;
1382     } else {
1383         ( *errorString ) = "Internal Error";
1384         return UPNP_E_INTERNAL_ERROR;
1385     }
1386 }
1387
1388 /******************************************************************************
1389  * TvDeviceIncreaseTint
1390  *
1391  * Description: 
1392  *       Increase tint.
1393  *
1394  * Parameters:
1395  *   
1396  *    IXML_Document * in -  action request document
1397  *    IXML_Document **out - action result document
1398  *    char **errorString - errorString (in case action was unsuccessful)
1399  *
1400  *****************************************************************************/
1401 int
1402 TvDeviceIncreaseTint( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1403 {
1404     return IncrementTint( 1, in, out, errorString );
1405 }
1406
1407 /******************************************************************************
1408  * TvDeviceDecreaseTint
1409  *
1410  * Description: 
1411  *       Decrease tint.
1412  *
1413  * Parameters:
1414  *  
1415  *    IXML_Document * in -  action request document
1416  *    IXML_Document **out - action result document
1417  *    char **errorString - errorString (in case action was unsuccessful)
1418  *
1419  *****************************************************************************/
1420 int
1421 TvDeviceDecreaseTint( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1422 {
1423     return IncrementTint( -1, in, out, errorString );
1424 }
1425
1426 /*****************************************************************************
1427  * TvDeviceSetContrast
1428  *
1429  * Description: 
1430  *       Change the contrast, update the TvDevice picture service
1431  *       state table, and notify all subscribed control points of the
1432  *       updated state.
1433  *
1434  * Parameters:
1435  *   
1436  *    IXML_Document * in -  action request document
1437  *    IXML_Document **out - action result document
1438  *    char **errorString - errorString (in case action was unsuccessful)
1439  *
1440  ****************************************************************************/
1441 int
1442 TvDeviceSetContrast( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1443 {
1444     char *value = NULL;
1445     int contrast = -1;
1446
1447     ( *out ) = NULL;
1448     ( *errorString ) = NULL;
1449
1450     if( !( value = SampleUtil_GetFirstDocumentItem( in, "Contrast" ) ) ) {
1451         ( *errorString ) = "Invalid Contrast";
1452         return UPNP_E_INVALID_PARAM;
1453     }
1454
1455     contrast = atoi( value );
1456
1457     if( contrast < MIN_CONTRAST || contrast > MAX_CONTRAST ) {
1458         SampleUtil_Print( "error: can't change to contrast %d\n",
1459                           contrast );
1460         ( *errorString ) = "Invalid Contrast";
1461         return UPNP_E_INVALID_PARAM;
1462     }
1463
1464     /*
1465        Vendor-specific code to set the volume goes here 
1466      */
1467
1468     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1469                                     TV_PICTURE_CONTRAST, value ) ) {
1470         if( UpnpAddToActionResponse( out, "SetContrast",
1471                                      TvServiceType[TV_SERVICE_PICTURE],
1472                                      "NewContrast",
1473                                      value ) != UPNP_E_SUCCESS ) {
1474             ( *out ) = NULL;
1475             ( *errorString ) = "Internal Error";
1476             free( value );
1477             return UPNP_E_INTERNAL_ERROR;
1478         }
1479         free( value );
1480         return UPNP_E_SUCCESS;
1481     } else {
1482         free( value );
1483         ( *errorString ) = "Internal Error";
1484         return UPNP_E_INTERNAL_ERROR;
1485     }
1486
1487 }
1488
1489 /******************************************************************************
1490  * IncrementContrast
1491  *
1492  * Description: 
1493  *       Increment the contrast.  Read the current contrast from the state
1494  *       table, add the increment, and then change the contrast.
1495  *
1496  * Parameters:
1497  *   incr -- The increment by which to change the contrast.
1498  *   
1499  *    IXML_Document * in -  action request document
1500  *    IXML_Document **out - action result document
1501  *    char **errorString - errorString (in case action was unsuccessful)
1502  *****************************************************************************/
1503 int
1504 IncrementContrast( IN int incr, IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1505 {
1506     int curcontrast;
1507     int newcontrast;
1508     char *actionName = NULL;
1509     char value[TV_MAX_VAL_LEN];
1510
1511     if( incr > 0 ) {
1512         actionName = "IncreaseContrast";
1513     } else {
1514         actionName = "DecreaseContrast";
1515     }
1516
1517     ithread_mutex_lock( &TVDevMutex );
1518     curcontrast = atoi( tv_service_table[TV_SERVICE_PICTURE].
1519                         VariableStrVal[TV_PICTURE_CONTRAST] );
1520     ithread_mutex_unlock( &TVDevMutex );
1521
1522     newcontrast = curcontrast + incr;
1523
1524     if( newcontrast < MIN_CONTRAST || newcontrast > MAX_CONTRAST ) {
1525         SampleUtil_Print( "error: can't change to contrast %d\n",
1526                           newcontrast );
1527         ( *errorString ) = "Invalid Contrast";
1528         return UPNP_E_INVALID_PARAM;
1529     }
1530
1531     /*
1532        Vendor-specific code to set the channel goes here 
1533      */
1534
1535     sprintf( value, "%d", newcontrast );
1536
1537     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1538                                     TV_PICTURE_CONTRAST, value ) ) {
1539         if( UpnpAddToActionResponse( out, actionName,
1540                                      TvServiceType[TV_SERVICE_PICTURE],
1541                                      "Contrast",
1542                                      value ) != UPNP_E_SUCCESS ) {
1543             ( *out ) = NULL;
1544             ( *errorString ) = "Internal Error";
1545             return UPNP_E_INTERNAL_ERROR;
1546         }
1547         return UPNP_E_SUCCESS;
1548     } else {
1549         ( *errorString ) = "Internal Error";
1550         return UPNP_E_INTERNAL_ERROR;
1551     }
1552 }
1553
1554 /******************************************************************************
1555  * TvDeviceIncreaseContrast
1556  *
1557  * Description: 
1558  *
1559  *      Increase the contrast.
1560  *
1561  * Parameters:
1562  *       
1563  *    IXML_Document * in -  action request document
1564  *    IXML_Document **out - action result document
1565  *    char **errorString - errorString (in case action was unsuccessful)
1566  *
1567  *****************************************************************************/
1568 int
1569 TvDeviceIncreaseContrast( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1570 {
1571     return IncrementContrast( 1, in, out, errorString );
1572 }
1573
1574 /******************************************************************************
1575  * TvDeviceDecreaseContrast
1576  *
1577  * Description: 
1578  *      Decrease the contrast.
1579  *
1580  * Parameters:
1581  *          
1582  *    IXML_Document * in -  action request document
1583  *    IXML_Document **out - action result document
1584  *    char **errorString - errorString (in case action was unsuccessful)
1585  *
1586  *****************************************************************************/
1587 int
1588 TvDeviceDecreaseContrast( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1589 {
1590     return IncrementContrast( -1, in, out, errorString );
1591 }
1592
1593 /******************************************************************************
1594  * TvDeviceSetBrightness
1595  *
1596  * Description: 
1597  *       Change the brightness, update the TvDevice picture service
1598  *       state table, and notify all subscribed control points of the
1599  *       updated state.
1600  *
1601  * Parameters:
1602  *   brightness -- The brightness value to change to.
1603  *
1604  *****************************************************************************/
1605 int
1606 TvDeviceSetBrightness( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1607 {
1608     char *value = NULL;
1609     int brightness = -1;
1610
1611     ( *out ) = NULL;
1612     ( *errorString ) = NULL;
1613
1614     if( !( value = SampleUtil_GetFirstDocumentItem( in, "Brightness" ) ) ) {
1615         ( *errorString ) = "Invalid Brightness";
1616         return UPNP_E_INVALID_PARAM;
1617     }
1618
1619     brightness = atoi( value );
1620
1621     if( brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS ) {
1622         SampleUtil_Print( "error: can't change to brightness %d\n",
1623                           brightness );
1624         ( *errorString ) = "Invalid Brightness";
1625         return UPNP_E_INVALID_PARAM;
1626     }
1627
1628     /*
1629        Vendor-specific code to set the volume goes here 
1630      */
1631
1632     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1633                                     TV_PICTURE_BRIGHTNESS, value ) ) {
1634         if( UpnpAddToActionResponse( out, "SetBrightness",
1635                                      TvServiceType[TV_SERVICE_PICTURE],
1636                                      "NewBrightness",
1637                                      value ) != UPNP_E_SUCCESS ) {
1638             ( *out ) = NULL;
1639             ( *errorString ) = "Internal Error";
1640             free( value );
1641             return UPNP_E_INTERNAL_ERROR;
1642         }
1643         free( value );
1644         return UPNP_E_SUCCESS;
1645     } else {
1646         free( value );
1647         ( *errorString ) = "Internal Error";
1648         return UPNP_E_INTERNAL_ERROR;
1649     }
1650 }
1651
1652 /******************************************************************************
1653  * IncrementBrightness
1654  *
1655  * Description: 
1656  *       Increment the brightness.  Read the current brightness from the state
1657  *       table, add the increment, and then change the brightness.
1658  *
1659  * Parameters:
1660  *   incr -- The increment by which to change the brightness.
1661  *   
1662  *    IXML_Document * in -  action request document
1663  *    IXML_Document **out - action result document
1664  *    char **errorString - errorString (in case action was unsuccessful)
1665  *****************************************************************************/
1666 int
1667 IncrementBrightness( IN int incr, IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1668 {
1669     int curbrightness;
1670     int newbrightness;
1671     char *actionName = NULL;
1672     char value[TV_MAX_VAL_LEN];
1673
1674     if( incr > 0 ) {
1675         actionName = "IncreaseBrightness";
1676     } else {
1677         actionName = "DecreaseBrightness";
1678     }
1679
1680     ithread_mutex_lock( &TVDevMutex );
1681     curbrightness = atoi( tv_service_table[TV_SERVICE_PICTURE].
1682                           VariableStrVal[TV_PICTURE_BRIGHTNESS] );
1683     ithread_mutex_unlock( &TVDevMutex );
1684
1685     newbrightness = curbrightness + incr;
1686
1687     if( newbrightness < MIN_BRIGHTNESS || newbrightness > MAX_BRIGHTNESS ) {
1688         SampleUtil_Print( "error: can't change to brightness %d\n",
1689                           newbrightness );
1690         ( *errorString ) = "Invalid Brightness";
1691         return UPNP_E_INVALID_PARAM;
1692     }
1693
1694     /*
1695        Vendor-specific code to set the channel goes here 
1696      */
1697
1698     sprintf( value, "%d", newbrightness );
1699
1700     if( TvDeviceSetServiceTableVar( TV_SERVICE_PICTURE,
1701                                     TV_PICTURE_BRIGHTNESS, value ) ) {
1702         if( UpnpAddToActionResponse( out, actionName,
1703                                      TvServiceType[TV_SERVICE_PICTURE],
1704                                      "Brightness",
1705                                      value ) != UPNP_E_SUCCESS ) {
1706             ( *out ) = NULL;
1707             ( *errorString ) = "Internal Error";
1708             return UPNP_E_INTERNAL_ERROR;
1709         }
1710         return UPNP_E_SUCCESS;
1711     } else {
1712         ( *errorString ) = "Internal Error";
1713         return UPNP_E_INTERNAL_ERROR;
1714     }
1715 }
1716
1717 /******************************************************************************
1718  * TvDeviceIncreaseBrightness
1719  *
1720  * Description: 
1721  *       Increase brightness.
1722  *
1723  * Parameters:
1724  *
1725  *    IXML_Document * in -  action request document
1726  *    IXML_Document **out - action result document
1727  *    char **errorString - errorString (in case action was unsuccessful)
1728  *
1729  *****************************************************************************/
1730 int
1731 TvDeviceIncreaseBrightness( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1732 {
1733     return IncrementBrightness( 1, in, out, errorString );
1734 }
1735
1736 /******************************************************************************
1737  * TvDeviceDecreaseBrightness
1738  *
1739  * Description: 
1740  *       Decrease brightnesss.
1741  *
1742  * Parameters:
1743  *    IXML_Document * in -  action request document
1744  *    IXML_Document **out - action result document
1745  *    char **errorString - errorString (in case action was unsuccessful)
1746  *
1747  *****************************************************************************/
1748 int
1749 TvDeviceDecreaseBrightness( IN IXML_Document *in, OUT IXML_Document **out, OUT char **errorString )
1750 {
1751     return IncrementBrightness( -1, in, out, errorString );
1752 }
1753
1754 /******************************************************************************
1755  * TvDeviceCallbackEventHandler
1756  *
1757  * Description: 
1758  *       The callback handler registered with the SDK while registering
1759  *       root device.  Dispatches the request to the appropriate procedure
1760  *       based on the value of EventType. The four requests handled by the 
1761  *       device are: 
1762  *                   1) Event Subscription requests.  
1763  *                   2) Get Variable requests. 
1764  *                   3) Action requests.
1765  *
1766  * Parameters:
1767  *
1768  *   EventType -- The type of callback event
1769  *   Event -- Data structure containing event data
1770  *   Cookie -- Optional data specified during callback registration
1771  *
1772  *****************************************************************************/
1773 int TvDeviceCallbackEventHandler(Upnp_EventType EventType, void *Event, void *Cookie)
1774 {
1775     switch ( EventType ) {
1776         case UPNP_EVENT_SUBSCRIPTION_REQUEST:
1777
1778             TvDeviceHandleSubscriptionRequest( ( struct
1779                                                  Upnp_Subscription_Request
1780                                                  * )Event );
1781             break;
1782
1783         case UPNP_CONTROL_GET_VAR_REQUEST:
1784             TvDeviceHandleGetVarRequest( ( struct Upnp_State_Var_Request
1785                                            * )Event );
1786             break;
1787
1788         case UPNP_CONTROL_ACTION_REQUEST:
1789             TvDeviceHandleActionRequest( ( struct Upnp_Action_Request * )
1790                                          Event );
1791             break;
1792
1793             /*
1794                ignore these cases, since this is not a control point 
1795              */
1796         case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
1797         case UPNP_DISCOVERY_SEARCH_RESULT:
1798         case UPNP_DISCOVERY_SEARCH_TIMEOUT:
1799         case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
1800         case UPNP_CONTROL_ACTION_COMPLETE:
1801         case UPNP_CONTROL_GET_VAR_COMPLETE:
1802         case UPNP_EVENT_RECEIVED:
1803         case UPNP_EVENT_RENEWAL_COMPLETE:
1804         case UPNP_EVENT_SUBSCRIBE_COMPLETE:
1805         case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
1806             break;
1807
1808         default:
1809             SampleUtil_Print( "Error in TvDeviceCallbackEventHandler: unknown event type %d\n",
1810                 EventType );
1811     }
1812
1813     /* Print a summary of the event received */
1814     SampleUtil_PrintEvent( EventType, Event );
1815
1816     return 0;
1817 }
1818
1819 /******************************************************************************
1820  * TvDeviceStop
1821  *
1822  * Description: 
1823  *       Stops the device. Uninitializes the sdk. 
1824  *
1825  * Parameters:
1826  *
1827  *****************************************************************************/
1828 int
1829 TvDeviceStop()
1830 {
1831     UpnpUnRegisterRootDevice( device_handle );
1832     UpnpFinish();
1833     SampleUtil_Finish();
1834     ithread_mutex_destroy( &TVDevMutex );
1835
1836     return UPNP_E_SUCCESS;
1837 }
1838
1839 /******************************************************************************
1840  * TvDeviceStart
1841  *
1842  * Description: 
1843  *      Initializes the UPnP Sdk, registers the device, and sends out 
1844  *      advertisements.  
1845  *
1846  * Parameters:
1847  *
1848  *   ip_address - ip address to initialize the sdk (may be NULL)
1849  *                if null, then the first non null loopback address is used.
1850  *   port       - port number to initialize the sdk (may be 0)
1851  *                if zero, then a random number is used.
1852  *   desc_doc_name - name of description document.
1853  *                   may be NULL. Default is tvdevicedesc.xml
1854  *   web_dir_path  - path of web directory.
1855  *                   may be NULL. Default is ./web (for Linux) or ../tvdevice/web
1856  *                   for windows.
1857  *   pfun          - print function to use.  
1858  *
1859  *****************************************************************************/
1860 int
1861 TvDeviceStart( char *ip_address,
1862                unsigned short port,
1863                char *desc_doc_name,
1864                char *web_dir_path,
1865                print_string pfun )
1866 {
1867     int ret = UPNP_E_SUCCESS;
1868     char desc_doc_url[DESC_URL_SIZE];
1869
1870     ithread_mutex_init( &TVDevMutex, NULL );
1871
1872     SampleUtil_Initialize( pfun );
1873
1874     SampleUtil_Print(
1875         "Initializing UPnP Sdk with\n"
1876         "\tipaddress = %s port = %u\n",
1877         ip_address, port );
1878
1879     ret = UpnpInit( ip_address, port );
1880     if( ret != UPNP_E_SUCCESS ) {
1881         SampleUtil_Print( "Error with UpnpInit -- %d\n", ret );
1882         UpnpFinish();
1883         return ret;
1884     }
1885
1886     ip_address = UpnpGetServerIpAddress();
1887     port = UpnpGetServerPort();
1888
1889     SampleUtil_Print(
1890         "UPnP Initialized\n"
1891         "\tipaddress= %s port = %u\n",
1892         ip_address, port );
1893
1894     if( desc_doc_name == NULL ) {
1895         desc_doc_name = "tvdevicedesc.xml";
1896     }
1897
1898     if( web_dir_path == NULL ) {
1899         web_dir_path = DEFAULT_WEB_DIR;
1900     }
1901
1902     snprintf( desc_doc_url, DESC_URL_SIZE, "http://%s:%d/%s", ip_address,
1903               port, desc_doc_name );
1904
1905     SampleUtil_Print( "Specifying the webserver root directory -- %s\n",
1906                       web_dir_path );
1907     ret = UpnpSetWebServerRootDir( web_dir_path );
1908     if( ret != UPNP_E_SUCCESS ) {
1909         SampleUtil_Print( "Error specifying webserver root directory -- %s: %d\n",
1910               web_dir_path, ret );
1911         UpnpFinish();
1912
1913         return ret;
1914     }
1915
1916     SampleUtil_Print(
1917         "Registering the RootDevice\n"
1918         "\t with desc_doc_url: %s\n",
1919         desc_doc_url );
1920
1921     ret = UpnpRegisterRootDevice( desc_doc_url, TvDeviceCallbackEventHandler,
1922         &device_handle, &device_handle );
1923     if( ret != UPNP_E_SUCCESS ) {
1924         SampleUtil_Print( "Error registering the rootdevice : %d\n", ret );
1925         UpnpFinish();
1926
1927         return ret;
1928     } else {
1929         SampleUtil_Print(
1930             "RootDevice Registered\n"
1931             "Initializing State Table\n");
1932         TvDeviceStateTableInit( desc_doc_url );
1933         SampleUtil_Print("State Table Initialized\n");
1934         ret = UpnpSendAdvertisement( device_handle, default_advr_expire );
1935         if( ret != UPNP_E_SUCCESS ) {
1936             SampleUtil_Print( "Error sending advertisements : %d\n", ret );
1937             UpnpFinish();
1938
1939             return ret;
1940         }
1941
1942         SampleUtil_Print("Advertisements Sent\n");
1943     }
1944
1945     return UPNP_E_SUCCESS;
1946 }
1947