]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
Merge branch 1.0-bugfix
[vlc] / projects / mozilla / control / npolibvlc.cpp
1 /*****************************************************************************
2  * npolibvlc.cpp: official Javascript APIs
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *          JP Dinger <jpd@m2x.nl>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 /* Mozilla stuff */
31 #ifdef HAVE_MOZILLA_CONFIG_H
32 #   include <mozilla-config.h>
33 #endif
34
35 #include "vlcplugin.h"
36 #include "npolibvlc.h"
37
38 /*
39 ** Local helper macros and function
40 */
41 #define COUNTNAMES(a,b,c) const int a::b = sizeof(a::c)/sizeof(NPUTF8 *)
42 #define RETURN_ON_EXCEPTION(this,ex) \
43     do { if( libvlc_exception_raised(&ex) ) \
44     { \
45         NPN_SetException(this, libvlc_exception_get_message(&ex)); \
46         libvlc_exception_clear(&ex); \
47         return INVOKERESULT_GENERIC_ERROR; \
48     } } while(false)
49
50 /*
51 ** implementation of libvlc root object
52 */
53
54 LibvlcRootNPObject::~LibvlcRootNPObject()
55 {
56     /*
57     ** When the plugin is destroyed, firefox takes it upon itself to
58     ** destroy all 'live' script objects and ignores refcounting.
59     ** Therefore we cannot safely assume that refcounting will control
60     ** lifespan of objects. Hence they are only lazily created on
61     ** request, so that firefox can take ownership, and are not released
62     ** when the plugin is destroyed.
63     */
64     if( isValid() )
65     {
66         if( audioObj    ) NPN_ReleaseObject(audioObj);
67         if( inputObj    ) NPN_ReleaseObject(inputObj);
68         if( playlistObj ) NPN_ReleaseObject(playlistObj);
69         if( videoObj    ) NPN_ReleaseObject(videoObj);
70     }
71 }
72
73 const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
74 {
75     "audio",
76     "input",
77     "playlist",
78     "video",
79     "VersionInfo",
80 };
81 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
82
83 enum LibvlcRootNPObjectPropertyIds
84 {
85     ID_root_audio = 0,
86     ID_root_input,
87     ID_root_playlist,
88     ID_root_video,
89     ID_root_VersionInfo,
90 };
91
92 RuntimeNPObject::InvokeResult
93 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
94 {
95     /* is plugin still running */
96     if( isPluginRunning() )
97     {
98         switch( index )
99         {
100             case ID_root_audio:
101                 // create child object in lazyman fashion to avoid
102                 // ownership problem with firefox
103                 if( ! audioObj )
104                     audioObj = NPN_CreateObject(_instance,
105                              RuntimeNPClass<LibvlcAudioNPObject>::getClass());
106                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
107                 return INVOKERESULT_NO_ERROR;
108             case ID_root_input:
109                 // create child object in lazyman fashion to avoid
110                 // ownership problem with firefox
111                 if( ! inputObj )
112                     inputObj = NPN_CreateObject(_instance,
113                              RuntimeNPClass<LibvlcInputNPObject>::getClass());
114                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
115                 return INVOKERESULT_NO_ERROR;
116             case ID_root_playlist:
117                 // create child object in lazyman fashion to avoid
118                 // ownership problem with firefox
119                 if( ! playlistObj )
120                     playlistObj = NPN_CreateObject(_instance,
121                           RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());
122                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
123                 return INVOKERESULT_NO_ERROR;
124             case ID_root_video:
125                 // create child object in lazyman fashion to avoid
126                 // ownership problem with firefox
127                 if( ! videoObj )
128                     videoObj = NPN_CreateObject(_instance,
129                              RuntimeNPClass<LibvlcVideoNPObject>::getClass());
130                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
131                 return INVOKERESULT_NO_ERROR;
132             case ID_root_VersionInfo:
133                 return invokeResultString(libvlc_get_version(),result);
134             default:
135                 ;
136         }
137     }
138     return INVOKERESULT_GENERIC_ERROR;
139 }
140
141 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
142 {
143     "versionInfo",
144 };
145 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
146
147 enum LibvlcRootNPObjectMethodIds
148 {
149     ID_root_versionInfo,
150 };
151
152 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
153                   const NPVariant *args, uint32_t argCount, NPVariant &result)
154 {
155     /* is plugin still running */
156     if( isPluginRunning() )
157     {
158         libvlc_exception_t ex;
159         libvlc_exception_init(&ex);
160
161         switch( index )
162         {
163             case ID_root_versionInfo:
164                 if( 0 != argCount )
165                     return INVOKERESULT_NO_SUCH_METHOD;
166                 return invokeResultString(libvlc_get_version(),result);
167             default:
168                 ;
169         }
170     }
171     return INVOKERESULT_GENERIC_ERROR;
172 }
173
174 /*
175 ** implementation of libvlc audio object
176 */
177
178 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
179 {
180     "mute",
181     "volume",
182     "track",
183     "channel",
184 };
185 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
186
187 enum LibvlcAudioNPObjectPropertyIds
188 {
189     ID_audio_mute,
190     ID_audio_volume,
191     ID_audio_track,
192     ID_audio_channel,
193 };
194
195 RuntimeNPObject::InvokeResult
196 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
197 {
198     /* is plugin still running */
199     if( isPluginRunning() )
200     {
201         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
202         libvlc_exception_t ex;
203         libvlc_exception_init(&ex);
204
205         switch( index )
206         {
207             case ID_audio_mute:
208             {
209                 bool muted = libvlc_audio_get_mute(p_plugin->getVLC(), &ex);
210                 RETURN_ON_EXCEPTION(this,ex);
211                 BOOLEAN_TO_NPVARIANT(muted, result);
212                 return INVOKERESULT_NO_ERROR;
213             }
214             case ID_audio_volume:
215             {
216                 int volume = libvlc_audio_get_volume(p_plugin->getVLC(), &ex);
217                 RETURN_ON_EXCEPTION(this,ex);
218                 INT32_TO_NPVARIANT(volume, result);
219                 return INVOKERESULT_NO_ERROR;
220             }
221             case ID_audio_track:
222             {
223                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
224                 RETURN_ON_EXCEPTION(this,ex);
225                 int track = libvlc_audio_get_track(p_md, &ex);
226                 RETURN_ON_EXCEPTION(this,ex);
227                 INT32_TO_NPVARIANT(track, result);
228                 return INVOKERESULT_NO_ERROR;
229             }
230             case ID_audio_channel:
231             {
232                 int channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
233                 RETURN_ON_EXCEPTION(this,ex);
234                 INT32_TO_NPVARIANT(channel, result);
235                 return INVOKERESULT_NO_ERROR;
236             }
237             default:
238                 ;
239         }
240     }
241     return INVOKERESULT_GENERIC_ERROR;
242 }
243
244 RuntimeNPObject::InvokeResult
245 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
246 {
247     /* is plugin still running */
248     if( isPluginRunning() )
249     {
250         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
251         libvlc_exception_t ex;
252         libvlc_exception_init(&ex);
253
254         switch( index )
255         {
256             case ID_audio_mute:
257                 if( NPVARIANT_IS_BOOLEAN(value) )
258                 {
259                     libvlc_audio_set_mute(p_plugin->getVLC(),
260                                           NPVARIANT_TO_BOOLEAN(value), &ex);
261                     RETURN_ON_EXCEPTION(this,ex);
262                     return INVOKERESULT_NO_ERROR;
263                 }
264                 return INVOKERESULT_INVALID_VALUE;
265             case ID_audio_volume:
266                 if( isNumberValue(value) )
267                 {
268                     libvlc_audio_set_volume(p_plugin->getVLC(),
269                                             numberValue(value), &ex);
270                     RETURN_ON_EXCEPTION(this,ex);
271                     return INVOKERESULT_NO_ERROR;
272                 }
273                 return INVOKERESULT_INVALID_VALUE;
274             case ID_audio_track:
275                 if( isNumberValue(value) )
276                 {
277                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
278                     RETURN_ON_EXCEPTION(this,ex);
279                     libvlc_audio_set_track(p_md, numberValue(value), &ex);
280                     RETURN_ON_EXCEPTION(this,ex);
281                     return INVOKERESULT_NO_ERROR;
282                 }
283                 return INVOKERESULT_INVALID_VALUE;
284             case ID_audio_channel:
285                 if( isNumberValue(value) )
286                 {
287                     libvlc_audio_set_channel(p_plugin->getVLC(),
288                                              numberValue(value), &ex);
289                     RETURN_ON_EXCEPTION(this,ex);
290                     return INVOKERESULT_NO_ERROR;
291                 }
292                 return INVOKERESULT_INVALID_VALUE;
293             default:
294                 ;
295         }
296     }
297     return INVOKERESULT_GENERIC_ERROR;
298 }
299
300 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
301 {
302     "toggleMute",
303 };
304 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
305
306 enum LibvlcAudioNPObjectMethodIds
307 {
308     ID_audio_togglemute,
309 };
310
311 RuntimeNPObject::InvokeResult
312 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
313                             uint32_t argCount, NPVariant &result)
314 {
315     /* is plugin still running */
316     if( isPluginRunning() )
317     {
318         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
319         libvlc_exception_t ex;
320         libvlc_exception_init(&ex);
321
322         switch( index )
323         {
324             case ID_audio_togglemute:
325                 if( argCount == 0 )
326                 {
327                     libvlc_audio_toggle_mute(p_plugin->getVLC(), &ex);
328                     RETURN_ON_EXCEPTION(this,ex);
329                     VOID_TO_NPVARIANT(result);
330                     return INVOKERESULT_NO_ERROR;
331                 }
332                 return INVOKERESULT_NO_SUCH_METHOD;
333             default:
334                 ;
335         }
336     }
337     return INVOKERESULT_GENERIC_ERROR;
338 }
339
340 /*
341 ** implementation of libvlc input object
342 */
343
344 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] =
345 {
346     "length",
347     "position",
348     "time",
349     "state",
350     "rate",
351     "fps",
352     "hasVout",
353 };
354 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
355
356 enum LibvlcInputNPObjectPropertyIds
357 {
358     ID_input_length,
359     ID_input_position,
360     ID_input_time,
361     ID_input_state,
362     ID_input_rate,
363     ID_input_fps,
364     ID_input_hasvout,
365 };
366
367 RuntimeNPObject::InvokeResult
368 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
369 {
370     /* is plugin still running */
371     if( isPluginRunning() )
372     {
373         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
374         libvlc_exception_t ex;
375         libvlc_exception_init(&ex);
376
377         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
378         if( libvlc_exception_raised(&ex) )
379         {
380             if( index != ID_input_state )
381             {
382                 NPN_SetException(this, libvlc_exception_get_message(&ex));
383                 libvlc_exception_clear(&ex);
384                 return INVOKERESULT_GENERIC_ERROR;
385             }
386             else
387             {
388                 /* for input state, return CLOSED rather than an exception */
389                 INT32_TO_NPVARIANT(0, result);
390                 libvlc_exception_clear(&ex);
391                 return INVOKERESULT_NO_ERROR;
392             }
393         }
394
395         switch( index )
396         {
397             case ID_input_length:
398             {
399                 double val = (double)libvlc_media_player_get_length(p_md, &ex);
400                 RETURN_ON_EXCEPTION(this,ex);
401                 DOUBLE_TO_NPVARIANT(val, result);
402                 return INVOKERESULT_NO_ERROR;
403             }
404             case ID_input_position:
405             {
406                 double val = libvlc_media_player_get_position(p_md, &ex);
407                 RETURN_ON_EXCEPTION(this,ex);
408                 DOUBLE_TO_NPVARIANT(val, result);
409                 return INVOKERESULT_NO_ERROR;
410             }
411             case ID_input_time:
412             {
413                 double val = (double)libvlc_media_player_get_time(p_md, &ex);
414                 RETURN_ON_EXCEPTION(this,ex);
415                 DOUBLE_TO_NPVARIANT(val, result);
416                 return INVOKERESULT_NO_ERROR;
417             }
418             case ID_input_state:
419             {
420                 int val = libvlc_media_player_get_state(p_md, &ex);
421                 RETURN_ON_EXCEPTION(this,ex);
422                 INT32_TO_NPVARIANT(val, result);
423                 return INVOKERESULT_NO_ERROR;
424             }
425             case ID_input_rate:
426             {
427                 float val = libvlc_media_player_get_rate(p_md, &ex);
428                 RETURN_ON_EXCEPTION(this,ex);
429                 DOUBLE_TO_NPVARIANT(val, result);
430                 return INVOKERESULT_NO_ERROR;
431             }
432             case ID_input_fps:
433             {
434                 double val = libvlc_media_player_get_fps(p_md, &ex);
435                 RETURN_ON_EXCEPTION(this,ex);
436                 DOUBLE_TO_NPVARIANT(val, result);
437                 return INVOKERESULT_NO_ERROR;
438             }
439             case ID_input_hasvout:
440             {
441                 bool val = p_plugin->player_has_vout(&ex);
442                 RETURN_ON_EXCEPTION(this,ex);
443                 BOOLEAN_TO_NPVARIANT(val, result);
444                 return INVOKERESULT_NO_ERROR;
445             }
446             default:
447                 ;
448         }
449     }
450     return INVOKERESULT_GENERIC_ERROR;
451 }
452
453 RuntimeNPObject::InvokeResult
454 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
455 {
456     /* is plugin still running */
457     if( isPluginRunning() )
458     {
459         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
460         libvlc_exception_t ex;
461         libvlc_exception_init(&ex);
462
463         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
464         RETURN_ON_EXCEPTION(this,ex);
465
466         switch( index )
467         {
468             case ID_input_position:
469             {
470                 if( ! NPVARIANT_IS_DOUBLE(value) )
471                 {
472                     return INVOKERESULT_INVALID_VALUE;
473                 }
474
475                 float val = (float)NPVARIANT_TO_DOUBLE(value);
476                 libvlc_media_player_set_position(p_md, val, &ex);
477                 RETURN_ON_EXCEPTION(this,ex);
478                 return INVOKERESULT_NO_ERROR;
479             }
480             case ID_input_time:
481             {
482                 int64_t val;
483                 if( NPVARIANT_IS_INT32(value) )
484                     val = (int64_t)NPVARIANT_TO_INT32(value);
485                 else if( NPVARIANT_IS_DOUBLE(value) )
486                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
487                 else
488                 {
489                     return INVOKERESULT_INVALID_VALUE;
490                 }
491
492                 libvlc_media_player_set_time(p_md, val, &ex);
493                 RETURN_ON_EXCEPTION(this,ex);
494                 return INVOKERESULT_NO_ERROR;
495             }
496             case ID_input_rate:
497             {
498                 float val;
499                 if( NPVARIANT_IS_INT32(value) )
500                     val = (float)NPVARIANT_TO_INT32(value);
501                 else if( NPVARIANT_IS_DOUBLE(value) )
502                     val = (float)NPVARIANT_TO_DOUBLE(value);
503                 else
504                 {
505                     return INVOKERESULT_INVALID_VALUE;
506                 }
507
508                 libvlc_media_player_set_rate(p_md, val, &ex);
509                 RETURN_ON_EXCEPTION(this,ex);
510                 return INVOKERESULT_NO_ERROR;
511             }
512             default:
513                 ;
514         }
515     }
516     return INVOKERESULT_GENERIC_ERROR;
517 }
518
519 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
520 {
521     /* no methods */
522 };
523
524 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
525
526 /*
527 ** implementation of libvlc playlist items object
528 */
529
530 const NPUTF8 * const LibvlcPlaylistItemsNPObject::propertyNames[] =
531 {
532     "count",
533 };
534 COUNTNAMES(LibvlcPlaylistItemsNPObject,propertyCount,propertyNames);
535
536 enum LibvlcPlaylistItemsNPObjectPropertyIds
537 {
538     ID_playlistitems_count,
539 };
540
541 RuntimeNPObject::InvokeResult
542 LibvlcPlaylistItemsNPObject::getProperty(int index, NPVariant &result)
543 {
544     /* is plugin still running */
545     if( isPluginRunning() )
546     {
547         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
548         libvlc_exception_t ex;
549         libvlc_exception_init(&ex);
550
551         switch( index )
552         {
553             case ID_playlistitems_count:
554             {
555                 int val = p_plugin->playlist_count(&ex);
556                 RETURN_ON_EXCEPTION(this,ex);
557                 INT32_TO_NPVARIANT(val, result);
558                 return INVOKERESULT_NO_ERROR;
559             }
560             default:
561                 ;
562         }
563     }
564     return INVOKERESULT_GENERIC_ERROR;
565 }
566
567 const NPUTF8 * const LibvlcPlaylistItemsNPObject::methodNames[] =
568 {
569     "clear",
570     "remove",
571 };
572 COUNTNAMES(LibvlcPlaylistItemsNPObject,methodCount,methodNames);
573
574 enum LibvlcPlaylistItemsNPObjectMethodIds
575 {
576     ID_playlistitems_clear,
577     ID_playlistitems_remove,
578 };
579
580 RuntimeNPObject::InvokeResult
581 LibvlcPlaylistItemsNPObject::invoke(int index, const NPVariant *args,
582                                     uint32_t argCount, NPVariant &result)
583 {
584     /* is plugin still running */
585     if( isPluginRunning() )
586     {
587         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
588         libvlc_exception_t ex;
589         libvlc_exception_init(&ex);
590
591         switch( index )
592         {
593             case ID_playlistitems_clear:
594                 if( argCount == 0 )
595                 {
596                     p_plugin->playlist_clear(&ex);
597                     RETURN_ON_EXCEPTION(this,ex);
598                     VOID_TO_NPVARIANT(result);
599                     return INVOKERESULT_NO_ERROR;
600                 }
601                 return INVOKERESULT_NO_SUCH_METHOD;
602             case ID_playlistitems_remove:
603                 if( (argCount == 1) && isNumberValue(args[0]) )
604                 {
605                     p_plugin->playlist_delete_item(numberValue(args[0]),&ex);
606                     RETURN_ON_EXCEPTION(this,ex);
607                     VOID_TO_NPVARIANT(result);
608                     return INVOKERESULT_NO_ERROR;
609                 }
610                 return INVOKERESULT_NO_SUCH_METHOD;
611             default:
612                 ;
613         }
614     }
615     return INVOKERESULT_GENERIC_ERROR;
616 }
617
618 /*
619 ** implementation of libvlc playlist object
620 */
621
622 LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()
623 {
624     // Why the isValid()?
625     if( isValid() && playlistItemsObj )
626         NPN_ReleaseObject(playlistItemsObj);
627 };
628
629 const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] =
630 {
631     "itemCount", /* deprecated */
632     "isPlaying",
633     "items",
634 };
635 COUNTNAMES(LibvlcPlaylistNPObject,propertyCount,propertyNames);
636
637 enum LibvlcPlaylistNPObjectPropertyIds
638 {
639     ID_playlist_itemcount,
640     ID_playlist_isplaying,
641     ID_playlist_items,
642 };
643
644 RuntimeNPObject::InvokeResult
645 LibvlcPlaylistNPObject::getProperty(int index, NPVariant &result)
646 {
647     /* is plugin still running */
648     if( isPluginRunning() )
649     {
650         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
651         libvlc_exception_t ex;
652         libvlc_exception_init(&ex);
653
654         switch( index )
655         {
656             case ID_playlist_itemcount: /* deprecated */
657             {
658                 int val = p_plugin->playlist_count(&ex);
659                 RETURN_ON_EXCEPTION(this,ex);
660                 INT32_TO_NPVARIANT(val, result);
661                 return INVOKERESULT_NO_ERROR;
662             }
663             case ID_playlist_isplaying:
664             {
665                 int val = p_plugin->playlist_isplaying(&ex);
666                 RETURN_ON_EXCEPTION(this,ex);
667                 BOOLEAN_TO_NPVARIANT(val, result);
668                 return INVOKERESULT_NO_ERROR;
669             }
670             case ID_playlist_items:
671             {
672                 // create child object in lazyman fashion to avoid
673                 // ownership problem with firefox
674                 if( ! playlistItemsObj )
675                     playlistItemsObj =
676                         NPN_CreateObject(_instance, RuntimeNPClass<
677                         LibvlcPlaylistItemsNPObject>::getClass());
678                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
679                 return INVOKERESULT_NO_ERROR;
680             }
681             default:
682                 ;
683         }
684     }
685     return INVOKERESULT_GENERIC_ERROR;
686 }
687
688 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
689 {
690     "add",
691     "play",
692     "playItem",
693     "togglePause",
694     "stop",
695     "next",
696     "prev",
697     "clear", /* deprecated */
698     "removeItem", /* deprecated */
699 };
700 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
701
702 enum LibvlcPlaylistNPObjectMethodIds
703 {
704     ID_playlist_add,
705     ID_playlist_play,
706     ID_playlist_playItem,
707     ID_playlist_togglepause,
708     ID_playlist_stop,
709     ID_playlist_next,
710     ID_playlist_prev,
711     ID_playlist_clear,
712     ID_playlist_removeitem
713 };
714
715 RuntimeNPObject::InvokeResult
716 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
717                                uint32_t argCount, NPVariant &result)
718 {
719     /* is plugin still running */
720     if( isPluginRunning() )
721     {
722         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
723         libvlc_exception_t ex;
724         libvlc_exception_init(&ex);
725
726         switch( index )
727         {
728             // XXX FIXME this needs squashing into something much smaller
729             case ID_playlist_add:
730             {
731                 if( (argCount < 1) || (argCount > 3) )
732                     return INVOKERESULT_NO_SUCH_METHOD;
733
734                 char *url = NULL;
735
736                 // grab URL
737                 if( NPVARIANT_IS_STRING(args[0]) )
738                 {
739                     char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
740                     if( s )
741                     {
742                         url = p_plugin->getAbsoluteURL(s);
743                         if( url )
744                             free(s);
745                         else
746                             // problem with combining url, use argument
747                             url = s;
748                     }
749                     else
750                         return INVOKERESULT_OUT_OF_MEMORY;
751                 }
752                 else
753                     return INVOKERESULT_NO_SUCH_METHOD;
754
755                 char *name = NULL;
756
757                 // grab name if available
758                 if( argCount > 1 )
759                 {
760                     if( NPVARIANT_IS_NULL(args[1]) )
761                     {
762                         // do nothing
763                     }
764                     else if( NPVARIANT_IS_STRING(args[1]) )
765                     {
766                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
767                     }
768                     else
769                     {
770                         free(url);
771                         return INVOKERESULT_INVALID_VALUE;
772                     }
773                 }
774
775                 int i_options = 0;
776                 char** ppsz_options = NULL;
777
778                 // grab options if available
779                 if( argCount > 2 )
780                 {
781                     if( NPVARIANT_IS_NULL(args[2]) )
782                     {
783                         // do nothing
784                     }
785                     else if( NPVARIANT_IS_STRING(args[2]) )
786                     {
787                         parseOptions(NPVARIANT_TO_STRING(args[2]),
788                                      &i_options, &ppsz_options);
789
790                     }
791                     else if( NPVARIANT_IS_OBJECT(args[2]) )
792                     {
793                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
794                                      &i_options, &ppsz_options);
795                     }
796                     else
797                     {
798                         free(url);
799                         free(name);
800                         return INVOKERESULT_INVALID_VALUE;
801                     }
802                 }
803
804                 int item = p_plugin->playlist_add_extended_untrusted(url, name,
805                       i_options, const_cast<const char **>(ppsz_options), &ex);
806                 free(url);
807                 free(name);
808                 for( int i=0; i< i_options; ++i )
809                 {
810                     free(ppsz_options[i]);
811                 }
812                 free(ppsz_options);
813
814                 RETURN_ON_EXCEPTION(this,ex);
815                 INT32_TO_NPVARIANT(item, result);
816                 return INVOKERESULT_NO_ERROR;
817             }
818             case ID_playlist_play:
819                 if( argCount == 0 )
820                 {
821                     p_plugin->playlist_play(&ex);
822                     RETURN_ON_EXCEPTION(this,ex);
823                     VOID_TO_NPVARIANT(result);
824                     return INVOKERESULT_NO_ERROR;
825                 }
826                 return INVOKERESULT_NO_SUCH_METHOD;
827             case ID_playlist_playItem:
828                 if( (argCount == 1) && isNumberValue(args[0]) )
829                 {
830                     p_plugin->playlist_play_item(numberValue(args[0]),&ex);
831                     RETURN_ON_EXCEPTION(this,ex);
832                     VOID_TO_NPVARIANT(result);
833                     return INVOKERESULT_NO_ERROR;
834                 }
835                 return INVOKERESULT_NO_SUCH_METHOD;
836             case ID_playlist_togglepause:
837                 if( argCount == 0 )
838                 {
839                     p_plugin->playlist_pause(&ex);
840                     RETURN_ON_EXCEPTION(this,ex);
841                     VOID_TO_NPVARIANT(result);
842                     return INVOKERESULT_NO_ERROR;
843                 }
844                 return INVOKERESULT_NO_SUCH_METHOD;
845             case ID_playlist_stop:
846                 if( argCount == 0 )
847                 {
848                     p_plugin->playlist_stop(&ex);
849                     RETURN_ON_EXCEPTION(this,ex);
850                     VOID_TO_NPVARIANT(result);
851                     return INVOKERESULT_NO_ERROR;
852                 }
853                 return INVOKERESULT_NO_SUCH_METHOD;
854             case ID_playlist_next:
855                 if( argCount == 0 )
856                 {
857                     p_plugin->playlist_next(&ex);
858                     RETURN_ON_EXCEPTION(this,ex);
859                     VOID_TO_NPVARIANT(result);
860                     return INVOKERESULT_NO_ERROR;
861                 }
862                 return INVOKERESULT_NO_SUCH_METHOD;
863             case ID_playlist_prev:
864                 if( argCount == 0 )
865                 {
866                     p_plugin->playlist_prev(&ex);
867                     RETURN_ON_EXCEPTION(this,ex);
868                     VOID_TO_NPVARIANT(result);
869                     return INVOKERESULT_NO_ERROR;
870                 }
871                 return INVOKERESULT_NO_SUCH_METHOD;
872             case ID_playlist_clear: /* deprecated */
873                 if( argCount == 0 )
874                 {
875                     p_plugin->playlist_clear(&ex);
876                     RETURN_ON_EXCEPTION(this,ex);
877                     VOID_TO_NPVARIANT(result);
878                     return INVOKERESULT_NO_ERROR;
879                 }
880                 return INVOKERESULT_NO_SUCH_METHOD;
881             case ID_playlist_removeitem: /* deprecated */
882                 if( (argCount == 1) && isNumberValue(args[0]) )
883                 {
884                     p_plugin->playlist_delete_item(numberValue(args[0]), &ex);
885                     RETURN_ON_EXCEPTION(this,ex);
886                     VOID_TO_NPVARIANT(result);
887                     return INVOKERESULT_NO_ERROR;
888                 }
889                 return INVOKERESULT_NO_SUCH_METHOD;
890             default:
891                 ;
892         }
893     }
894     return INVOKERESULT_GENERIC_ERROR;
895 }
896
897 // XXX FIXME The new playlist_add creates a media instance and feeds it
898 // XXX FIXME these options one at a time, so this hunk of code does lots
899 // XXX FIXME of unnecessairy work. Break out something that can do one
900 // XXX FIXME option at a time and doesn't need to realloc().
901 // XXX FIXME Same for the other version of parseOptions.
902
903 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
904                                          int *i_options, char*** ppsz_options)
905 {
906     if( nps.utf8length )
907     {
908         char *s = stringValue(nps);
909         char *val = s;
910         if( val )
911         {
912             long capacity = 16;
913             char **options = (char **)malloc(capacity*sizeof(char *));
914             if( options )
915             {
916                 int nOptions = 0;
917
918                 char *end = val + nps.utf8length;
919                 while( val < end )
920                 {
921                     // skip leading blanks
922                     while( (val < end)
923                         && ((*val == ' ' ) || (*val == '\t')) )
924                         ++val;
925
926                     char *start = val;
927                     // skip till we get a blank character
928                     while( (val < end)
929                         && (*val != ' ' )
930                         && (*val != '\t') )
931                     {
932                         char c = *(val++);
933                         if( ('\'' == c) || ('"' == c) )
934                         {
935                             // skip till end of string
936                             while( (val < end) && (*(val++) != c ) );
937                         }
938                     }
939
940                     if( val > start )
941                     {
942                         if( nOptions == capacity )
943                         {
944                             capacity += 16;
945                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
946                             if( ! moreOptions )
947                             {
948                                 /* failed to allocate more memory */
949                                 free(s);
950                                 /* return what we got so far */
951                                 *i_options = nOptions;
952                                 *ppsz_options = options;
953                                 return;
954                             }
955                             options = moreOptions;
956                         }
957                         *(val++) = '\0';
958                         options[nOptions++] = strdup(start);
959                     }
960                     else
961                         // must be end of string
962                         break;
963                 }
964                 *i_options = nOptions;
965                 *ppsz_options = options;
966             }
967             free(s);
968         }
969     }
970 }
971
972 // XXX FIXME See comment at the other parseOptions variant.
973 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
974                                           char*** ppsz_options)
975 {
976     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
977
978     NPVariant value;
979
980     /* we are expecting to have a Javascript Array object */
981     NPIdentifier propId = NPN_GetStringIdentifier("length");
982     if( NPN_GetProperty(_instance, obj, propId, &value) )
983     {
984         int count = numberValue(value);
985         NPN_ReleaseVariantValue(&value);
986
987         if( count )
988         {
989             long capacity = 16;
990             char **options = (char **)malloc(capacity*sizeof(char *));
991             if( options )
992             {
993                 int nOptions = 0;
994
995                 while( nOptions < count )
996                 {
997                     propId = NPN_GetIntIdentifier(nOptions);
998                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
999                         /* return what we got so far */
1000                         break;
1001
1002                     if( ! NPVARIANT_IS_STRING(value) )
1003                     {
1004                         /* return what we got so far */
1005                         NPN_ReleaseVariantValue(&value);
1006                         break;
1007                     }
1008
1009                     if( nOptions == capacity )
1010                     {
1011                         capacity += 16;
1012                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1013                         if( ! moreOptions )
1014                         {
1015                             /* failed to allocate more memory */
1016                             NPN_ReleaseVariantValue(&value);
1017                             /* return what we got so far */
1018                             *i_options = nOptions;
1019                             *ppsz_options = options;
1020                             break;
1021                         }
1022                         options = moreOptions;
1023                     }
1024
1025                     options[nOptions++] = stringValue(value);
1026                 }
1027                 *i_options = nOptions;
1028                 *ppsz_options = options;
1029             }
1030         }
1031     }
1032 }
1033
1034 /*
1035 ** implementation of libvlc video object
1036 */
1037
1038 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
1039 {
1040     "fullscreen",
1041     "height",
1042     "width",
1043     "aspectRatio",
1044     "subtitle",
1045     "crop",
1046     "teletext"
1047 };
1048
1049 enum LibvlcVideoNPObjectPropertyIds
1050 {
1051     ID_video_fullscreen,
1052     ID_video_height,
1053     ID_video_width,
1054     ID_video_aspectratio,
1055     ID_video_subtitle,
1056     ID_video_crop,
1057     ID_video_teletext
1058 };
1059 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1060
1061 RuntimeNPObject::InvokeResult
1062 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1063 {
1064     /* is plugin still running */
1065     if( isPluginRunning() )
1066     {
1067         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1068         libvlc_exception_t ex;
1069         libvlc_exception_init(&ex);
1070
1071         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1072         RETURN_ON_EXCEPTION(this,ex);
1073
1074         switch( index )
1075         {
1076             case ID_video_fullscreen:
1077             {
1078                 int val = p_plugin->get_fullscreen(&ex);
1079                 RETURN_ON_EXCEPTION(this,ex);
1080                 BOOLEAN_TO_NPVARIANT(val, result);
1081                 return INVOKERESULT_NO_ERROR;
1082             }
1083             case ID_video_height:
1084             {
1085                 int val = libvlc_video_get_height(p_md, &ex);
1086                 RETURN_ON_EXCEPTION(this,ex);
1087                 INT32_TO_NPVARIANT(val, result);
1088                 return INVOKERESULT_NO_ERROR;
1089             }
1090             case ID_video_width:
1091             {
1092                 int val = libvlc_video_get_width(p_md, &ex);
1093                 RETURN_ON_EXCEPTION(this,ex);
1094                 INT32_TO_NPVARIANT(val, result);
1095                 return INVOKERESULT_NO_ERROR;
1096             }
1097             case ID_video_aspectratio:
1098             {
1099                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1100                 RETURN_ON_EXCEPTION(this,ex);
1101                 if( !psz_aspect )
1102                     return INVOKERESULT_GENERIC_ERROR;
1103
1104                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1105                 return INVOKERESULT_NO_ERROR;
1106             }
1107             case ID_video_subtitle:
1108             {
1109                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1110                 RETURN_ON_EXCEPTION(this,ex);
1111                 INT32_TO_NPVARIANT(i_spu, result);
1112                 return INVOKERESULT_NO_ERROR;
1113             }
1114             case ID_video_crop:
1115             {
1116                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1117                 RETURN_ON_EXCEPTION(this,ex);
1118                 if( !psz_geometry )
1119                     return INVOKERESULT_GENERIC_ERROR;
1120
1121                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1122                 return INVOKERESULT_NO_ERROR;
1123             }
1124             case ID_video_teletext:
1125             {
1126                 int i_page = libvlc_video_get_teletext(p_md, &ex);
1127                 RETURN_ON_EXCEPTION(this,ex);
1128                 INT32_TO_NPVARIANT(i_page, result);
1129                 return INVOKERESULT_NO_ERROR;
1130             }
1131         }
1132     }
1133     return INVOKERESULT_GENERIC_ERROR;
1134 }
1135
1136 RuntimeNPObject::InvokeResult
1137 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1138 {
1139     /* is plugin still running */
1140     if( isPluginRunning() )
1141     {
1142         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1143         libvlc_exception_t ex;
1144         libvlc_exception_init(&ex);
1145
1146         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1147         RETURN_ON_EXCEPTION(this,ex);
1148
1149         switch( index )
1150         {
1151             case ID_video_fullscreen:
1152             {
1153                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1154                 {
1155                     return INVOKERESULT_INVALID_VALUE;
1156                 }
1157
1158                 int val = NPVARIANT_TO_BOOLEAN(value);
1159                 p_plugin->set_fullscreen(val, &ex);
1160                 RETURN_ON_EXCEPTION(this,ex);
1161                 return INVOKERESULT_NO_ERROR;
1162             }
1163             case ID_video_aspectratio:
1164             {
1165                 char *psz_aspect = NULL;
1166
1167                 if( ! NPVARIANT_IS_STRING(value) )
1168                 {
1169                     return INVOKERESULT_INVALID_VALUE;
1170                 }
1171
1172                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1173                 if( !psz_aspect )
1174                 {
1175                     return INVOKERESULT_GENERIC_ERROR;
1176                 }
1177
1178                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1179                 free(psz_aspect);
1180                 RETURN_ON_EXCEPTION(this,ex);
1181
1182                 return INVOKERESULT_NO_ERROR;
1183             }
1184             case ID_video_subtitle:
1185             {
1186                 if( isNumberValue(value) )
1187                 {
1188                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1189                     RETURN_ON_EXCEPTION(this,ex);
1190
1191                     return INVOKERESULT_NO_ERROR;
1192                 }
1193                 return INVOKERESULT_INVALID_VALUE;
1194             }
1195             case ID_video_crop:
1196             {
1197                 char *psz_geometry = NULL;
1198
1199                 if( ! NPVARIANT_IS_STRING(value) )
1200                 {
1201                     return INVOKERESULT_INVALID_VALUE;
1202                 }
1203
1204                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1205                 if( !psz_geometry )
1206                 {
1207                     return INVOKERESULT_GENERIC_ERROR;
1208                 }
1209
1210                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1211                 free(psz_geometry);
1212                 RETURN_ON_EXCEPTION(this,ex);
1213
1214                 return INVOKERESULT_NO_ERROR;
1215             }
1216             case ID_video_teletext:
1217             {
1218                 if( isNumberValue(value) )
1219                 {
1220                     libvlc_video_set_teletext(p_md, numberValue(value), &ex);
1221                     RETURN_ON_EXCEPTION(this,ex);
1222
1223                     return INVOKERESULT_NO_ERROR;
1224                 }
1225                 return INVOKERESULT_INVALID_VALUE;
1226             }
1227         }
1228     }
1229     return INVOKERESULT_GENERIC_ERROR;
1230 }
1231
1232 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1233 {
1234     "toggleFullscreen",
1235     "toggleTeletext"
1236 };
1237 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1238
1239 enum LibvlcVideoNPObjectMethodIds
1240 {
1241     ID_video_togglefullscreen,
1242     ID_video_toggleteletext
1243 };
1244
1245 RuntimeNPObject::InvokeResult
1246 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1247                             uint32_t argCount, NPVariant &result)
1248 {
1249     /* is plugin still running */
1250     if( isPluginRunning() )
1251     {
1252         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1253         libvlc_exception_t ex;
1254         libvlc_exception_init(&ex);
1255
1256         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1257         RETURN_ON_EXCEPTION(this,ex);
1258
1259         switch( index )
1260         {
1261             case ID_video_togglefullscreen:
1262                 if( argCount == 0 )
1263                 {
1264                     p_plugin->toggle_fullscreen(&ex);
1265                     RETURN_ON_EXCEPTION(this,ex);
1266                     VOID_TO_NPVARIANT(result);
1267                     return INVOKERESULT_NO_ERROR;
1268                 }
1269                 return INVOKERESULT_NO_SUCH_METHOD;
1270             case ID_video_toggleteletext:
1271                 if( argCount == 0 )
1272                 {
1273                     libvlc_toggle_teletext(p_md, &ex);
1274                     RETURN_ON_EXCEPTION(this,ex);
1275                     VOID_TO_NPVARIANT(result);
1276                     return INVOKERESULT_NO_ERROR;
1277                 }
1278                 return INVOKERESULT_NO_SUCH_METHOD;
1279             default:
1280                 return INVOKERESULT_NO_SUCH_METHOD;
1281         }
1282     }
1283     return INVOKERESULT_GENERIC_ERROR;
1284 }