1 /*
  2  * This is system cordova_plugin (TV specific API).
  3  * Apache License (2004). See http://www.apache.org/licenses/LICENSE-2.0
  4  *
  5  * Copyright (c) 2014, LG Electronics, Inc.
  6  */
  7 
  8 
  9 /**
 10  * This represents the InputSource API itself, and provides a global namespace for operating InputSource service.
 11  * @class
 12  */
 13 cordova.define('cordova/plugin/inputSource', function (require, exports, module) { // jshint ignore:line
 14     
 15     function log(msg) {
 16         //console.log//will be removed // jshint ignore:line
 17     }
 18     
 19     var service;
 20     if (window.PalmSystem) { // jshint ignore:line
 21         log("Window.PalmSystem Available");
 22         service = require('cordova/plugin/webos/service'); 
 23     } else {
 24         service = {
 25             Request : function(uri, params) {
 26                log(uri + " invoked. But I am a dummy because PalmSystem is not available");
 27                         
 28                if (typeof params.onFailure === 'function') {
 29                   params.onFailure({ returnValue:false,
 30                      errorText:"PalmSystem Not Available. Cordova is not installed?"});
 31                }
 32         }};
 33     }
 34 
 35     /**
 36      * inputSource interface
 37      */
 38     var InputSource = function () {
 39     };
 40     
 41     var broadcast = null;
 42     
 43     function checkErrorCodeNText(result, errorCode, errorText) {
 44         
 45         if (result.errorCode === undefined || result.errorCode === null ) {
 46             result.errorCode = errorCode;
 47         }
 48         if (result.errorText ===undefined || result.errorText === null) {
 49             result.errorText = errorText;
 50         }
 51     }
 52     
 53     /**
 54      * Imports video tag to show the input source dynamically. This is used to embed input source in an html page.
 55      *  
 56      * @class InputSource
 57      * @param {Function} successCallback success callback function.
 58      * @param {Function} errorCallback failure callback function.
 59      * @param {Object} options
 60      * <div align=left>
 61      * <table class="hcap_spec" width=400>
 62      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
 63      *   <tbody>
 64      *       <tr><th>divId</th><th>String</th><th>Div tag ID with the video tag in it. </th><th>required</th></tr>
 65      *       <tr class="odd"><th>videoId</th><th>String</th><th>The ID of the video tag to be dynamically created. </th><th>required</th></tr>
 66      *       <tr><th>callback</th><th>Function</th><th>An event handler (onloadedmetadata) that is called when the video tag is created. </th><th>required</th></tr>
 67      *       <tr class="odd"><th>src</th><th>String</th><th>The src attribute of the video tag. ext://[externalInput]:[portNum]. (eg: "ext://hdmi:1") </th><th>required</th></tr>
 68      *   </tbody>
 69      * </table>
 70      * @return <p>None.</p>
 71      * @example
 72      * // HTML code
 73      *  < body onload="onLoad()" >
 74      *     < div id = "videoDiv" style="width:640px; height:380px" >
 75      *     < /div >
 76      *  < /body >
 77      *
 78      * // Javascript code
 79      * function init () {
 80      * }
 81      * 
 82      * function onLoad() {
 83      *   var options = {
 84      *      divId : "videoDiv", // It should be matched to div tag name in an html page.
 85      *      videoId : "broadcastvideo",
 86      *      callback : init,
 87      *      src : "ext://hdmi:1"
 88      *   };   
 89      *     
 90      *   function successCb() {
 91      *      // Do something
 92      *   }
 93      *
 94      *   function failureCb(cbObject) {
 95      *      var errorCode = cbObject.errorCode;
 96      *      var errorText = cbObject.errorText;
 97      *      console.log ("Error Code [" + errorCode + "]: " + errorText);
 98      *   }
 99      *   
100      *   var inputSource = new InputSource();
101      *   inputSource.initialize(successCb, failureCb, options);
102      * }
103      * @since 1.0
104      * @since 1.1 options.isLastChannel removed
105      */
106     InputSource.prototype.initialize = function (successCallback, errorCallback, options) {
107     
108         log("initialize: " + JSON.stringify(options));
109         
110         // bound check
111         if (options.divId === undefined || typeof options.divId !== 'string' || options.divId === null || options.divId.length <= 0 ||
112                 options.videoId === undefined || typeof options.videoId !== 'string' || options.videoId === null || options.videoId.length <= 0 ||
113                 options.callback === undefined || typeof options.callback !== 'function' ||
114                 options.src === undefined || typeof options.src !== 'string' || options.src === null || options.src.length <= 0 ) {
115             
116             if (typeof errorCallback === 'function') {
117                 var result = {};
118                 checkErrorCodeNText(result, "II", "InputSource.initialize returns failure. invalid parameters.");
119                 errorCallback(result);
120             }
121             
122             return;
123         }
124         
125         convertInputSource(options.src, function success(inputSource) {
126             // success callback
127             options.src = inputSource;
128             broadcast = new Broadcast(); // jshint ignore:line
129             
130             log("initialize: converted " + JSON.stringify(options));
131             
132             broadcast.initialize(successCallback, errorCallback, options);
133             
134         }, function failure(cbObj) {
135             // failure callback
136             log("initialize: failure " + JSON.stringify(cbObj));
137             
138             if (typeof errorCallback === 'function') {
139                 var result = {};
140                 checkErrorCodeNText(result, "II", "InputSource.initialize returns failure. invalid parameters.");
141                 errorCallback(result);
142             }
143         });
144         
145         log("initialize: Done");
146         
147     };
148 
149     /**
150      * Changes the input source that viewer is currently watching. This method is used to change to other input source after initializing the inputSource object (creating video tag. etc.) using InputSource.initialize() method.
151      * Available input types and number of input sources for each input types may differ model by model. <br>
152      * For example, LS55A model has the following inputs : (HDMI1, HDMI2, DP, DVI) or SM5B model has the following inputs : (HDMI1, DP, DVI, RGB, OPS)
153      * @class InputSource
154      * @param {Function} successCallback success callback function.
155      * @param {Function} errorCallback failure callback function.
156      * @param {Object} options
157      * <div align=left>
158      * <table class="hcap_spec" width=400>
159      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
160      *   <tbody>
161      *       <tr><th>src</th><th>String</th><th>Define the src attribute of video tag. "ext://[externalinput]:[portNum]" (eg, "ext://dp:1")</a> </th><th>required</th></tr>
162      *   </tbody>
163      * </table>
164      * </div>
165      * @return <p>If the method is successfully executed, success callback function is called without a parameter.</br>
166      * If an error occurs, failure callback function is called with failure callback object as a parameter.</p>
167      * @example
168      * // Javascript code
169      * function changeInputSource () {
170      *   var options = {
171      *      src : "ext://hdmi:1"
172      *   };
173      *
174      *   function successCb() {
175      *      // Do something
176      *   }
177      *
178      *   function failureCb(cbObject) {
179      *      var errorCode = cbObject.errorCode;
180      *      var errorText = cbObject.errorText;
181      *      console.log ("Error Code [" + errorCode + "]: " + errorText);
182      *   }
183      *
184      *   var inputSource = new InputSource();
185      *   inputSource.changeInputSource(successCb, failureCb, options);
186      * }
187      * @since 1.0
188      * @see <a href="InputSource%23getInputSourceStatus.html">InputSource.getInputSourceStatus()</a><br>
189      */
190     InputSource.prototype.changeInputSource = function (successCallback, errorCallback, options) {
191     
192         // bound check
193         if ( options.src === undefined || typeof options.src !== 'string' || options.src === null || options.src.length <= 0) {
194             
195             if (typeof errorCallback === 'function') {
196                 var result = {};
197                 checkErrorCodeNText(result, "ICIS", "InputSource.changeInputSource returns failure. invalid argument. ");
198                 errorCallback(result);
199             }
200             
201             return;
202         }
203         
204        //TODO; deprecated changeInput in broadcast.js 
205         
206         log("changeInputSource: " + JSON.stringify(options));
207         
208         convertInputSource(options.src, function success (inputSource) {
209             // success callback
210             options.src = inputSource;
211             
212             if (broadcast.setInput(options)) {
213                 log("changeInputSource: On Success");
214                 successCallback();
215             } else {
216                 var result = {};
217                 log("changeInputSource: On Failure");
218                 checkErrorCodeNText(result, "ICIS", "InputSource.changeInputSource returns failure.");
219                 errorCallback(result);
220             }
221             
222         }, function failure(cbObj) {
223             // failure callback
224             log("changeInputSource: failure " + JSON.stringify(cbObj));
225             
226             if (typeof errorCallback === 'function') {
227                 var result = {};
228                 checkErrorCodeNText(result, "ICIS", "InputSource.changeInputSource returns failure. invalid argument. ");
229                 errorCallback(result);
230             }
231         });
232         
233         log("changeInputSource: Done");
234     };
235     
236     /**
237      * Gets current input source status. 
238      * @class InputSource
239      * @param {Function} successCallback success callback function.
240      * @param {Function} errorCallback failure callback function.
241      * @return {Object} array of inputSource object, signal state and current input source.
242      * <div align=left>
243      * <table class="hcap_spec" width=400>
244      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead>
245      *   <tbody>
246      *       <tr><th>inputSourceList[]</th><th>Array</th><th>An array with input source object.</th></tr>
247      *       <tr class="odd"><th>inputSourceList[].inputPort</th><th>String</th><th>Input label (ext://hdmi:1, ext://hdmi:2, ext://dp:1, ext://dvi:1 etc) </th></tr>
248      *       <tr><th>currentSignalState</th><th>String</th><th>Status and change information of the input that is currently selected.<br>"good" : good signal, "bad" : poor signal, "unknown" : can't indicate a signal status </th></tr>
249      *       <tr class="odd"><th>currentInputSource</th><th>String</th><th>Input source that the viewer is currently watching.<br>input label </th></tr>       
250      *   </tbody>
251      * </table>
252      * </div>
253      * 
254      * @example
255      * // Javascript code
256      * function getInputSourceStatus () {
257      *   function successCb(cbObject) {
258      *      var inputSourceList = cbObject.inputSourceList;
259      *      for ( var i = 0; i < inputSourceList.length; i++) {
260      *         console.log("inputSourceList[" + i + "] : " + JSON.stringify(inputSourceList[i]));
261      *         console.log("inputSourceList[" + i + "].inputPort : " + inputSourceList[i].inputPort);
262      *      }
263      *      console.log("currentInputSource : " + cbObject.currentInputSource);
264      *      console.log("currentSignalState : " + cbObject.currentSignalState);
265      *      // Do something
266      *   }
267      *
268      *   function failureCb(cbObject) {
269      *      var errorCode = cbObject.errorCode;
270      *      var errorText = cbObject.errorText;
271      *      console.log ("Error Code [" + errorCode + "]: " + errorText);
272      *   }
273      *
274      *   var inputSource = new InputSource();
275      *   inputSource.getInputSourceStatus(successCb, failureCb);
276      * }
277      * @since 1.0
278      * @see <a href="InputSource%23changeInputSource.html">InputSource.changeInputSource()</a><br>
279      */
280     InputSource.prototype.getInputSourceStatus = function (successCallback, errorCallback) {
281     
282         log("getInputSourceStatus: ");
283         
284         
285     
286         service.Request("luna://com.webos.service.eim/", {
287             method : "getAllInputStatus",
288             onSuccess : function(result) {
289                 log("getInputSourceStatus: On Success");
290 
291                 if (result.returnValue === true) {
292                     if (successCallback && typeof successCallback === 'function') {
293                         
294                         checkPlatformVersion(function(ver){
295                             
296                             log("convertInputSource: " + JSON.stringify(result.totalCount));
297                             log("convertInputSource: " + JSON.stringify(result.devices));
298                             log("version: " + ver);
299                             
300                             
301                             var cbObj = {};
302                             var inputList = new Array(result.totalCount);
303                             var convertList = new Array(result.totalCount);
304                             
305                             for (var i=0; i<inputList.length; i++) {
306                                 inputList[i] = {};
307                                 inputList[i].inputPort = parseInputSource(result.devices[i].label);
308                                 
309                                 
310                                 switch (ver) {
311                                 case 1 :
312                                     // fixed input for hdmi:3, hdmi:4. requested by youngjun.lee
313                                     var tempInputSource = result.devices[i].id.split("_");
314                                     inputList[i].inputPort = 'ext://' + tempInputSource[0].toLowerCase() + ':' + tempInputSource[1];
315                                     if (inputList[i].inputPort === 'ext://hdmi:3') {
316                                         inputList[i].inputPort = 'ext://dp:1';
317                                     } else if (inputList[i].inputPort === 'ext://hdmi:4') {
318                                         inputList[i].inputPort = 'ext://dvi:1';
319                                     }
320                                     // end
321                                     
322                                     break;
323                                 case 2 :
324                                     
325                                     var tempInputSource = result.devices[i].id.split("_");
326                                     inputList[i].inputPort = 'ext://' + tempInputSource[0].toLowerCase() + ':' + tempInputSource[1];
327                                     if (inputList[i].inputPort === 'ext://hdmi:3') {
328                                         inputList[i].inputPort = 'ext://dp:1';
329                                     } else if (inputList[i].inputPort === 'ext://hdmi:2') {
330                                         inputList[i].inputPort = 'ext://dvi:1';
331                                     } else if (inputList[i].inputPort === 'ext://hdmi:4') {
332                                         inputList[i].inputPort = 'ext://ops:1';
333                                     }
334                                     break;
335                                 default :
336                                     break;
337                                 }
338                                 
339                                 convertList[i] = {};
340                                 convertList[i].inputPort = inputList[i].inputPort;
341                                 convertList[i].id = result.devices[i].id;
342                             }
343                             
344                             cbObj.inputSourceList = inputList;
345                         
346                             service.Request("luna://com.webos.service.eim/", {
347                                 method : "getCurrentInput",
348                                 parameters : {},
349                                 onSuccess : function(result) {
350                                     log("InputSource.getInputSourceStatus: On Success 3");
351                                     
352                                     if (result.returnValue === true) {
353                                         
354                                         if (successCallback && typeof successCallback === 'function') {
355                                             
356                                             cbObj.currentInputSource = {};
357                                             
358                                             for (var i=0; i<convertList.length; i++) {
359                                                 if (convertList[i].id === result.mainInputSourceId) {
360                                                     cbObj.currentInputSource = convertList[i].inputPort;
361                                                     break;
362                                                 }
363                                             }
364                                             
365                                             cbObj.currentSignalState = "unknown";
366                                             
367                                             if (broadcast !== null) {
368                                                 log("InputSource.getInputSourceStatus : broadcast is not null");
369                                                 
370                                                 broadcast.getSignalStatus(function successCb(cbObject) {
371                                                     
372                                                     cbObj.currentSignalState = cbObject.videoSignalState;
373                                                     log("InputSource.getInputSourceStatus: On Success 2");
374     
375                                                     if (successCallback && typeof successCallback === 'function') {
376                                                         log("getInputSourceStatus: On Success" + JSON.stringify(cbObj));
377                                                         successCallback(cbObj);
378                                                         return;
379                                                     }
380                                                     
381                                                 }, function failureCb() {
382                                                     
383                                                     log("InputSource.getInputSourceStatus : signal state is fail.");
384                                                     if (successCallback && typeof successCallback === 'function') {
385                                                         log("getInputSourceStatus: On Success" + JSON.stringify(cbObj));
386                                                         successCallback(cbObj);
387                                                         return;
388                                                     }
389                                                 });
390                                                 
391                                             } else {
392                                                 
393                                                 log("InputSource.getInputSourceStatus : it does not initialize.");
394                                                 if (successCallback && typeof successCallback === 'function') {
395                                                     log("getInputSourceStatus: On Success" + JSON.stringify(cbObj));
396                                                     successCallback(cbObj);
397                                                     return;
398                                                 }
399                                             }
400                                         }
401                                     }
402                                 },
403                                 onFailure : function(result) {
404                                     log("InputSource.getInputSourceStatus: On Failure 2");
405                                     delete result.returnValue;
406                                     if (errorCallback && typeof errorCallback === 'function') {
407                                         checkErrorCodeNText(result, "IGISS", "InputSource.getInputSourceStatus returns failure.");
408                                         errorCallback(result);
409                                         return;
410                                     }
411                                 }
412                             });
413                         }); // check version
414                     } //  if (successCallback && typeof successCallback === 'function') { 
415                 } // if (result.returnValue === true) {
416             },
417             onFailure : function(result) {
418                 log("getInputSourceStatus: On Failure");
419                 delete result.returnValue;
420                 if (errorCallback && typeof errorCallback === 'function') {
421                     checkErrorCodeNText(result, "IGISS", "InputSource.changeInputSource returns failure on gathering input list.");
422                     errorCallback(result);
423                 }
424             }
425         });
426                 
427     log("InputSource.getInputSourceStatus Done");
428     
429     };
430     
431     function parseInputSource(str) {
432         
433         var index = 1;
434         var length = str.length;
435         
436         if (!isNaN(parseInt(str.charAt(length-1), 10))) {
437             // has number
438             index = str.charAt(length-1);
439             length--;
440         }
441         
442         str = str.substring(0, length) +":"+ index;
443         str = "ext://" + str.toLowerCase();
444         
445         return str;
446     }
447     
448     var version = null;
449     function checkPlatformVersion(cb) {
450         
451         if (version === null) {
452             
453             service.Request('luna://com.webos.service.tv.systemproperty', {
454                 method: 'getSystemInfo',
455                 parameters: {
456                     keys: ["sdkVersion"]
457                 },
458                 onSuccess: function(result) {
459                     log("getPlatformInfo: onSuccess");
460                     
461                     var temp = result.sdkVersion.split('.');
462                     if (temp.length >= 1 && temp[0] === '1') {
463                         version = 1;
464                     } else if (temp.length >= 1 && temp[0] === '2') {
465                         version = 2;
466                     } else {
467                         version = 0;
468                     }
469                     
470                     delete result.returnValue;
471                     
472                     cb(version);
473                     
474                 },
475                 onFailure: function(error) {
476                     log("getPlatformInfo: onFailure");
477                     delete error.returnValue;
478                     version = 0;
479                     
480                     cb(version);
481                 }
482             });
483             
484         } else {
485             cb(version);
486         }
487     }
488     
489     function convertInputSource(inputSource, successCallback, errorCallback) {
490         
491         service.Request("luna://com.webos.service.eim/", {
492             method : "getAllInputStatus",
493             onSuccess : function(result) {
494                 log("convertInputSource: On Success " + inputSource);
495 
496                 if (result.returnValue === true) {
497                     if (successCallback && typeof successCallback === 'function') {
498                         var inputList = new Array(result.totalCount);
499                         
500                         checkPlatformVersion(function(ver){
501                             
502                             log("convertInputSource: " + JSON.stringify(result.totalCount));
503                             log("convertInputSource: " + JSON.stringify(result.devices));
504                             log("version: " + ver);
505                             
506                             switch (ver) {
507                             case 1 :
508                                 // fixed input for hdmi:3, hdmi:4. requested by youngjun.lee
509                                 if (inputSource === 'ext://dp:1') {
510                                     inputSource = 'ext://hdmi:3';
511                                 } else if (inputSource === 'ext://dvi:1') {
512                                     inputSource = 'ext://hdmi:4';
513                                 }
514                                 // end
515                                 break;
516                             case 2 :
517                                 if (inputSource === 'ext://dp:1') {
518                                     inputSource = 'ext://hdmi:3';
519                                 } else if (inputSource === 'ext://dvi:1') {
520                                     inputSource = 'ext://hdmi:2';
521                                 } else if (inputSource === 'ext://ops:1') {
522                                     inputSource = 'ext://hdmi:4';
523                                 }
524                                 break;
525                             default :
526                                 break;
527                             }
528                                                     
529                             for (var i=0; i<inputList.length; i++) {
530                                 inputList[i] = {};
531                                 inputList[i].inputPort = parseInputSource(result.devices[i].label);
532                                 var tempInputSource = result.devices[i].id.split("_");
533                                 inputList[i].id = 'ext://' + tempInputSource[0].toLowerCase() + ':' + tempInputSource[1];
534                                 
535                                 if (inputSource === inputList[i].id) {
536                                     // ok
537                                     log("convertInputSource: On Success ok " + inputSource);
538                                     successCallback(inputSource);
539                                     return;
540                                 }
541                             }
542                             
543                             for (var j=0; j<inputList.length; j++) {
544                                 if (inputSource === inputList[j].inputPort) {
545                                     // convert source
546                                     inputSource = inputList[j].id;
547                                     log("convertInputSource: On Success converted " + inputSource);
548                                     successCallback(inputSource);
549                                     return;
550                                 }
551                             }
552                             
553                             log("convertInputSource: On Failure " + inputSource);
554                             var errResult = {};
555                             checkErrorCodeNText(errResult, "IGISS", "convertInputSource. It does not support inputsource type.");
556                             errorCallback(errResult);
557                             
558                             
559                         });
560                         
561                     }
562                 }
563             },
564             onFailure : function(result) {
565                 log("convertInputSource: On Failure");
566                 delete result.returnValue;
567                 if (errorCallback && typeof errorCallback === 'function') {
568                     checkErrorCodeNText(result, "IGISS", "convertInputSource returns failure on gathering input list.");
569                     errorCallback(result);
570                 }
571             }
572         });
573     
574         
575     }
576 
577     module.exports = InputSource;
578 });
579 
580 InputSource = cordova.require('cordova/plugin/inputSource'); // jshint ignore:line
581 
582 
583 
584 
585