Commit 28029c51 authored by Yannick Brehon's avatar Yannick Brehon Committed by JP Dinger

Mozilla plugin event listeners.

This is the patch as supplied, which needs work and as of yet doesn't
compile on non-unix. Fixes pending. -- jpd
parent e783869a
......@@ -22,6 +22,7 @@ Alexey Salmin <alexey dot salmin at gmail dot com> - Russian localisation
Alexis Ballier <aballlier at gentoo dot org> - Additional options in configure
Alexis de Lattre <alexis at videolan dot org> - Documentation, packaging, IGMPv3 support and various fixes
Amanpreet Singh Alam <aalam at users dot sf dot net> - Punjabi translation
Amir Gouini <a.gouini at qiplay dot com> - VLC mozilla plugin event listerners.
Andrea Guzzo <xant at xant dot net> - dc1394 firewire support
André de Barros Martins Ribeiro <andrerib at ajato.com.br> - Brazilian portuguese localization
Andre Pang <adre.pang at csiro dot au> - Annodex support
......@@ -316,6 +317,7 @@ William Hawkins - Speex RTP payload format
Xavier Maillard <zedek at fxgsproject.org> - audio converters
Xavier Marchesini <xav at alarue.net> - Win32 fixes
Xènia Albà Cantero <xenia_alba at hotmail.com> - Catalan translation
Yannick Bréhon <y.brehon at qiplay dot com> - VLC mozilla plugin event listerners.
Ye zhang <yzhang90003 _at_ gmail dot com> - Fix for VLM RTSP concurent LEAVE make VLC crash
Yuehua Zhao <zhao908@hotmail.com> - real video codec
Yuksel Yildirim <xleopar at yahoo d0t com> - Turkish localisation
......
......@@ -50,6 +50,71 @@
return INVOKERESULT_GENERIC_ERROR; \
} } while(false)
#define ERROR_EVENT_NOT_FOUND "ERROR: One or more events could not be found."
#define ERROR_API_VERSION "ERROR: NPAPI version not high enough. (Gecko >= 1.9 needed)"
// Make a copy of an NPVariant.
NPVariant copyNPVariant(const NPVariant& original)
{
NPVariant res;
if (NPVARIANT_IS_STRING(original))
STRINGZ_TO_NPVARIANT(strdup(NPVARIANT_TO_STRING(original).utf8characters), res);
else if (NPVARIANT_IS_INT32(original))
INT32_TO_NPVARIANT(NPVARIANT_TO_INT32(original), res);
else if (NPVARIANT_IS_DOUBLE(original))
DOUBLE_TO_NPVARIANT(NPVARIANT_TO_DOUBLE(original), res);
else if (NPVARIANT_IS_OBJECT(original))
{
NPObject *obj = NPVARIANT_TO_OBJECT(original);
NPN_RetainObject(obj);
OBJECT_TO_NPVARIANT(obj, res);
}
else if (NPVARIANT_IS_BOOLEAN(original))
BOOLEAN_TO_NPVARIANT(NPVARIANT_TO_BOOLEAN(original), res);
return res;
}
// Parse an event Array given as a NPObject by JS.
// This function is similar to LibvlcPlaylistNPObject::parseOptions,
// but we don't use it because it's not clearly accessible and the FIXME flags
// implie that it might be modified.
bool parseEventArray(NPObject *obj, eventtypes_bitmap_t &eventToGet, NPP instance)
{
NPIdentifier propId = NPN_GetStringIdentifier("length");
NPVariant value;
if (!NPN_GetProperty(instance, obj, propId, &value))
return false;
int count = NPVARIANT_TO_INT32(value);
NPN_ReleaseVariantValue(&value);
if (count == 0)
return false;
int nOptions = 0;
while (nOptions < count)
{
propId = NPN_GetIntIdentifier(nOptions);
// if there is no other string in the array.
if( ! NPN_GetProperty(instance, obj, propId, &value) )
break;
// if the element is not a string.
if( ! NPVARIANT_IS_STRING(value) )
{
NPN_ReleaseVariantValue(&value);
break;
}
if (!eventToGet.add_event(NPVARIANT_TO_STRING(value).utf8characters))
return false;
nOptions++;
}
return true;
}
/*
** implementation of libvlc root object
*/
......@@ -80,6 +145,7 @@ const NPUTF8 * const LibvlcRootNPObject::propertyNames[] =
"playlist",
"subtitle",
"video",
"events",
"VersionInfo",
};
COUNTNAMES(LibvlcRootNPObject,propertyCount,propertyNames);
......@@ -91,6 +157,7 @@ enum LibvlcRootNPObjectPropertyIds
ID_root_playlist,
ID_root_subtitle,
ID_root_video,
ID_root_events,
ID_root_VersionInfo,
};
......@@ -122,6 +189,14 @@ LibvlcRootNPObject::getProperty(int index, NPVariant &result)
InstantObj<LibvlcVideoNPObject>( videoObj );
OBJECT_TO_NPVARIANT(NPN_RetainObject(videoObj), result);
return INVOKERESULT_NO_ERROR;
case ID_root_events:
// create child object in lazyman fashion to avoid
// ownership problem with firefox
if( ! eventObj )
eventObj = NPN_CreateObject(_instance,
RuntimeNPClass<LibvlcEventNPObject>::getClass());
OBJECT_TO_NPVARIANT(NPN_RetainObject(eventObj), result);
return INVOKERESULT_NO_ERROR;
case ID_root_VersionInfo:
return invokeResultString(libvlc_get_version(),result);
default:
......@@ -1986,3 +2061,125 @@ LibvlcDeinterlaceNPObject::invoke(int index, const NPVariant *args,
return INVOKERESULT_NO_ERROR;
}
/*
** implementation of libvlc event object
*/
const NPUTF8 * const LibvlcEventNPObject::propertyNames[] =
{
};
enum LibvlcEventNPObjectPropertyIds
{
};
COUNTNAMES(LibvlcEventNPObject,propertyCount,propertyNames);
const NPUTF8 * const LibvlcEventNPObject::methodNames[] =
{
"addListener",
"removeListeners",
};
COUNTNAMES(LibvlcEventNPObject,methodCount,methodNames);
enum LibvlcEventNPObjectMethodIds
{
ID_event_addListener,
ID_event_removeListeners,
};
bool LibvlcEventNPObject::parseArgs(const NPVariant *args, uint32_t argCount,
eventtypes_bitmap_t &eventToGet)
{
if (argCount > 2)
eventToGet.clear();
for (int argIndex = 2; argIndex < argCount; argIndex++)
{
if (NPVARIANT_IS_STRING(args[argIndex]))
{
if (!eventToGet.add_event(NPVARIANT_TO_STRING(args[argIndex]).utf8characters))
return false;
}
else if (NPVARIANT_IS_OBJECT(args[argIndex]))
{
if (!parseEventArray(NPVARIANT_TO_OBJECT(args[argIndex]), eventToGet, _instance))
return false;
}
else
return false;
}
return true;
}
RuntimeNPObject::InvokeResult
LibvlcEventNPObject::invoke(int index, const NPVariant *args,
uint32_t argCount, NPVariant &result)
{
/* is plugin still running */
if( isPluginRunning() )
{
libvlc_exception_t ex;
libvlc_exception_init(&ex);
switch( index )
{
case ID_event_addListener:
if (argCount >= 2)
{
// Checks if the first argument is a NPObject
if (!NPVARIANT_IS_OBJECT(args[0]))
return INVOKERESULT_NO_SUCH_METHOD;
// Checks if the browser has the NPAPI version 0.19 at least.
if (!VlcPlugin::canUseEventListener())
{
NPN_SetException(this, strdup(ERROR_API_VERSION));
return INVOKERESULT_GENERIC_ERROR;
}
VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
// Gets the binary field corresponding to the events the
// listener must listen to if specified.
// Else, listen to all events.
eventtypes_bitmap_t eventToGet;
eventToGet.set_all_events();
if (!parseArgs(args, argCount, eventToGet))
{
NPN_SetException(this, strdup(ERROR_EVENT_NOT_FOUND));
return INVOKERESULT_GENERIC_ERROR;
}
NPObject *listener = NPVARIANT_TO_OBJECT(args[0]);
NPN_RetainObject(listener);
EventListener *eventListener = new EventListener();
eventListener->listener = listener;
eventListener->id = copyNPVariant(args[1]);
eventListener->eventMap = eventToGet;
p_plugin->eventToCatch.add_event(eventToGet);
p_plugin->eventListeners.push_back(eventListener);
return INVOKERESULT_NO_ERROR;
}
return INVOKERESULT_NO_SUCH_METHOD;
case ID_event_removeListeners:
if (argCount == 0)
{
VlcPlugin* p_plugin = getPrivate<VlcPlugin>();
p_plugin->eventListeners.clear();
p_plugin->eventToCatch.clear();
return INVOKERESULT_NO_ERROR;
}
return INVOKERESULT_NO_SUCH_METHOD;
default:
;
}
}
return INVOKERESULT_GENERIC_ERROR;
}
......@@ -38,7 +38,8 @@ protected:
inputObj(NULL),
playlistObj(NULL),
subtitleObj(NULL),
videoObj(NULL) {};
videoObj(NULL),
eventObj(NULL) {};
virtual ~LibvlcRootNPObject();
......@@ -58,6 +59,7 @@ private:
NPObject *playlistObj;
NPObject *subtitleObj;
NPObject *videoObj;
NPObject *eventObj;
};
class LibvlcAudioNPObject: public RuntimeNPObject
......@@ -262,3 +264,24 @@ protected:
InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result);
};
class LibvlcEventNPObject: public RuntimeNPObject
{
protected:
friend class RuntimeNPClass<LibvlcEventNPObject>;
LibvlcEventNPObject(NPP instance, const NPClass *aClass) :
RuntimeNPObject(instance, aClass) {};
virtual ~LibvlcEventNPObject() {};
static const int propertyCount;
static const NPUTF8 * const propertyNames[];
static const int methodCount;
static const NPUTF8 * const methodNames[];
InvokeResult invoke(int index, const NPVariant *args, uint32_t argCount, NPVariant &result);
bool parseArgs(const NPVariant *args, uint32_t argCount,
eventtypes_bitmap_t &eventToGet);
};
......@@ -100,6 +100,16 @@ NPN_Version(int* plugin_major, int* plugin_minor,
*netscape_minor = gNetscapeFuncs.version & 0xFF;
}
void
NPN_PluginThreadAsyncCall(NPP plugin,
void (*func)(void *),
void *userData)
{
#if (((NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR) >= 20)
return (*gNetscapeFuncs.pluginthreadasynccall)(plugin, func, userData);
#endif
}
NPError
NPN_GetValue(NPP instance, NPNVariable variable, void *r_value)
{
......@@ -846,6 +856,10 @@ NP_Initialize(NPNetscapeFuncs* nsTable, NPPluginFuncs* pluginFuncs)
gNetscapeFuncs.memfree = nsTable->memfree;
gNetscapeFuncs.memflush = nsTable->memflush;
gNetscapeFuncs.reloadplugins = nsTable->reloadplugins;
#if (((NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR) >= 20)
gNetscapeFuncs.pluginthreadasynccall =
nsTable->pluginthreadasynccall;
#endif
#ifdef OJI
if( minor >= NPVERS_HAS_LIVECONNECT )
{
......
......@@ -36,6 +36,7 @@
#include "control/npolibvlc.h"
#include <ctype.h>
#include <string>
/*****************************************************************************
* VlcPlugin constructor and destructor
......@@ -86,6 +87,48 @@ static bool boolValue(const char *value) {
!strcasecmp(value, "yes") );
}
void eventAsync(void *param)
{
VlcPlugin *plugin = (VlcPlugin*)param;
NPVariant result;
NPVariant params[2];
pthread_mutex_lock(&plugin->mutex);
for (int i = 0; i < plugin->eventList.size(); i++)
{
for (int j = 0; j < plugin->eventListeners.size(); j++)
{
libvlc_event_type_t event = plugin->eventList[i];
if (plugin->eventListeners[j]->eventMap.have_event(event))
{
STRINGZ_TO_NPVARIANT(libvlc_event_type_name(event), params[0]);
params[1] = plugin->eventListeners[j]->id;
NPN_InvokeDefault(plugin->getBrowser(), plugin->eventListeners[j]->listener, params, 2, &result);
NPN_ReleaseVariantValue(&result);
}
}
}
plugin->eventList.clear();
pthread_mutex_unlock(&plugin->mutex);
}
void event_callback(const libvlc_event_t* event, void *param)
{
VlcPlugin *plugin = (VlcPlugin*)param;
pthread_mutex_lock(&plugin->mutex);
if (plugin->eventToCatch.have_event(event->type))
plugin->eventList.push_back(event->type);
pthread_mutex_unlock(&plugin->mutex);
NPN_PluginThreadAsyncCall(plugin->getBrowser(), eventAsync, plugin);
}
NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
{
/* prepare VLC command line */
......@@ -259,6 +302,9 @@ NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
/* new APIs */
p_scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
if (pthread_mutex_init(&mutex, NULL) != 0)
return NPERR_GENERIC_ERROR;
return NPERR_NO_ERROR;
}
......@@ -274,6 +320,15 @@ VlcPlugin::~VlcPlugin()
libvlc_media_list_release( libvlc_media_list );
if( libvlc_instance )
libvlc_release(libvlc_instance);
for (int i = 0; i < eventListeners.size(); i++)
{
NPN_ReleaseObject(eventListeners[i]->listener);
NPN_ReleaseVariantValue(&(eventListeners[i]->id));
delete eventListeners[i];
}
pthread_mutex_destroy(&mutex);
}
/*****************************************************************************
......@@ -336,6 +391,7 @@ int VlcPlugin::playlist_add_extended_untrusted( const char *mrl, const char *nam
bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
{
libvlc_media_t *p_m = NULL;
libvlc_event_manager_t *eventManager = NULL;
libvlc_media_list_lock(libvlc_media_list);
......@@ -360,8 +416,29 @@ bool VlcPlugin::playlist_select( int idx, libvlc_exception_t *ex )
libvlc_media_player = libvlc_media_player_new_from_media(p_m,ex);
if( libvlc_media_player )
{
set_player_window();
// Registers the events we're interested in.
eventManager = libvlc_media_player_event_manager(libvlc_media_player, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerOpening, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerStopped, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerPaused, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerForward, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerBackward, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerTimeChanged, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerTitleChanged, event_callback, this, ex);
libvlc_event_attach(eventManager, libvlc_MediaPlayerSnapshotTaken, event_callback, this, ex);
}
libvlc_media_release( p_m );
return !libvlc_exception_raised(ex);
......@@ -899,3 +976,20 @@ vlc_toolbar_clicked_t VlcPlugin::getToolbarButtonClicked( int i_xpos, int i_ypos
}
#undef BTN_SPACE
#endif
// Verifies the version of the NPAPI.
// The eventListeners use a NPAPI function available
// since Gecko 1.9.
bool VlcPlugin::canUseEventListener()
{
int plugin_major, plugin_minor;
int browser_major, browser_minor;
NPN_Version(&plugin_major, &plugin_minor,
&browser_major, &browser_minor);
if (browser_minor >= 19 || browser_major > 0)
return true;
return false;
}
......@@ -31,6 +31,7 @@
#include <vlc/vlc.h>
#include <npapi.h>
#include <vector>
#include "control/nporuntime.h"
#if !defined(XP_MACOSX) && !defined(XP_UNIX) && !defined(XP_WIN)
......@@ -79,6 +80,109 @@ typedef enum vlc_toolbar_clicked_e {
clicked_Unmute
} vlc_toolbar_clicked_t;
// Note that the accessor functions are unsafe, but this is handled in
// the next layer up. 64bit uints can be substituted to taste (shift=6).
template<size_t M> class bitmap
{
private:
typedef uint32_t bitu_t; enum { shift=5 };
enum { bmax=M, bpu=1<<shift, mask=bpu-1, units=(bmax+bpu-1)/bpu };
bitu_t bits[units];
public:
bool get(size_t idx) const
{
return bits[idx>>shift]&(1<<(idx&mask));
}
void set(size_t idx) { bits[idx>>shift]|= 1<<(idx&mask); }
void reset(size_t idx) { bits[idx>>shift]&=~(1<<(idx&mask)); }
void toggle(size_t idx) { bits[idx>>shift]^= 1<<(idx&mask); }
size_t maxbit() const { return bmax; }
void clear() { memset(bits,0,sizeof(bits)); }
bitmap() { clear(); }
~bitmap() { }
};
typedef bitmap<libvlc_num_event_types> parent;
class eventtypes_bitmap_t: private bitmap<libvlc_num_event_types> {
private:
typedef libvlc_event_type_t event_t;
event_t find_event(const char *s) const
{
event_t i;
for(i=0;i<maxbit();++i)
if(!strcmp(s,libvlc_event_type_name(i)))
break;
return i;
}
public:
bool add_event(const eventtypes_bitmap_t &eventBitmap)
{
event_t i;
for(i=0;i<maxbit();++i)
if (eventBitmap.have_event(i))
set(i);
}
bool add_event(const char *s)
{
if (!strcmp(s, "all"))
{
set_all_events();
return true;
}
if (!strcmp(s, "none"))
{
clear();
return true;
}
event_t event = find_event(s);
bool b = event<maxbit();
if(b) set(event);
return b;
}
bool del_event(const char *s)
{
event_t event=find_event(s);
bool b=event<maxbit();
if(b) reset(event);
return b;
}
bool have_event(libvlc_event_type_t event) const
{
return event<maxbit()?get(event):false;
}
void clear()
{
parent::clear();
}
void set_all_events()
{
event_t i;
for(i=0;i<maxbit();++i)
set(i);
}
};
// Structure used to represent an EventListener.
// It contains the listener object that will be invoked,
// An Id given by the addEventListener function and sent
// when invoking the listener. Can be anything or nothing.
// The profile associated with the listener used to invoke
// the listener only to some events.
typedef struct s_EventListener
{
NPObject *listener;
NPVariant id;
eventtypes_bitmap_t eventMap;
} EventListener;
void event_callback(const libvlc_event_t* event, void *param);
class VlcPlugin
{
public:
......@@ -197,6 +301,15 @@ public:
bool player_has_vout( libvlc_exception_t * );
// Events related members
std::vector<EventListener*> eventListeners; // List of registered listerners.
std::vector<libvlc_event_type_t> eventList; // List of event sent by VLC that must be returned to JS.
eventtypes_bitmap_t eventToCatch;
pthread_mutex_t mutex;
static bool canUseEventListener();
private:
bool playlist_select(int,libvlc_exception_t *);
void set_player_window();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment