]> git.sesse.net Git - vlc/blob - projects/mozilla/control/npolibvlc.cpp
moz-plugin: Improve subtitle and audio track JS bindings
[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     "subtitle",
79     "video",
80     "VersionInfo",
81 };
82 COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
83
84 enum LibvlcRootNPObjectPropertyIds
85 {
86     ID_root_audio = 0,
87     ID_root_input,
88     ID_root_playlist,
89     ID_root_subtitle,
90     ID_root_video,
91     ID_root_VersionInfo,
92 };
93
94 RuntimeNPObject::InvokeResult
95 LibvlcRootNPObject::getProperty(int index, NPVariant &result)
96 {
97     /* is plugin still running */
98     if( isPluginRunning() )
99     {
100         switch( index )
101         {
102             case ID_root_audio:
103                 // create child object in lazyman fashion to avoid
104                 // ownership problem with firefox
105                 if( ! audioObj )
106                     audioObj = NPN_CreateObject(_instance,
107                              RuntimeNPClass<LibvlcAudioNPObject>::getClass());
108                 OBJECT_TO_NPVARIANT(NPN_RetainObject(audioObj), result);
109                 return INVOKERESULT_NO_ERROR;
110             case ID_root_input:
111                 // create child object in lazyman fashion to avoid
112                 // ownership problem with firefox
113                 if( ! inputObj )
114                     inputObj = NPN_CreateObject(_instance,
115                              RuntimeNPClass<LibvlcInputNPObject>::getClass());
116                 OBJECT_TO_NPVARIANT(NPN_RetainObject(inputObj), result);
117                 return INVOKERESULT_NO_ERROR;
118             case ID_root_playlist:
119                 // create child object in lazyman fashion to avoid
120                 // ownership problem with firefox
121                 if( ! playlistObj )
122                     playlistObj = NPN_CreateObject(_instance,
123                           RuntimeNPClass<LibvlcPlaylistNPObject>::getClass());
124                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistObj), result);
125                 return INVOKERESULT_NO_ERROR;
126             case ID_root_subtitle:
127                 // create child object in lazyman fashion to avoid
128                 // ownership problem with firefox
129                 if( ! subtitleObj )
130                     subtitleObj = NPN_CreateObject(_instance,
131                              RuntimeNPClass<LibvlcSubtitleNPObject>::getClass());
132                 OBJECT_TO_NPVARIANT(NPN_RetainObject(subtitleObj), result);
133                 return INVOKERESULT_NO_ERROR;
134             case ID_root_video:
135                 // create child object in lazyman fashion to avoid
136                 // ownership problem with firefox
137                 if( ! videoObj )
138                     videoObj = NPN_CreateObject(_instance,
139                              RuntimeNPClass<LibvlcVideoNPObject>::getClass());
140                 OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
141                 return INVOKERESULT_NO_ERROR;
142             case ID_root_VersionInfo:
143                 return invokeResultString(libvlc_get_version(),result);
144             default:
145                 ;
146         }
147     }
148     return INVOKERESULT_GENERIC_ERROR;
149 }
150
151 const NPUTF8 * const LibvlcRootNPObject::methodNames[] =
152 {
153     "versionInfo",
154 };
155 COUNTNAMES(LibvlcRootNPObject,methodCount,methodNames);
156
157 enum LibvlcRootNPObjectMethodIds
158 {
159     ID_root_versionInfo,
160 };
161
162 RuntimeNPObject::InvokeResult LibvlcRootNPObject::invoke(int index,
163                   const NPVariant *args, uint32_t argCount, NPVariant &result)
164 {
165     /* is plugin still running */
166     if( isPluginRunning() )
167     {
168         libvlc_exception_t ex;
169         libvlc_exception_init(&ex);
170
171         switch( index )
172         {
173             case ID_root_versionInfo:
174                 if( 0 != argCount )
175                     return INVOKERESULT_NO_SUCH_METHOD;
176                 return invokeResultString(libvlc_get_version(),result);
177             default:
178                 ;
179         }
180     }
181     return INVOKERESULT_GENERIC_ERROR;
182 }
183
184 /*
185 ** implementation of libvlc audio object
186 */
187
188 const NPUTF8 * const LibvlcAudioNPObject::propertyNames[] =
189 {
190     "mute",
191     "volume",
192     "track",
193     "count",
194     "channel",
195 };
196 COUNTNAMES(LibvlcAudioNPObject,propertyCount,propertyNames);
197
198 enum LibvlcAudioNPObjectPropertyIds
199 {
200     ID_audio_mute,
201     ID_audio_volume,
202     ID_audio_track,
203     ID_audio_count,
204     ID_audio_channel,
205 };
206
207 RuntimeNPObject::InvokeResult
208 LibvlcAudioNPObject::getProperty(int index, NPVariant &result)
209 {
210     /* is plugin still running */
211     if( isPluginRunning() )
212     {
213         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
214         libvlc_exception_t ex;
215         libvlc_exception_init(&ex);
216
217         switch( index )
218         {
219             case ID_audio_mute:
220             {
221                 bool muted = libvlc_audio_get_mute(p_plugin->getVLC(), &ex);
222                 RETURN_ON_EXCEPTION(this,ex);
223                 BOOLEAN_TO_NPVARIANT(muted, result);
224                 return INVOKERESULT_NO_ERROR;
225             }
226             case ID_audio_volume:
227             {
228                 int volume = libvlc_audio_get_volume(p_plugin->getVLC(), &ex);
229                 RETURN_ON_EXCEPTION(this,ex);
230                 INT32_TO_NPVARIANT(volume, result);
231                 return INVOKERESULT_NO_ERROR;
232             }
233             case ID_audio_track:
234             {
235                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
236                 RETURN_ON_EXCEPTION(this,ex);
237                 int track = libvlc_audio_get_track(p_md, &ex);
238                 RETURN_ON_EXCEPTION(this,ex);
239                 INT32_TO_NPVARIANT(track, result);
240                 return INVOKERESULT_NO_ERROR;
241             }
242             case ID_audio_count:
243             {
244                 libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
245                 RETURN_ON_EXCEPTION(this,ex);
246                 // get the number of audio track available
247                 int i_track = libvlc_audio_get_track_count(p_md, &ex);
248                 RETURN_ON_EXCEPTION(this,ex);
249                 // return it
250                 INT32_TO_NPVARIANT(i_track, result);
251                 return INVOKERESULT_NO_ERROR;
252             }
253             case ID_audio_channel:
254             {
255                 int channel = libvlc_audio_get_channel(p_plugin->getVLC(), &ex);
256                 RETURN_ON_EXCEPTION(this,ex);
257                 INT32_TO_NPVARIANT(channel, result);
258                 return INVOKERESULT_NO_ERROR;
259             }
260             default:
261                 ;
262         }
263     }
264     return INVOKERESULT_GENERIC_ERROR;
265 }
266
267 RuntimeNPObject::InvokeResult
268 LibvlcAudioNPObject::setProperty(int index, const NPVariant &value)
269 {
270     /* is plugin still running */
271     if( isPluginRunning() )
272     {
273         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
274         libvlc_exception_t ex;
275         libvlc_exception_init(&ex);
276
277         switch( index )
278         {
279             case ID_audio_mute:
280                 if( NPVARIANT_IS_BOOLEAN(value) )
281                 {
282                     libvlc_audio_set_mute(p_plugin->getVLC(),
283                                           NPVARIANT_TO_BOOLEAN(value), &ex);
284                     RETURN_ON_EXCEPTION(this,ex);
285                     return INVOKERESULT_NO_ERROR;
286                 }
287                 return INVOKERESULT_INVALID_VALUE;
288             case ID_audio_volume:
289                 if( isNumberValue(value) )
290                 {
291                     libvlc_audio_set_volume(p_plugin->getVLC(),
292                                             numberValue(value), &ex);
293                     RETURN_ON_EXCEPTION(this,ex);
294                     return INVOKERESULT_NO_ERROR;
295                 }
296                 return INVOKERESULT_INVALID_VALUE;
297             case ID_audio_track:
298                 if( isNumberValue(value) )
299                 {
300                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
301                     RETURN_ON_EXCEPTION(this,ex);
302                     libvlc_audio_set_track(p_md, numberValue(value), &ex);
303                     RETURN_ON_EXCEPTION(this,ex);
304                     return INVOKERESULT_NO_ERROR;
305                 }
306                 return INVOKERESULT_INVALID_VALUE;
307             case ID_audio_channel:
308                 if( isNumberValue(value) )
309                 {
310                     libvlc_audio_set_channel(p_plugin->getVLC(),
311                                              numberValue(value), &ex);
312                     RETURN_ON_EXCEPTION(this,ex);
313                     return INVOKERESULT_NO_ERROR;
314                 }
315                 return INVOKERESULT_INVALID_VALUE;
316             default:
317                 ;
318         }
319     }
320     return INVOKERESULT_GENERIC_ERROR;
321 }
322
323 const NPUTF8 * const LibvlcAudioNPObject::methodNames[] =
324 {
325     "toggleMute",
326     "description",
327 };
328 COUNTNAMES(LibvlcAudioNPObject,methodCount,methodNames);
329
330 enum LibvlcAudioNPObjectMethodIds
331 {
332     ID_audio_togglemute,
333     ID_audio_description,
334 };
335
336 RuntimeNPObject::InvokeResult
337 LibvlcAudioNPObject::invoke(int index, const NPVariant *args,
338                             uint32_t argCount, NPVariant &result)
339 {
340     /* is plugin still running */
341     if( isPluginRunning() )
342     {
343         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
344         libvlc_exception_t ex;
345         libvlc_exception_init(&ex);
346
347         switch( index )
348         {
349             case ID_audio_togglemute:
350                 if( argCount == 0 )
351                 {
352                     libvlc_audio_toggle_mute(p_plugin->getVLC(), &ex);
353                     RETURN_ON_EXCEPTION(this,ex);
354                     VOID_TO_NPVARIANT(result);
355                     return INVOKERESULT_NO_ERROR;
356                 }
357                 return INVOKERESULT_NO_SUCH_METHOD;
358             case ID_audio_description:
359             {
360                 if( argCount == 1)
361                 {
362                     char *psz_name;
363                     int i_trackID, i_limit, i;
364                     libvlc_track_description_t *p_trackDesc;
365
366                     libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
367                     RETURN_ON_EXCEPTION(this,ex);
368
369                     /* get tracks description */
370                     p_trackDesc = libvlc_audio_get_track_description(p_md, &ex);
371                     RETURN_ON_EXCEPTION(this,ex);
372                     if( !p_trackDesc )
373                         return INVOKERESULT_GENERIC_ERROR;
374
375                     /* get the number of track available */
376                     i_limit = libvlc_audio_get_track_count(p_md, &ex);
377                     RETURN_ON_EXCEPTION(this,ex);
378
379                     /* check if a number is given by the user
380                      * and get the track number */
381                     if( isNumberValue(args[0]) )
382                         i_trackID = numberValue(args[0]);
383                     else
384                         return INVOKERESULT_INVALID_VALUE;
385
386                     /* if bad number is given return invalid value */
387                     if ( ( i_trackID > ( i_limit - 1 ) ) || ( i_trackID < 0 ) )
388                         return INVOKERESULT_INVALID_VALUE;
389
390                     /* get the good trackDesc */
391                     for( i = 0 ; i < i_trackID ; i++ )
392                     {
393                         p_trackDesc = p_trackDesc->p_next;
394                     }
395                     psz_name = p_trackDesc->psz_name;
396
397                     /* display the name of the track chosen */
398                     return invokeResultString( psz_name, result );
399                 }
400                 return INVOKERESULT_NO_SUCH_METHOD;
401             }
402             default:
403                 ;
404         }
405     }
406     return INVOKERESULT_GENERIC_ERROR;
407 }
408
409 /*
410 ** implementation of libvlc input object
411 */
412
413 const NPUTF8 * const LibvlcInputNPObject::propertyNames[] =
414 {
415     "length",
416     "position",
417     "time",
418     "state",
419     "rate",
420     "fps",
421     "hasVout",
422 };
423 COUNTNAMES(LibvlcInputNPObject,propertyCount,propertyNames);
424
425 enum LibvlcInputNPObjectPropertyIds
426 {
427     ID_input_length,
428     ID_input_position,
429     ID_input_time,
430     ID_input_state,
431     ID_input_rate,
432     ID_input_fps,
433     ID_input_hasvout,
434 };
435
436 RuntimeNPObject::InvokeResult
437 LibvlcInputNPObject::getProperty(int index, NPVariant &result)
438 {
439     /* is plugin still running */
440     if( isPluginRunning() )
441     {
442         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
443         libvlc_exception_t ex;
444         libvlc_exception_init(&ex);
445
446         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
447         if( libvlc_exception_raised(&ex) )
448         {
449             if( index != ID_input_state )
450             {
451                 NPN_SetException(this, libvlc_exception_get_message(&ex));
452                 libvlc_exception_clear(&ex);
453                 return INVOKERESULT_GENERIC_ERROR;
454             }
455             else
456             {
457                 /* for input state, return CLOSED rather than an exception */
458                 INT32_TO_NPVARIANT(0, result);
459                 libvlc_exception_clear(&ex);
460                 return INVOKERESULT_NO_ERROR;
461             }
462         }
463
464         switch( index )
465         {
466             case ID_input_length:
467             {
468                 double val = (double)libvlc_media_player_get_length(p_md, &ex);
469                 RETURN_ON_EXCEPTION(this,ex);
470                 DOUBLE_TO_NPVARIANT(val, result);
471                 return INVOKERESULT_NO_ERROR;
472             }
473             case ID_input_position:
474             {
475                 double val = libvlc_media_player_get_position(p_md, &ex);
476                 RETURN_ON_EXCEPTION(this,ex);
477                 DOUBLE_TO_NPVARIANT(val, result);
478                 return INVOKERESULT_NO_ERROR;
479             }
480             case ID_input_time:
481             {
482                 double val = (double)libvlc_media_player_get_time(p_md, &ex);
483                 RETURN_ON_EXCEPTION(this,ex);
484                 DOUBLE_TO_NPVARIANT(val, result);
485                 return INVOKERESULT_NO_ERROR;
486             }
487             case ID_input_state:
488             {
489                 int val = libvlc_media_player_get_state(p_md, &ex);
490                 RETURN_ON_EXCEPTION(this,ex);
491                 INT32_TO_NPVARIANT(val, result);
492                 return INVOKERESULT_NO_ERROR;
493             }
494             case ID_input_rate:
495             {
496                 float val = libvlc_media_player_get_rate(p_md, &ex);
497                 RETURN_ON_EXCEPTION(this,ex);
498                 DOUBLE_TO_NPVARIANT(val, result);
499                 return INVOKERESULT_NO_ERROR;
500             }
501             case ID_input_fps:
502             {
503                 double val = libvlc_media_player_get_fps(p_md, &ex);
504                 RETURN_ON_EXCEPTION(this,ex);
505                 DOUBLE_TO_NPVARIANT(val, result);
506                 return INVOKERESULT_NO_ERROR;
507             }
508             case ID_input_hasvout:
509             {
510                 bool val = p_plugin->player_has_vout(&ex);
511                 RETURN_ON_EXCEPTION(this,ex);
512                 BOOLEAN_TO_NPVARIANT(val, result);
513                 return INVOKERESULT_NO_ERROR;
514             }
515             default:
516                 ;
517         }
518     }
519     return INVOKERESULT_GENERIC_ERROR;
520 }
521
522 RuntimeNPObject::InvokeResult
523 LibvlcInputNPObject::setProperty(int index, const NPVariant &value)
524 {
525     /* is plugin still running */
526     if( isPluginRunning() )
527     {
528         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
529         libvlc_exception_t ex;
530         libvlc_exception_init(&ex);
531
532         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
533         RETURN_ON_EXCEPTION(this,ex);
534
535         switch( index )
536         {
537             case ID_input_position:
538             {
539                 if( ! NPVARIANT_IS_DOUBLE(value) )
540                 {
541                     return INVOKERESULT_INVALID_VALUE;
542                 }
543
544                 float val = (float)NPVARIANT_TO_DOUBLE(value);
545                 libvlc_media_player_set_position(p_md, val, &ex);
546                 RETURN_ON_EXCEPTION(this,ex);
547                 return INVOKERESULT_NO_ERROR;
548             }
549             case ID_input_time:
550             {
551                 int64_t val;
552                 if( NPVARIANT_IS_INT32(value) )
553                     val = (int64_t)NPVARIANT_TO_INT32(value);
554                 else if( NPVARIANT_IS_DOUBLE(value) )
555                     val = (int64_t)NPVARIANT_TO_DOUBLE(value);
556                 else
557                 {
558                     return INVOKERESULT_INVALID_VALUE;
559                 }
560
561                 libvlc_media_player_set_time(p_md, val, &ex);
562                 RETURN_ON_EXCEPTION(this,ex);
563                 return INVOKERESULT_NO_ERROR;
564             }
565             case ID_input_rate:
566             {
567                 float val;
568                 if( NPVARIANT_IS_INT32(value) )
569                     val = (float)NPVARIANT_TO_INT32(value);
570                 else if( NPVARIANT_IS_DOUBLE(value) )
571                     val = (float)NPVARIANT_TO_DOUBLE(value);
572                 else
573                 {
574                     return INVOKERESULT_INVALID_VALUE;
575                 }
576
577                 libvlc_media_player_set_rate(p_md, val, &ex);
578                 RETURN_ON_EXCEPTION(this,ex);
579                 return INVOKERESULT_NO_ERROR;
580             }
581             default:
582                 ;
583         }
584     }
585     return INVOKERESULT_GENERIC_ERROR;
586 }
587
588 const NPUTF8 * const LibvlcInputNPObject::methodNames[] =
589 {
590     /* no methods */
591 };
592
593 COUNTNAMES(LibvlcInputNPObject,methodCount,methodNames);
594
595 /*
596 ** implementation of libvlc playlist items object
597 */
598
599 const NPUTF8 * const LibvlcPlaylistItemsNPObject::propertyNames[] =
600 {
601     "count",
602 };
603 COUNTNAMES(LibvlcPlaylistItemsNPObject,propertyCount,propertyNames);
604
605 enum LibvlcPlaylistItemsNPObjectPropertyIds
606 {
607     ID_playlistitems_count,
608 };
609
610 RuntimeNPObject::InvokeResult
611 LibvlcPlaylistItemsNPObject::getProperty(int index, NPVariant &result)
612 {
613     /* is plugin still running */
614     if( isPluginRunning() )
615     {
616         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
617         libvlc_exception_t ex;
618         libvlc_exception_init(&ex);
619
620         switch( index )
621         {
622             case ID_playlistitems_count:
623             {
624                 int val = p_plugin->playlist_count(&ex);
625                 RETURN_ON_EXCEPTION(this,ex);
626                 INT32_TO_NPVARIANT(val, result);
627                 return INVOKERESULT_NO_ERROR;
628             }
629             default:
630                 ;
631         }
632     }
633     return INVOKERESULT_GENERIC_ERROR;
634 }
635
636 const NPUTF8 * const LibvlcPlaylistItemsNPObject::methodNames[] =
637 {
638     "clear",
639     "remove",
640 };
641 COUNTNAMES(LibvlcPlaylistItemsNPObject,methodCount,methodNames);
642
643 enum LibvlcPlaylistItemsNPObjectMethodIds
644 {
645     ID_playlistitems_clear,
646     ID_playlistitems_remove,
647 };
648
649 RuntimeNPObject::InvokeResult
650 LibvlcPlaylistItemsNPObject::invoke(int index, const NPVariant *args,
651                                     uint32_t argCount, NPVariant &result)
652 {
653     /* is plugin still running */
654     if( isPluginRunning() )
655     {
656         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
657         libvlc_exception_t ex;
658         libvlc_exception_init(&ex);
659
660         switch( index )
661         {
662             case ID_playlistitems_clear:
663                 if( argCount == 0 )
664                 {
665                     p_plugin->playlist_clear(&ex);
666                     RETURN_ON_EXCEPTION(this,ex);
667                     VOID_TO_NPVARIANT(result);
668                     return INVOKERESULT_NO_ERROR;
669                 }
670                 return INVOKERESULT_NO_SUCH_METHOD;
671             case ID_playlistitems_remove:
672                 if( (argCount == 1) && isNumberValue(args[0]) )
673                 {
674                     p_plugin->playlist_delete_item(numberValue(args[0]),&ex);
675                     RETURN_ON_EXCEPTION(this,ex);
676                     VOID_TO_NPVARIANT(result);
677                     return INVOKERESULT_NO_ERROR;
678                 }
679                 return INVOKERESULT_NO_SUCH_METHOD;
680             default:
681                 ;
682         }
683     }
684     return INVOKERESULT_GENERIC_ERROR;
685 }
686
687 /*
688 ** implementation of libvlc playlist object
689 */
690
691 LibvlcPlaylistNPObject::~LibvlcPlaylistNPObject()
692 {
693     // Why the isValid()?
694     if( isValid() && playlistItemsObj )
695         NPN_ReleaseObject(playlistItemsObj);
696 };
697
698 const NPUTF8 * const LibvlcPlaylistNPObject::propertyNames[] =
699 {
700     "itemCount", /* deprecated */
701     "isPlaying",
702     "items",
703 };
704 COUNTNAMES(LibvlcPlaylistNPObject,propertyCount,propertyNames);
705
706 enum LibvlcPlaylistNPObjectPropertyIds
707 {
708     ID_playlist_itemcount,
709     ID_playlist_isplaying,
710     ID_playlist_items,
711 };
712
713 RuntimeNPObject::InvokeResult
714 LibvlcPlaylistNPObject::getProperty(int index, NPVariant &result)
715 {
716     /* is plugin still running */
717     if( isPluginRunning() )
718     {
719         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
720         libvlc_exception_t ex;
721         libvlc_exception_init(&ex);
722
723         switch( index )
724         {
725             case ID_playlist_itemcount: /* deprecated */
726             {
727                 int val = p_plugin->playlist_count(&ex);
728                 RETURN_ON_EXCEPTION(this,ex);
729                 INT32_TO_NPVARIANT(val, result);
730                 return INVOKERESULT_NO_ERROR;
731             }
732             case ID_playlist_isplaying:
733             {
734                 int val = p_plugin->playlist_isplaying(&ex);
735                 RETURN_ON_EXCEPTION(this,ex);
736                 BOOLEAN_TO_NPVARIANT(val, result);
737                 return INVOKERESULT_NO_ERROR;
738             }
739             case ID_playlist_items:
740             {
741                 // create child object in lazyman fashion to avoid
742                 // ownership problem with firefox
743                 if( ! playlistItemsObj )
744                     playlistItemsObj =
745                         NPN_CreateObject(_instance, RuntimeNPClass<
746                         LibvlcPlaylistItemsNPObject>::getClass());
747                 OBJECT_TO_NPVARIANT(NPN_RetainObject(playlistItemsObj), result);
748                 return INVOKERESULT_NO_ERROR;
749             }
750             default:
751                 ;
752         }
753     }
754     return INVOKERESULT_GENERIC_ERROR;
755 }
756
757 const NPUTF8 * const LibvlcPlaylistNPObject::methodNames[] =
758 {
759     "add",
760     "play",
761     "playItem",
762     "togglePause",
763     "stop",
764     "next",
765     "prev",
766     "clear", /* deprecated */
767     "removeItem", /* deprecated */
768 };
769 COUNTNAMES(LibvlcPlaylistNPObject,methodCount,methodNames);
770
771 enum LibvlcPlaylistNPObjectMethodIds
772 {
773     ID_playlist_add,
774     ID_playlist_play,
775     ID_playlist_playItem,
776     ID_playlist_togglepause,
777     ID_playlist_stop,
778     ID_playlist_next,
779     ID_playlist_prev,
780     ID_playlist_clear,
781     ID_playlist_removeitem
782 };
783
784 RuntimeNPObject::InvokeResult
785 LibvlcPlaylistNPObject::invoke(int index, const NPVariant *args,
786                                uint32_t argCount, NPVariant &result)
787 {
788     /* is plugin still running */
789     if( isPluginRunning() )
790     {
791         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
792         libvlc_exception_t ex;
793         libvlc_exception_init(&ex);
794
795         switch( index )
796         {
797             // XXX FIXME this needs squashing into something much smaller
798             case ID_playlist_add:
799             {
800                 if( (argCount < 1) || (argCount > 3) )
801                     return INVOKERESULT_NO_SUCH_METHOD;
802
803                 char *url = NULL;
804
805                 // grab URL
806                 if( NPVARIANT_IS_STRING(args[0]) )
807                 {
808                     char *s = stringValue(NPVARIANT_TO_STRING(args[0]));
809                     if( s )
810                     {
811                         url = p_plugin->getAbsoluteURL(s);
812                         if( url )
813                             free(s);
814                         else
815                             // problem with combining url, use argument
816                             url = s;
817                     }
818                     else
819                         return INVOKERESULT_OUT_OF_MEMORY;
820                 }
821                 else
822                     return INVOKERESULT_NO_SUCH_METHOD;
823
824                 char *name = NULL;
825
826                 // grab name if available
827                 if( argCount > 1 )
828                 {
829                     if( NPVARIANT_IS_NULL(args[1]) )
830                     {
831                         // do nothing
832                     }
833                     else if( NPVARIANT_IS_STRING(args[1]) )
834                     {
835                         name = stringValue(NPVARIANT_TO_STRING(args[1]));
836                     }
837                     else
838                     {
839                         free(url);
840                         return INVOKERESULT_INVALID_VALUE;
841                     }
842                 }
843
844                 int i_options = 0;
845                 char** ppsz_options = NULL;
846
847                 // grab options if available
848                 if( argCount > 2 )
849                 {
850                     if( NPVARIANT_IS_NULL(args[2]) )
851                     {
852                         // do nothing
853                     }
854                     else if( NPVARIANT_IS_STRING(args[2]) )
855                     {
856                         parseOptions(NPVARIANT_TO_STRING(args[2]),
857                                      &i_options, &ppsz_options);
858
859                     }
860                     else if( NPVARIANT_IS_OBJECT(args[2]) )
861                     {
862                         parseOptions(NPVARIANT_TO_OBJECT(args[2]),
863                                      &i_options, &ppsz_options);
864                     }
865                     else
866                     {
867                         free(url);
868                         free(name);
869                         return INVOKERESULT_INVALID_VALUE;
870                     }
871                 }
872
873                 int item = p_plugin->playlist_add_extended_untrusted(url, name,
874                       i_options, const_cast<const char **>(ppsz_options), &ex);
875                 free(url);
876                 free(name);
877                 for( int i=0; i< i_options; ++i )
878                 {
879                     free(ppsz_options[i]);
880                 }
881                 free(ppsz_options);
882
883                 RETURN_ON_EXCEPTION(this,ex);
884                 INT32_TO_NPVARIANT(item, result);
885                 return INVOKERESULT_NO_ERROR;
886             }
887             case ID_playlist_play:
888                 if( argCount == 0 )
889                 {
890                     p_plugin->playlist_play(&ex);
891                     RETURN_ON_EXCEPTION(this,ex);
892                     VOID_TO_NPVARIANT(result);
893                     return INVOKERESULT_NO_ERROR;
894                 }
895                 return INVOKERESULT_NO_SUCH_METHOD;
896             case ID_playlist_playItem:
897                 if( (argCount == 1) && isNumberValue(args[0]) )
898                 {
899                     p_plugin->playlist_play_item(numberValue(args[0]),&ex);
900                     RETURN_ON_EXCEPTION(this,ex);
901                     VOID_TO_NPVARIANT(result);
902                     return INVOKERESULT_NO_ERROR;
903                 }
904                 return INVOKERESULT_NO_SUCH_METHOD;
905             case ID_playlist_togglepause:
906                 if( argCount == 0 )
907                 {
908                     p_plugin->playlist_pause(&ex);
909                     RETURN_ON_EXCEPTION(this,ex);
910                     VOID_TO_NPVARIANT(result);
911                     return INVOKERESULT_NO_ERROR;
912                 }
913                 return INVOKERESULT_NO_SUCH_METHOD;
914             case ID_playlist_stop:
915                 if( argCount == 0 )
916                 {
917                     p_plugin->playlist_stop(&ex);
918                     RETURN_ON_EXCEPTION(this,ex);
919                     VOID_TO_NPVARIANT(result);
920                     return INVOKERESULT_NO_ERROR;
921                 }
922                 return INVOKERESULT_NO_SUCH_METHOD;
923             case ID_playlist_next:
924                 if( argCount == 0 )
925                 {
926                     p_plugin->playlist_next(&ex);
927                     RETURN_ON_EXCEPTION(this,ex);
928                     VOID_TO_NPVARIANT(result);
929                     return INVOKERESULT_NO_ERROR;
930                 }
931                 return INVOKERESULT_NO_SUCH_METHOD;
932             case ID_playlist_prev:
933                 if( argCount == 0 )
934                 {
935                     p_plugin->playlist_prev(&ex);
936                     RETURN_ON_EXCEPTION(this,ex);
937                     VOID_TO_NPVARIANT(result);
938                     return INVOKERESULT_NO_ERROR;
939                 }
940                 return INVOKERESULT_NO_SUCH_METHOD;
941             case ID_playlist_clear: /* deprecated */
942                 if( argCount == 0 )
943                 {
944                     p_plugin->playlist_clear(&ex);
945                     RETURN_ON_EXCEPTION(this,ex);
946                     VOID_TO_NPVARIANT(result);
947                     return INVOKERESULT_NO_ERROR;
948                 }
949                 return INVOKERESULT_NO_SUCH_METHOD;
950             case ID_playlist_removeitem: /* deprecated */
951                 if( (argCount == 1) && isNumberValue(args[0]) )
952                 {
953                     p_plugin->playlist_delete_item(numberValue(args[0]), &ex);
954                     RETURN_ON_EXCEPTION(this,ex);
955                     VOID_TO_NPVARIANT(result);
956                     return INVOKERESULT_NO_ERROR;
957                 }
958                 return INVOKERESULT_NO_SUCH_METHOD;
959             default:
960                 ;
961         }
962     }
963     return INVOKERESULT_GENERIC_ERROR;
964 }
965
966 // XXX FIXME The new playlist_add creates a media instance and feeds it
967 // XXX FIXME these options one at a time, so this hunk of code does lots
968 // XXX FIXME of unnecessairy work. Break out something that can do one
969 // XXX FIXME option at a time and doesn't need to realloc().
970 // XXX FIXME Same for the other version of parseOptions.
971
972 void LibvlcPlaylistNPObject::parseOptions(const NPString &nps,
973                                          int *i_options, char*** ppsz_options)
974 {
975     if( nps.utf8length )
976     {
977         char *s = stringValue(nps);
978         char *val = s;
979         if( val )
980         {
981             long capacity = 16;
982             char **options = (char **)malloc(capacity*sizeof(char *));
983             if( options )
984             {
985                 int nOptions = 0;
986
987                 char *end = val + nps.utf8length;
988                 while( val < end )
989                 {
990                     // skip leading blanks
991                     while( (val < end)
992                         && ((*val == ' ' ) || (*val == '\t')) )
993                         ++val;
994
995                     char *start = val;
996                     // skip till we get a blank character
997                     while( (val < end)
998                         && (*val != ' ' )
999                         && (*val != '\t') )
1000                     {
1001                         char c = *(val++);
1002                         if( ('\'' == c) || ('"' == c) )
1003                         {
1004                             // skip till end of string
1005                             while( (val < end) && (*(val++) != c ) );
1006                         }
1007                     }
1008
1009                     if( val > start )
1010                     {
1011                         if( nOptions == capacity )
1012                         {
1013                             capacity += 16;
1014                             char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1015                             if( ! moreOptions )
1016                             {
1017                                 /* failed to allocate more memory */
1018                                 free(s);
1019                                 /* return what we got so far */
1020                                 *i_options = nOptions;
1021                                 *ppsz_options = options;
1022                                 return;
1023                             }
1024                             options = moreOptions;
1025                         }
1026                         *(val++) = '\0';
1027                         options[nOptions++] = strdup(start);
1028                     }
1029                     else
1030                         // must be end of string
1031                         break;
1032                 }
1033                 *i_options = nOptions;
1034                 *ppsz_options = options;
1035             }
1036             free(s);
1037         }
1038     }
1039 }
1040
1041 // XXX FIXME See comment at the other parseOptions variant.
1042 void LibvlcPlaylistNPObject::parseOptions(NPObject *obj, int *i_options,
1043                                           char*** ppsz_options)
1044 {
1045     /* WARNING: Safari does not implement NPN_HasProperty/NPN_HasMethod */
1046
1047     NPVariant value;
1048
1049     /* we are expecting to have a Javascript Array object */
1050     NPIdentifier propId = NPN_GetStringIdentifier("length");
1051     if( NPN_GetProperty(_instance, obj, propId, &value) )
1052     {
1053         int count = numberValue(value);
1054         NPN_ReleaseVariantValue(&value);
1055
1056         if( count )
1057         {
1058             long capacity = 16;
1059             char **options = (char **)malloc(capacity*sizeof(char *));
1060             if( options )
1061             {
1062                 int nOptions = 0;
1063
1064                 while( nOptions < count )
1065                 {
1066                     propId = NPN_GetIntIdentifier(nOptions);
1067                     if( ! NPN_GetProperty(_instance, obj, propId, &value) )
1068                         /* return what we got so far */
1069                         break;
1070
1071                     if( ! NPVARIANT_IS_STRING(value) )
1072                     {
1073                         /* return what we got so far */
1074                         NPN_ReleaseVariantValue(&value);
1075                         break;
1076                     }
1077
1078                     if( nOptions == capacity )
1079                     {
1080                         capacity += 16;
1081                         char **moreOptions = (char **)realloc(options, capacity*sizeof(char*));
1082                         if( ! moreOptions )
1083                         {
1084                             /* failed to allocate more memory */
1085                             NPN_ReleaseVariantValue(&value);
1086                             /* return what we got so far */
1087                             *i_options = nOptions;
1088                             *ppsz_options = options;
1089                             break;
1090                         }
1091                         options = moreOptions;
1092                     }
1093
1094                     options[nOptions++] = stringValue(value);
1095                 }
1096                 *i_options = nOptions;
1097                 *ppsz_options = options;
1098             }
1099         }
1100     }
1101 }
1102
1103 /*
1104 ** implementation of libvlc subtitle object
1105 */
1106
1107 const NPUTF8 * const LibvlcSubtitleNPObject::propertyNames[] =
1108 {
1109     "track",
1110     "count",
1111 };
1112
1113 enum LibvlcSubtitleNPObjectPropertyIds
1114 {
1115     ID_subtitle_track,
1116     ID_subtitle_count,
1117 };
1118 COUNTNAMES(LibvlcSubtitleNPObject,propertyCount,propertyNames);
1119
1120 RuntimeNPObject::InvokeResult
1121 LibvlcSubtitleNPObject::getProperty(int index, NPVariant &result)
1122 {
1123     /* is plugin still running */
1124     if( isPluginRunning() )
1125     {
1126         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1127         libvlc_exception_t ex;
1128         libvlc_exception_init(&ex);
1129
1130         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1131         RETURN_ON_EXCEPTION(this,ex);
1132
1133         switch( index )
1134         {
1135             case ID_subtitle_track:
1136             {
1137                 /* get the current subtitle ID */
1138                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1139                 RETURN_ON_EXCEPTION(this,ex);
1140                 /* return it */
1141                 INT32_TO_NPVARIANT(i_spu, result);
1142                 return INVOKERESULT_NO_ERROR;
1143             }
1144             case ID_subtitle_count:
1145             {
1146                 /* get the number of subtitles available */
1147                 int i_spu = libvlc_video_get_spu_count(p_md, &ex);
1148                 RETURN_ON_EXCEPTION(this,ex);
1149                 /* return it */
1150                 INT32_TO_NPVARIANT(i_spu, result);
1151                 return INVOKERESULT_NO_ERROR;
1152             }
1153         }
1154     }
1155     return INVOKERESULT_GENERIC_ERROR;
1156 }
1157
1158 RuntimeNPObject::InvokeResult
1159 LibvlcSubtitleNPObject::setProperty(int index, const NPVariant &value)
1160 {
1161     /* is plugin still running */
1162     if( isPluginRunning() )
1163     {
1164         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1165         libvlc_exception_t ex;
1166         libvlc_exception_init(&ex);
1167
1168         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1169         RETURN_ON_EXCEPTION(this,ex);
1170
1171         switch( index )
1172         {
1173             case ID_subtitle_track:
1174             {
1175                 if( isNumberValue(value) )
1176                 {
1177                     /* set the new subtitle track to show */
1178                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1179                     RETURN_ON_EXCEPTION(this,ex);
1180
1181                     return INVOKERESULT_NO_ERROR;
1182                 }
1183                 return INVOKERESULT_INVALID_VALUE;
1184             }
1185         }
1186     }
1187     return INVOKERESULT_GENERIC_ERROR;
1188 }
1189
1190 const NPUTF8 * const LibvlcSubtitleNPObject::methodNames[] =
1191 {
1192     "description"
1193 };
1194 COUNTNAMES(LibvlcSubtitleNPObject,methodCount,methodNames);
1195
1196 enum LibvlcSubtitleNPObjectMethodIds
1197 {
1198     ID_subtitle_description
1199 };
1200
1201 RuntimeNPObject::InvokeResult
1202 LibvlcSubtitleNPObject::invoke(int index, const NPVariant *args,
1203                             uint32_t argCount, NPVariant &result)
1204 {
1205     /* is plugin still running */
1206     if( isPluginRunning() )
1207     {
1208         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1209         libvlc_exception_t ex;
1210         libvlc_exception_init(&ex);
1211
1212         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1213         RETURN_ON_EXCEPTION(this,ex);
1214
1215         switch( index )
1216         {
1217             case ID_subtitle_description:
1218             {
1219                 if( argCount == 1)
1220                 {
1221                     char *psz_name;
1222                     int i_spuID, i_limit, i;
1223                     libvlc_track_description_t *p_spuDesc;
1224
1225                     /* get subtitles description */
1226                     p_spuDesc = libvlc_video_get_spu_description(p_md, &ex);
1227                     RETURN_ON_EXCEPTION(this,ex);
1228                     if( !p_spuDesc )
1229                         return INVOKERESULT_GENERIC_ERROR;
1230
1231                     /* get the number of subtitle available */
1232                     i_limit = libvlc_video_get_spu_count(p_md, &ex);
1233                     RETURN_ON_EXCEPTION(this,ex);
1234
1235                     /* check if a number is given by the user
1236                      * and get the subtitle number */
1237                     if( isNumberValue(args[0]) )
1238                         i_spuID = numberValue(args[0]);
1239                     else
1240                         return INVOKERESULT_INVALID_VALUE;
1241
1242                     /* if bad number is given return invalid value */
1243                     if ( ( i_spuID > ( i_limit -1 ) ) || ( i_spuID < 0 ) )
1244                         return INVOKERESULT_INVALID_VALUE;
1245
1246                     /* get the good spuDesc */
1247                     for( i = 0 ; i < i_spuID ; i++ )
1248                     {
1249                         p_spuDesc = p_spuDesc->p_next;
1250                     }
1251                     psz_name = p_spuDesc->psz_name;
1252
1253                     /* return the name of the track chosen */
1254                     return invokeResultString(psz_name, result);
1255                 }
1256                 return INVOKERESULT_NO_SUCH_METHOD;
1257             }
1258             default:
1259                 return INVOKERESULT_NO_SUCH_METHOD;
1260         }
1261     }
1262     return INVOKERESULT_GENERIC_ERROR;
1263 }
1264
1265 /*
1266 ** implementation of libvlc video object
1267 */
1268
1269 const NPUTF8 * const LibvlcVideoNPObject::propertyNames[] =
1270 {
1271     "fullscreen",
1272     "height",
1273     "width",
1274     "aspectRatio",
1275     "subtitle",
1276     "crop",
1277     "teletext"
1278 };
1279
1280 enum LibvlcVideoNPObjectPropertyIds
1281 {
1282     ID_video_fullscreen,
1283     ID_video_height,
1284     ID_video_width,
1285     ID_video_aspectratio,
1286     ID_video_subtitle,
1287     ID_video_crop,
1288     ID_video_teletext
1289 };
1290 COUNTNAMES(LibvlcVideoNPObject,propertyCount,propertyNames);
1291
1292 RuntimeNPObject::InvokeResult
1293 LibvlcVideoNPObject::getProperty(int index, NPVariant &result)
1294 {
1295     /* is plugin still running */
1296     if( isPluginRunning() )
1297     {
1298         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1299         libvlc_exception_t ex;
1300         libvlc_exception_init(&ex);
1301
1302         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1303         RETURN_ON_EXCEPTION(this,ex);
1304
1305         switch( index )
1306         {
1307             case ID_video_fullscreen:
1308             {
1309                 int val = p_plugin->get_fullscreen(&ex);
1310                 RETURN_ON_EXCEPTION(this,ex);
1311                 BOOLEAN_TO_NPVARIANT(val, result);
1312                 return INVOKERESULT_NO_ERROR;
1313             }
1314             case ID_video_height:
1315             {
1316                 int val = libvlc_video_get_height(p_md, &ex);
1317                 RETURN_ON_EXCEPTION(this,ex);
1318                 INT32_TO_NPVARIANT(val, result);
1319                 return INVOKERESULT_NO_ERROR;
1320             }
1321             case ID_video_width:
1322             {
1323                 int val = libvlc_video_get_width(p_md, &ex);
1324                 RETURN_ON_EXCEPTION(this,ex);
1325                 INT32_TO_NPVARIANT(val, result);
1326                 return INVOKERESULT_NO_ERROR;
1327             }
1328             case ID_video_aspectratio:
1329             {
1330                 NPUTF8 *psz_aspect = libvlc_video_get_aspect_ratio(p_md, &ex);
1331                 RETURN_ON_EXCEPTION(this,ex);
1332                 if( !psz_aspect )
1333                     return INVOKERESULT_GENERIC_ERROR;
1334
1335                 STRINGZ_TO_NPVARIANT(psz_aspect, result);
1336                 return INVOKERESULT_NO_ERROR;
1337             }
1338             case ID_video_subtitle:
1339             {
1340                 int i_spu = libvlc_video_get_spu(p_md, &ex);
1341                 RETURN_ON_EXCEPTION(this,ex);
1342                 INT32_TO_NPVARIANT(i_spu, result);
1343                 return INVOKERESULT_NO_ERROR;
1344             }
1345             case ID_video_crop:
1346             {
1347                 NPUTF8 *psz_geometry = libvlc_video_get_crop_geometry(p_md, &ex);
1348                 RETURN_ON_EXCEPTION(this,ex);
1349                 if( !psz_geometry )
1350                     return INVOKERESULT_GENERIC_ERROR;
1351
1352                 STRINGZ_TO_NPVARIANT(psz_geometry, result);
1353                 return INVOKERESULT_NO_ERROR;
1354             }
1355             case ID_video_teletext:
1356             {
1357                 int i_page = libvlc_video_get_teletext(p_md, &ex);
1358                 RETURN_ON_EXCEPTION(this,ex);
1359                 INT32_TO_NPVARIANT(i_page, result);
1360                 return INVOKERESULT_NO_ERROR;
1361             }
1362         }
1363     }
1364     return INVOKERESULT_GENERIC_ERROR;
1365 }
1366
1367 RuntimeNPObject::InvokeResult
1368 LibvlcVideoNPObject::setProperty(int index, const NPVariant &value)
1369 {
1370     /* is plugin still running */
1371     if( isPluginRunning() )
1372     {
1373         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1374         libvlc_exception_t ex;
1375         libvlc_exception_init(&ex);
1376
1377         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1378         RETURN_ON_EXCEPTION(this,ex);
1379
1380         switch( index )
1381         {
1382             case ID_video_fullscreen:
1383             {
1384                 if( ! NPVARIANT_IS_BOOLEAN(value) )
1385                 {
1386                     return INVOKERESULT_INVALID_VALUE;
1387                 }
1388
1389                 int val = NPVARIANT_TO_BOOLEAN(value);
1390                 p_plugin->set_fullscreen(val, &ex);
1391                 RETURN_ON_EXCEPTION(this,ex);
1392                 return INVOKERESULT_NO_ERROR;
1393             }
1394             case ID_video_aspectratio:
1395             {
1396                 char *psz_aspect = NULL;
1397
1398                 if( ! NPVARIANT_IS_STRING(value) )
1399                 {
1400                     return INVOKERESULT_INVALID_VALUE;
1401                 }
1402
1403                 psz_aspect = stringValue(NPVARIANT_TO_STRING(value));
1404                 if( !psz_aspect )
1405                 {
1406                     return INVOKERESULT_GENERIC_ERROR;
1407                 }
1408
1409                 libvlc_video_set_aspect_ratio(p_md, psz_aspect, &ex);
1410                 free(psz_aspect);
1411                 RETURN_ON_EXCEPTION(this,ex);
1412
1413                 return INVOKERESULT_NO_ERROR;
1414             }
1415             case ID_video_subtitle:
1416             {
1417                 if( isNumberValue(value) )
1418                 {
1419                     libvlc_video_set_spu(p_md, numberValue(value), &ex);
1420                     RETURN_ON_EXCEPTION(this,ex);
1421
1422                     return INVOKERESULT_NO_ERROR;
1423                 }
1424                 return INVOKERESULT_INVALID_VALUE;
1425             }
1426             case ID_video_crop:
1427             {
1428                 char *psz_geometry = NULL;
1429
1430                 if( ! NPVARIANT_IS_STRING(value) )
1431                 {
1432                     return INVOKERESULT_INVALID_VALUE;
1433                 }
1434
1435                 psz_geometry = stringValue(NPVARIANT_TO_STRING(value));
1436                 if( !psz_geometry )
1437                 {
1438                     return INVOKERESULT_GENERIC_ERROR;
1439                 }
1440
1441                 libvlc_video_set_crop_geometry(p_md, psz_geometry, &ex);
1442                 free(psz_geometry);
1443                 RETURN_ON_EXCEPTION(this,ex);
1444
1445                 return INVOKERESULT_NO_ERROR;
1446             }
1447             case ID_video_teletext:
1448             {
1449                 if( isNumberValue(value) )
1450                 {
1451                     libvlc_video_set_teletext(p_md, numberValue(value), &ex);
1452                     RETURN_ON_EXCEPTION(this,ex);
1453
1454                     return INVOKERESULT_NO_ERROR;
1455                 }
1456                 return INVOKERESULT_INVALID_VALUE;
1457             }
1458         }
1459     }
1460     return INVOKERESULT_GENERIC_ERROR;
1461 }
1462
1463 const NPUTF8 * const LibvlcVideoNPObject::methodNames[] =
1464 {
1465     "toggleFullscreen",
1466     "toggleTeletext"
1467 };
1468 COUNTNAMES(LibvlcVideoNPObject,methodCount,methodNames);
1469
1470 enum LibvlcVideoNPObjectMethodIds
1471 {
1472     ID_video_togglefullscreen,
1473     ID_video_toggleteletext
1474 };
1475
1476 RuntimeNPObject::InvokeResult
1477 LibvlcVideoNPObject::invoke(int index, const NPVariant *args,
1478                             uint32_t argCount, NPVariant &result)
1479 {
1480     /* is plugin still running */
1481     if( isPluginRunning() )
1482     {
1483         VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
1484         libvlc_exception_t ex;
1485         libvlc_exception_init(&ex);
1486
1487         libvlc_media_player_t *p_md = p_plugin->getMD(&ex);
1488         RETURN_ON_EXCEPTION(this,ex);
1489
1490         switch( index )
1491         {
1492             case ID_video_togglefullscreen:
1493                 if( argCount == 0 )
1494                 {
1495                     p_plugin->toggle_fullscreen(&ex);
1496                     RETURN_ON_EXCEPTION(this,ex);
1497                     VOID_TO_NPVARIANT(result);
1498                     return INVOKERESULT_NO_ERROR;
1499                 }
1500                 return INVOKERESULT_NO_SUCH_METHOD;
1501             case ID_video_toggleteletext:
1502                 if( argCount == 0 )
1503                 {
1504                     libvlc_toggle_teletext(p_md, &ex);
1505                     RETURN_ON_EXCEPTION(this,ex);
1506                     VOID_TO_NPVARIANT(result);
1507                     return INVOKERESULT_NO_ERROR;
1508                 }
1509                 return INVOKERESULT_NO_SUCH_METHOD;
1510             default:
1511                 return INVOKERESULT_NO_SUCH_METHOD;
1512         }
1513     }
1514     return INVOKERESULT_GENERIC_ERROR;
1515 }