[xiph-commits] r3026 - in liboggplay/trunk/plugin: . mac/liboggplay.xcodeproj support test

tahn at svn.annodex.net tahn at svn.annodex.net
Fri Jun 22 00:57:43 PDT 2007


Author: tahn
Date: 2007-06-22 00:57:43 -0700 (Fri, 22 Jun 2007)
New Revision: 3026

Modified:
   liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj
   liboggplay/trunk/plugin/nsILibOggPlugin.idl
   liboggplay/trunk/plugin/plugin.cpp
   liboggplay/trunk/plugin/plugin.h
   liboggplay/trunk/plugin/plugin_gui.h
   liboggplay/trunk/plugin/plugin_gui_linux.c
   liboggplay/trunk/plugin/plugin_gui_mac.c
   liboggplay/trunk/plugin/plugin_gui_win32.c
   liboggplay/trunk/plugin/plugin_oggplay.c
   liboggplay/trunk/plugin/plugin_oggplay.h
   liboggplay/trunk/plugin/support/nsScriptablePeer.cpp
   liboggplay/trunk/plugin/test/test.html
Log:
Implemented the Javascript API interface functions for single-movie mode.
Playlist interface functions still to come.


Modified: liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj
===================================================================
--- liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj	2007-06-22 07:57:43 UTC (rev 3026)
@@ -64,6 +64,7 @@
 		2C83ABCA0BEAC328004C14F4 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
 		2C96CCA30C0402280015B6AC /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = "<absolute>"; };
 		2C96D1320C0666340015B6AC /* sydney_audio_mac.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = sydney_audio_mac.c; path = ../audio/sydney_audio_mac.c; sourceTree = SOURCE_ROOT; };
+		2C9F53E10C2A5727007365C0 /* nsILibOggPlugin.idl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = nsILibOggPlugin.idl; path = ../nsILibOggPlugin.idl; sourceTree = SOURCE_ROOT; };
 		2CA761D40BF978E10008A3B7 /* std_semaphore.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = std_semaphore.h; path = ../std_semaphore.h; sourceTree = SOURCE_ROOT; };
 		2CB42DDE0C291F6800DA05E7 /* local_fishsound.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = local_fishsound.a; path = libs/local_fishsound.a; sourceTree = SOURCE_ROOT; };
 		2CB42DDF0C291F6800DA05E7 /* local_oggz.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = local_oggz.a; path = libs/local_oggz.a; sourceTree = SOURCE_ROOT; };
@@ -162,6 +163,7 @@
 				2C81E4130C1E119F008364B7 /* plugin_playlist.c */,
 				2C81E4120C1E119F008364B7 /* plugin_playlist.h */,
 				2CA761D40BF978E10008A3B7 /* std_semaphore.h */,
+				2C9F53E10C2A5727007365C0 /* nsILibOggPlugin.idl */,
 				2CF2FD540C191FD70074A9C3 /* audio */,
 				2CD58C930BD33B65001D751D /* include */,
 				2CD58C960BD33B65001D751D /* support */,

Modified: liboggplay/trunk/plugin/nsILibOggPlugin.idl
===================================================================
--- liboggplay/trunk/plugin/nsILibOggPlugin.idl	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/nsILibOggPlugin.idl	2007-06-22 07:57:43 UTC (rev 3026)
@@ -40,31 +40,58 @@
 
 #include "nsISupports.idl"
 
+[scriptable, uuid(482e1890-1fe5-11d5-9cf8-0260b0fbd8ae)]
+interface nsILibOggCallbackString : nsISupports {
+  void call(in string arg);
+};
+
 [scriptable, uuid(482e1890-1fe5-11d5-9cf8-0260b0fbd8ad)]
-interface nsILibOggCallback : nsISupports {
-  void cmmlCallback(in string cmmlData);
+interface nsILibOggCallbackNoArg : nsISupports {
+  void call();
 };
 
 [scriptable, uuid(482e1890-1fe5-11d5-9cf8-0260b0fbd8ac)]
 interface nsILibOggPlugin : nsISupports {
-  readonly attribute string version;
+
+  const short apiVersionMajor = 0;
+  const short apiVersionMinor = 1;
+
+  string getVersionString();
+
+  /* basic playback functions */
+  void play();
+  void pause();
+  void restart();
+  short getCurrentState();
+
+  /* movie and position control */
   void setCurrentMovie(in string URL);
   string getCurrentMovie();
+  boolean setPlayPosition(in long milliseconds);
   long getPlayPosition();
-  /* playback interface functions */
-  void play();
-  void pause();  
-  void restart();
-  short getCurrentState();
-  /* CMML related */
-  void registerCallbackObject(in nsILibOggCallback callback);
-  void retrieveAnnotations(out string xmlData);
+
   /* audio related */
   void setVolume(in float volume);
   float getVolume();
+
+  /* miscellaneous queries */
+  long getWindowWidth();
+  long getWindowHeight();
+  long getBufferedTime();
+  long getMovieLength();
+
+  /* CMML related */
+  string retrieveAnnotations();
+
+  /* callbacks */
+  void registerCMMLCallback(in nsILibOggCallbackString callback);
+  void registerEndPlayCallback(in nsILibOggCallbackNoArg callback);
+
   /* playlist related */
+/* //!todo
   void registerPlaylistCallback(in string playlistCallback);
   string getMovieAt(in short position);
   void setMovieAt(in short position, in string url);
   void appendMovie(in string url);
+*/
 };

Modified: liboggplay/trunk/plugin/plugin.cpp
===================================================================
--- liboggplay/trunk/plugin/plugin.cpp	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin.cpp	2007-06-22 07:57:43 UTC (rev 3026)
@@ -67,16 +67,15 @@
 #include "plugin_tools.h"
 }
 
-// service manager which will give the access to all public browser services
-// we will use memory service as an illustration
-static nsIServiceManager * gServiceManager = NULL;
 
+#define PLUGIN_VERSION    "1.0"
+
 #if defined(XP_UX) || defined(XP_MACOSX)
 
 #define MIME_TYPES_HANDLED      "application/liboggplay"
 #define PLUGIN_NAME             "Annodex/Ogg Plugin for Mozilla"
 #define MIME_TYPES_DESCRIPTION  MIME_TYPES_HANDLED"::"PLUGIN_NAME
-#define PLUGIN_DESCRIPTION      PLUGIN_NAME " (v0.1.0)" 
+#define PLUGIN_DESCRIPTION      PLUGIN_NAME PLUGIN_VERSION
 
 char* NPP_GetMIMEDescription(void)
 {
@@ -111,10 +110,6 @@
 NPError 
 NS_PluginInitialize()
 {
-  // this is probably a good place to get the service manager
-  // note that Mozilla will add reference, so do not forget to release
-  nsISupports * sm = NULL;  
-
 #if defined(XP_UX)
   NPError         err             = NPERR_NO_ERROR;
   PRBool          supportsXEmbed  = PR_FALSE;
@@ -130,26 +125,13 @@
   if (err != NPERR_NO_ERROR || toolkit != NPNVGtk2)
     return NPERR_INCOMPATIBLE_VERSION_ERROR;
 #endif
-
-  NPN_GetValue(NULL, NPNVserviceManager, &sm);
-
-  // Mozilla returns nsIServiceManager so we can use it directly; doing QI on
-  // nsISupports here can still be more appropriate in case something is changed 
-  // in the future so we don't need to do casting of any sort.
-  if(sm) {
-    sm->QueryInterface(NS_GET_IID(nsIServiceManager), (void**)&gServiceManager);
-    NS_RELEASE(sm);
-  }
-  
   return NPERR_NO_ERROR;
 }
 
 void 
 NS_PluginShutdown()
 {
-  // we should release the service manager
-  NS_IF_RELEASE(gServiceManager);
-  gServiceManager = NULL;
+
 }
 
 
@@ -162,26 +144,24 @@
 {
   int i;
   char * source = NULL;
-  
-  if(!aCreateDataStruct)
+
+  if (!aCreateDataStruct)
     return NULL;
 
-  nsPluginInstance * plugin = new nsPluginInstance(aCreateDataStruct->instance);
-  
-  // set to FALSE for windowless.  But that doesn't seem to be supported on
-  // Lunix
-  NPN_SetValue(aCreateDataStruct->instance, NPPVpluginWindowBool, (void *)TRUE);
-  
   for (i = 0; i < aCreateDataStruct->argc; i++) {
     printf("%s=%s; ", aCreateDataStruct->argn[i], aCreateDataStruct->argv[i]);
     if (strcmp(aCreateDataStruct->argn[i], "src") == 0) {
-      source = strdup(aCreateDataStruct->argv[i]);
+      source = aCreateDataStruct->argv[i];
     }
   }
   printf("\n");
 
-  plugin->setSource(source);
+  nsPluginInstance * plugin =
+    new nsPluginInstance(aCreateDataStruct->instance, source);
 
+  // Set to FALSE for windowless. But that doesn't seem to be supported on Lunix
+  NPN_SetValue(aCreateDataStruct->instance, NPPVpluginWindowBool, (void *)TRUE);
+
   /*
   NPObject      * value;
   NPVariant       v1, v2;
@@ -227,7 +207,8 @@
 //
 // nsPluginInstance class implementation
 //
-nsPluginInstance::nsPluginInstance(NPP aInstance) : nsPluginInstanceBase(),
+nsPluginInstance::nsPluginInstance(NPP aInstance, const char *source) :
+  nsPluginInstanceBase(),
   mInstance(aInstance),
   mPluginInitialised(FALSE),
   mWindowInitialised(FALSE), 
@@ -235,17 +216,18 @@
   mScriptablePeer(NULL),
   mOggHandle(NULL),
   mGuiHandle(NULL),
-  mCallback(NULL)
+  mSource(NULL),
+  mCmmlCallback(NULL),
+  mEndPlayCallback(NULL)
 #if defined(XP_MACOSX)
   ,
-  mOutputCleared(FALSE),
-  mCmmlDataProvided(FALSE)
+  mOutputCleared(FALSE)
 #endif
 {
   mString[0] = '\0';
-#if defined(XP_MACOSX)
-  pthread_mutex_init(&mCmmlMutex, NULL);
-#endif
+  setSource(source);
+  SEM_CREATE(mCmmlSem, 1);
+  SEM_CREATE(mEndPlaySem, 1);
 }
 
 nsPluginInstance::~nsPluginInstance()
@@ -258,11 +240,50 @@
     mScriptablePeer->SetInstance(NULL);
     NS_IF_RELEASE(mScriptablePeer);
   }
+  if (mSource != NULL) {
+    free(mSource);
+  }
+  if (mCmmlCallback != NULL) {
+    NS_RELEASE(mCmmlCallback);
+  }
+  if (mEndPlayCallback != NULL) {
+    NS_RELEASE(mEndPlayCallback);
+  }
+  SEM_CLOSE(mCmmlSem);
+  SEM_CLOSE(mEndPlaySem);
 #if defined(XP_MACOSX)
-  pthread_mutex_destroy(&mCmmlMutex);
+  clearCmmlStrings();
 #endif
 }
 
+#if defined(XP_MACOSX)
+void
+nsPluginInstance::clearCmmlStrings() {
+  for (unsigned int i = 0; i < mCmmlStrings.size(); i++) {
+    free(mCmmlStrings[i]);
+  }
+  mCmmlStrings.clear();
+}
+#endif
+
+void
+nsPluginInstance::setSource(const char *source)
+{
+  if (mSource != NULL) {
+    free(mSource);
+    mSource = NULL;
+  }
+  if (source != NULL) {
+    mSource = strdup(source);
+  }
+}
+
+char *
+nsPluginInstance::getSource()
+{
+  return mSource;
+}
+
 NPBool 
 nsPluginInstance::init(NPWindow* aWindow)
 {  
@@ -276,7 +297,6 @@
 void 
 nsPluginInstance::shut()
 {
-
   if (mWindowInitialised) {    
     shut_gui(mGuiHandle);
     mGuiHandle = NULL;
@@ -291,152 +311,6 @@
   return mPluginInitialised;
 }
 
-void 
-nsPluginInstance::getVersion(char* *aVersion)
-{
-  const char *ua = NPN_UserAgent(mInstance);
-  char*& version = *aVersion;
-
-  // although we can use NPAPI NPN_MemAlloc call to allocate memory:
-  //    version = (char*)NPN_MemAlloc(strlen(ua) + 1);
-  // for illustration purposed we use the service manager to access 
-  // the memory service provided by Mozilla
-  nsIMemory * nsMemoryService = NULL;
-  
-  if (gServiceManager) {
-    // get service using its contract id and use it to allocate the memory
-    gServiceManager->GetServiceByContractID("@mozilla.org/xpcom/memory-service;1", NS_GET_IID(nsIMemory), (void **)&nsMemoryService);
-    if(nsMemoryService)
-      version = (char *)nsMemoryService->Alloc(strlen(ua) + 1);
-  }
-
-  if (version)
-    strcpy(version, ua);
-
-  // release service
-  NS_IF_RELEASE(nsMemoryService);
-}
-
-void 
-nsPluginInstance::pauseMovie() {
-  pause_gui(mGuiHandle);
-}
-
-void 
-nsPluginInstance::playMovie() {
-  start_gui(mGuiHandle);
-}
-
-void
-nsPluginInstance::restartMovie() {
-  char * URL;  
-  get_oggplay_curr_url(mOggHandle, &URL);
-  if (URL != NULL) {
-    mSource = strdup(URL);
-    mOggHandle = initialise_oggplay(mSource);
-    update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
-    start_gui(mGuiHandle);
-  }
-}
-
-short 
-nsPluginInstance::getCurrentState() {
-  return get_gui_current_state(mGuiHandle);
-}
-
-void 
-nsPluginInstance::setCallbackObject(nsILibOggCallback *cbObj) {
-
-  mCallback = cbObj;
-  NS_ADDREF(cbObj);
-}
-
-void
-nsPluginInstance::onCMMLData(char **cmml_data, int cmml_size) {
-
-  if (mCallback != NULL) {
-#if defined(XP_MACOSX)
-    // The Mac doesn't like cross-thread calls between the plugin and
-    // the browser. We need to execute the cmml callback in the main browser
-    // thread, but this function is called from the GUI display thread. So we
-    // buffer up the cmml strings here and piggyback on the browser-originated
-    // calls to HandleEvent below to send the strings to the browser.
-    pthread_mutex_lock(&mCmmlMutex);
-    for (int i = 0; i < cmml_size; i++) {
-      mCmmlStrings.push_back(cmml_data[i]);
-    }
-    mCmmlDataProvided = TRUE;
-    pthread_mutex_unlock(&mCmmlMutex);
-#else
-    for (int i = 0; i < cmml_size; i++) {
-      mCallback->CmmlCallback(cmml_data[i]);
-    }
-#endif
-  }
-}
-
-extern "C" void 
-onCMMLData(nsPluginInstance *i, char **cmml_data, int cmml_size) {
-  i->onCMMLData(cmml_data, cmml_size);
-}
-
-char *
-nsPluginInstance::retrieveAllAnnotations() {
-  return NULL;
-}
-
-void 
-nsPluginInstance::setVolume(float volume) {
-}
-
-float
-nsPluginInstance::getVolume() {
-  return (float)0.0;
-}
-
-void 
-nsPluginInstance::setPlaylistCallback(const char *callback) {
-}
-
-char*
-nsPluginInstance::getMovieAt(int position) {
-  return NULL;
-}
-
-void 
-nsPluginInstance::setMovieAt(int position, const char *url) {
-}
-
-void 
-nsPluginInstance::appendMovie(const char *url) {
-}
-
-void 
-nsPluginInstance::setCurrentMovie(const char *URL)
-{
-  // It's ok to lose the reference to the old oggplay handle (no, really, it
-  // is). The gui code will destroy it before swapping over to the new handle.
-  mSource = strdup(URL);
-  mOggHandle = initialise_oggplay(mSource);
-  update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
-}
-
-char *  
-nsPluginInstance::getCurrentMovie()
-{
-  char ** URL = NULL;
-  get_oggplay_curr_url(mOggHandle, URL);
-  return *URL;
-}
-
-long
-nsPluginInstance::getPlayPosition()
-{
-
-  return get_oggplay_play_position(mOggHandle);
-  
-}
-
 NPError 
 nsPluginInstance::SetWindow(NPWindow *aWindow)
 {
@@ -448,7 +322,7 @@
   // -- MAC OS X SPECIFIC -
   if (mWindowInitialised == FALSE) {
  
-    if (mSource == NULL) {
+    if (getSource() == NULL) {
       return NPERR_NO_ERROR;
     }
     
@@ -456,11 +330,10 @@
     // code is responsible for destroying it, because only the gui code knows
     // when to shut down the old handle after a new media source has been
     // provided.
-    mOggHandle = initialise_oggplay(mSource);
+    mOggHandle = initialise_oggplay(getSource());
     mGuiHandle = initialise_gui(this, aWindow, mOggHandle);
     mWindow = aWindow;
     mWindowInitialised = TRUE;
-
   }
 
   return NPERR_NO_ERROR;
@@ -486,14 +359,18 @@
   // turn out to be useful for a couple of things.
   //
   // First, to send the cmml strings collected by onCMMLData to the browser..
-  if (mCmmlDataProvided) {
-    pthread_mutex_lock(&mCmmlMutex);
-    for (unsigned int i = 0; i < mCmmlStrings.size(); i++) {
-      mCallback->CmmlCallback(mCmmlStrings[i]);
+  // (since this function is called very frequently, we don't want to grab
+  // the semaphore every time, but checking the pointer for null before locking
+  // introduces a potential race condition, so we need to double-check).
+  if (mCmmlCallback != NULL) {
+    SEM_WAIT(mCmmlSem);
+    if (mCmmlCallback != NULL && mCmmlStrings.size() > 0) {
+      for (unsigned int i = 0; i < mCmmlStrings.size(); i++) {
+        mCmmlCallback->Call(mCmmlStrings[i]);
+      }
+      clearCmmlStrings();
     }
-    mCmmlStrings.clear();
-    mCmmlDataProvided = FALSE;
-    pthread_mutex_unlock(&mCmmlMutex);
+    SEM_CLOSE(mCmmlSem);
   }
 
   // ..and second, to handle hiding our output when the user changes tabs or
@@ -599,3 +476,215 @@
   return mScriptablePeer;
 }
 
+////////////////////////////////////////
+//
+// Javascript API implementation
+//
+void
+nsPluginInstance::getVersionString(
+  char **versionString, int apiVersionMajor, int apiVersionMinor
+) {
+  *versionString = (char *)NPN_MemAlloc(100);
+  if (*versionString != NULL) {
+    sprintf(*versionString,
+      "liboggplay (" PLUGIN_VERSION ") Annodex Media Plugin (API %d.%d)",
+      apiVersionMajor, apiVersionMinor
+    );
+  }
+}
+
+void
+nsPluginInstance::play() {
+  gui_play(mGuiHandle);
+}
+
+void
+nsPluginInstance::pause() {
+  gui_pause(mGuiHandle);
+}
+
+void
+nsPluginInstance::restart() {
+  if (getSource() != NULL) {
+    mOggHandle = initialise_oggplay(getSource());
+    update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
+    gui_play(mGuiHandle);
+  }
+}
+
+short
+nsPluginInstance::getCurrentState() {
+  return gui_get_current_state(mGuiHandle);
+}
+
+void
+nsPluginInstance::setCurrentMovie(const char *url) {
+  // It's ok to lose the reference to the old oggplay handle (no, really, it
+  // is). The gui code will destroy it before swapping over to the new handle.
+  setSource(url);
+  mOggHandle = initialise_oggplay(getSource());
+  update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
+}
+
+char *
+nsPluginInstance::getCurrentMovie() {
+  char *url = NULL;
+
+  if (getSource() != NULL) {
+    url = (char *)NPN_MemAlloc(strlen(getSource()) + 1);
+    if (url != NULL) {
+      strcpy(url, getSource());
+    }
+  }
+  return url;
+}
+
+bool
+nsPluginInstance::setPlayPosition(long milliseconds) {
+//!todo
+  return TRUE;
+}
+
+long
+nsPluginInstance::getPlayPosition() {
+  return get_oggplay_play_position(mOggHandle);
+}
+
+void
+nsPluginInstance::setVolume(float volume) {
+  gui_set_volume(mGuiHandle, volume);
+}
+
+float
+nsPluginInstance::getVolume() {
+  return gui_get_volume(mGuiHandle);
+}
+
+long
+nsPluginInstance::getWindowWidth() {
+  return gui_get_window_width(mGuiHandle);
+}
+
+long
+nsPluginInstance::getWindowHeight() {
+  return gui_get_window_height(mGuiHandle);
+}
+
+long
+nsPluginInstance::getBufferedTime() {
+//!todo
+  return 0;
+}
+
+long
+nsPluginInstance::getMovieLength() {
+//!todo
+  return 0;
+}
+
+char *
+nsPluginInstance::retrieveAnnotations() {
+//!todo
+  char *annotations = NULL;
+
+  annotations = (char *)NPN_MemAlloc(100);
+  if (annotations != NULL) {
+    strcpy(annotations, "all ur annotations are belong to us");
+  }
+  return annotations;
+}
+
+void
+nsPluginInstance::registerCMMLCallback(nsILibOggCallbackString *cbObj) {
+  SEM_WAIT(mCmmlSem);
+  if (mCmmlCallback != NULL) {
+    NS_RELEASE(mCmmlCallback);
+  }
+  mCmmlCallback = cbObj;
+  if (mCmmlCallback != NULL) {
+    NS_ADDREF(mCmmlCallback);
+  }
+#if defined(XP_MACOSX)
+  if (mCmmlCallback == NULL) {
+    clearCmmlStrings();
+  }
+#endif
+  SEM_SIGNAL(mCmmlSem);
+}
+
+void
+nsPluginInstance::registerEndPlayCallback(nsILibOggCallbackNoArg *cbObj) {
+  SEM_WAIT(mEndPlaySem);
+  if (mEndPlayCallback != NULL) {
+    NS_RELEASE(mEndPlayCallback);
+  }
+  mEndPlayCallback = cbObj;
+  if (mEndPlayCallback != NULL) {
+    NS_ADDREF(mEndPlayCallback);
+  }
+  SEM_SIGNAL(mEndPlaySem);
+}
+
+void
+nsPluginInstance::onCMMLData(char **cmml_data, int cmml_size) {
+  SEM_WAIT(mCmmlSem);
+  if (mCmmlCallback != NULL) {
+#if defined(XP_MACOSX)
+    // The Mac doesn't like cross-thread calls between the plugin and
+    // the browser. We need to execute the cmml callback in the main browser
+    // thread, but this function is called from the GUI display thread. So we
+    // buffer up the cmml strings here and piggyback on the browser-originated
+    // calls to HandleEvent to send the strings to the browser. We need to make
+    // copies of the strings because the oggplay frame can be freed before we
+    // get in to HandleEvent.
+    for (int i = 0; i < cmml_size; i++) {
+      mCmmlStrings.push_back(strdup(cmml_data[i]));
+    }
+#else
+    for (int i = 0; i < cmml_size; i++) {
+      mCmmlCallback->Call(cmml_data[i]);
+    }
+#endif
+  }
+  SEM_SIGNAL(mCmmlSem);
+}
+
+void
+nsPluginInstance::onEndPlay() {
+  SEM_WAIT(mEndPlaySem);
+  if (mEndPlayCallback != NULL) {
+    mEndPlayCallback->Call();
+  }
+  SEM_SIGNAL(mEndPlaySem);
+}
+
+extern "C" {
+void
+onCMMLData(nsPluginInstance *i, char **cmml_data, int cmml_size) {
+  i->onCMMLData(cmml_data, cmml_size);
+}
+
+void
+onEndPlay(nsPluginInstance *i) {
+  i->onEndPlay();
+}
+} // extern "C"
+
+/* //!todo
+void
+nsPluginInstance::setPlaylistCallback(const char *callback) {
+}
+
+char*
+nsPluginInstance::getMovieAt(int position) {
+  return NULL;
+}
+
+void
+nsPluginInstance::setMovieAt(int position, const char *url) {
+}
+
+void
+nsPluginInstance::appendMovie(const char *url) {
+}
+*/

Modified: liboggplay/trunk/plugin/plugin.h
===================================================================
--- liboggplay/trunk/plugin/plugin.h	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin.h	2007-06-22 07:57:43 UTC (rev 3026)
@@ -40,6 +40,7 @@
 
 #include "pluginbase.h"
 #include "nsScriptablePeer.h"
+#include "std_semaphore.h"
 
 #if defined(XP_UX)
 #include <X11/Xlib.h>
@@ -48,14 +49,13 @@
 #endif
  
 #if defined(XP_MACOSX)
-#include <pthread.h>
 #include <vector>
 #endif
  
 class nsPluginInstance : public nsPluginInstanceBase
 {
 public:
-  nsPluginInstance(NPP aInstance);
+  nsPluginInstance(NPP aInstance, const char *source);
   ~nsPluginInstance();
 
   NPBool init(NPWindow* aWindow);
@@ -72,34 +72,48 @@
   NPError NewStream(NPMIMEType type, NPStream* stream,  
 			NPBool seekable, uint16* stype);    
 
-  void setSource(char *source) {mSource = source;};
-
 #if defined(XP_UX)
   void redraw(Widget widget, XtPointer call_data);
 #endif
 
-  // locals
-  void playMovie();
-  void pauseMovie();
-  void restartMovie();  
-  void getVersion(char* *aVersion);
-  void setCurrentMovie(const char *URL);
-  char* getCurrentMovie();
-  long getPlayPosition();
-  short getCurrentState();
-  void setCallbackObject(nsILibOggCallback *cbObj);
-  void onCMMLData(char **cmml_data, int cmml_size);
-  char* retrieveAllAnnotations();
-  void setVolume(float volume);
-  float getVolume();
+  nsScriptablePeer* getScriptablePeer();
+
+  // Javascript API
+  void    getVersionString(
+            char **versionString, int apiVersionMajor, int apiVersionMinor
+          );
+  void    play();
+  void    pause();
+  void    restart();  
+  short   getCurrentState();
+  void    setCurrentMovie(const char *URL);
+  char  * getCurrentMovie();
+  bool    setPlayPosition(long milliseconds);
+  long    getPlayPosition();
+  void    setVolume(float volume);
+  float   getVolume();
+  long    getWindowWidth();
+  long    getWindowHeight();
+  long    getBufferedTime();
+  long    getMovieLength();
+  char  * retrieveAnnotations();
+
+  void    registerCMMLCallback(nsILibOggCallbackString *cbObj);
+  void    registerEndPlayCallback(nsILibOggCallbackNoArg *cbObj);
+  void    onCMMLData(char **cmml_data, int cmml_size);
+  void    onEndPlay();
+
+/* //!todo
   void setPlaylistCallback(const char *callback);
-  char* getMovieAt(int position);
+  char *getMovieAt(int position);
   void setMovieAt(int position, const char *url);
   void appendMovie(const char *url); 
+*/
 
-  nsScriptablePeer* getScriptablePeer();
+private:
+  void    setSource(const char *source);
+  char  * getSource();
 
-private:
   NPP                 mInstance;
   NPBool              mPluginInitialised;
   NPBool              mWindowInitialised;
@@ -108,15 +122,18 @@
   void              * mOggHandle;
   void              * mGuiHandle;
   char              * mSource;
-  nsILibOggCallback * mCallback;
 
+  nsILibOggCallbackString   * mCmmlCallback;
+  nsILibOggCallbackNoArg    * mEndPlayCallback;
+  semaphore                   mCmmlSem;
+  semaphore                   mEndPlaySem;
+
 #if defined(XP_WIN)
   WNDPROC             lpOldProc;  
 #elif defined(XP_MACOSX)
   NPBool              mOutputCleared;
-  volatile NPBool     mCmmlDataProvided;
-  pthread_mutex_t     mCmmlMutex;
   std::vector<char*>  mCmmlStrings;
+  void clearCmmlStrings();
 #endif
 
 public:

Modified: liboggplay/trunk/plugin/plugin_gui.h
===================================================================
--- liboggplay/trunk/plugin/plugin_gui.h	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin_gui.h	2007-06-22 07:57:43 UTC (rev 3026)
@@ -59,19 +59,28 @@
 void
 update_gui_with_new_oggplay(void *gui_handle, void *oggplay_handle);
 
-short
-get_gui_current_state(void *gui_handle);
-
-void 
-set_gui_cmml_callback(void *handle, char * callback, NPP mInstance);
-
 void
 shut_gui(void *gui_handle);
 
 void
-pause_gui(void *gui_handle);
+gui_play(void *gui_handle);
 
 void
-start_gui(void *gui_handle);
+gui_pause(void *gui_handle);
 
+short
+gui_get_current_state(void *gui_handle);
+
+void
+gui_set_volume(void *gui_handle, float volume);
+
+float
+gui_get_volume(void *gui_handle);
+
+long
+gui_get_window_width(void *gui_handle);
+
+long
+gui_get_window_height(void *gui_handle);
+
 #endif

Modified: liboggplay/trunk/plugin/plugin_gui_linux.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_linux.c	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin_gui_linux.c	2007-06-22 07:57:43 UTC (rev 3026)
@@ -363,18 +363,18 @@
   SEM_SIGNAL(info->oggplay_replace_sem); 
 }
 
-void pause_gui(void *handle) {
+void gui_pause(void *handle) {
   PluginWindowInfo  * info = (PluginWindowInfo *)handle;
   info->playback_state = PAUSED;
 }
 
-void start_gui(void *handle) {
+void gui_play(void *handle) {
   PluginWindowInfo  * info = (PluginWindowInfo *)handle;
   info->playback_state = PLAYING;
 }
 
 short
-get_gui_current_state(void *handle) {
+gui_get_current_state(void *handle) {
   short state;
   PluginWindowInfo  * info = (PluginWindowInfo *)handle;
   switch (info->playback_state) {
@@ -418,3 +418,25 @@
 
 }
 
+void
+gui_set_volume(void *handle, float volume) {
+//!todo
+}
+
+float
+gui_get_volume(void *handle) {
+//!todo
+  return 0.0f;
+}
+
+long
+gui_get_window_width(void *handle) {
+//!todo
+  return 0;
+}
+
+long
+gui_get_window_height(void *handle) {
+//!todo
+  return 0;
+}

Modified: liboggplay/trunk/plugin/plugin_gui_mac.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_mac.c	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin_gui_mac.c	2007-06-22 07:57:43 UTC (rev 3026)
@@ -649,19 +649,31 @@
 
 
 void
-pause_gui(void *gui_handle) {
+shut_gui(void *gui_handle) {
 
   PluginWindowInfo  * info = gui_handle;
 
-  SEM_WAIT(info->playback_sem);
-  info->playback_state        = PAUSED;
-  info->playback_state_change = SET_PAUSE;
-  SEM_SIGNAL(info->playback_sem);
+  /*
+   * Signal the display thread then wait until it indicates successful
+   * shutdown by clearing the flag.
+   */
+  info->shutdown_gui = 1;
+  while (info->shutdown_gui) {
+    oggplay_millisleep(1);
+  }
+
+  SEM_CLOSE(info->display_resize_sem);
+  SEM_CLOSE(info->oggplay_replace_sem);
+  SEM_CLOSE(info->playback_sem);
+
+  shut_oggplay(info->oggplay_handle);
+  
+  free(info);
 }
 
 
 void
-start_gui(void *gui_handle) {
+gui_play(void *gui_handle) {
 
   PluginWindowInfo  * info = gui_handle;
 
@@ -672,8 +684,20 @@
 }
 
 
+void
+gui_pause(void *gui_handle) {
+
+  PluginWindowInfo  * info = gui_handle;
+
+  SEM_WAIT(info->playback_sem);
+  info->playback_state        = PAUSED;
+  info->playback_state_change = SET_PAUSE;
+  SEM_SIGNAL(info->playback_sem);
+}
+
+
 short
-get_gui_current_state(void *gui_handle) {
+gui_get_current_state(void *gui_handle) {
 
   PluginWindowInfo  * info = gui_handle;
 
@@ -692,25 +716,27 @@
 
 
 void
-shut_gui(void *gui_handle) {
+gui_set_volume(void *gui_handle, float volume) {
+//!todo
+}
 
-  PluginWindowInfo  * info = gui_handle;
 
-  /*
-   * Signal the display thread then wait until it indicates successful
-   * shutdown by clearing the flag.
-   */
-  info->shutdown_gui = 1;
-  while (info->shutdown_gui) {
-    oggplay_millisleep(1);
-  }
+float
+gui_get_volume(void *gui_handle) {
+//!todo
+  return 0.0f;
+}
 
-  SEM_CLOSE(info->display_resize_sem);
-  SEM_CLOSE(info->oggplay_replace_sem);
-  SEM_CLOSE(info->playback_sem);
 
-  shut_oggplay(info->oggplay_handle);
-  
-  free(info);
+long
+gui_get_window_width(void *gui_handle) {
+//!todo
+  return 0;
 }
 
+
+long
+gui_get_window_height(void *gui_handle) {
+//!todo
+  return 0;
+}

Modified: liboggplay/trunk/plugin/plugin_gui_win32.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_win32.c	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin_gui_win32.c	2007-06-22 07:57:43 UTC (rev 3026)
@@ -405,20 +405,20 @@
 }
 
 void 
-pause_gui(void *handle) {
+gui_pause(void *handle) {
   PluginWindowInfo  * info = (PluginWindowInfo *)handle;
   info->playback_state = PAUSED;
 }
 
 void 
-start_gui(void *handle) {
+gui_play(void *handle) {
   PluginWindowInfo  * info = (PluginWindowInfo *)handle;
   info->playback_state = PLAYING;
   SEM_SIGNAL(info->playback_sem);
 }
      
 short
-get_gui_current_state(void *handle) {
+gui_get_current_state(void *handle) {
   short state;
   PluginWindowInfo  * info = (PluginWindowInfo *)handle;
   switch (info->playback_state) {
@@ -438,3 +438,27 @@
   }
   return state;
 }
+
+void
+gui_set_volume(void *handle, float volume) {
+//!todo
+}
+
+float
+gui_get_volume(void *handle) {
+//!todo
+  return 0.0f;
+}
+
+long
+gui_get_window_width(void *handle) {
+//!todo
+  return 0;
+}
+
+long
+gui_get_window_height(void *handle) {
+//!todo
+  return 0;
+}
+

Modified: liboggplay/trunk/plugin/plugin_oggplay.c
===================================================================
--- liboggplay/trunk/plugin/plugin_oggplay.c	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin_oggplay.c	2007-06-22 07:57:43 UTC (rev 3026)
@@ -480,14 +480,3 @@
   return pointers->last_displayed_frame_time;
   
 }
-
-void 
-get_oggplay_curr_url(void *handle, char** url) {
-  PluginPointers *pointers = (PluginPointers *)handle;
-  (*url) = NULL;
-  if (pointers->location != NULL) {
-    size_t length = strlen(pointers->location) + 1;
-    (*url) = NPN_MemAlloc((uint32)length);
-    memcpy((*url), pointers->location, length);  
-  }
-}

Modified: liboggplay/trunk/plugin/plugin_oggplay.h
===================================================================
--- liboggplay/trunk/plugin/plugin_oggplay.h	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/plugin_oggplay.h	2007-06-22 07:57:43 UTC (rev 3026)
@@ -83,9 +83,6 @@
 long
 get_oggplay_play_position(void *handle);
 
-void
-get_oggplay_curr_url(void *handle, char** url);
-
 int get_audio_rate(void *ptrs);
 int get_audio_channels(void *ptrs);
 int get_video_rate(void *ptrs);

Modified: liboggplay/trunk/plugin/support/nsScriptablePeer.cpp
===================================================================
--- liboggplay/trunk/plugin/support/nsScriptablePeer.cpp	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/support/nsScriptablePeer.cpp	2007-06-22 07:57:43 UTC (rev 3026)
@@ -113,83 +113,137 @@
   mPlugin = plugin;
 }
 
-NS_IMETHODIMP nsScriptablePeer::Play() {
-  // play movie when paused
-  mPlugin->playMovie();
+
+// ============================
+// ! Javascript API functions !
+// ============================
+
+NS_IMETHODIMP nsScriptablePeer::GetVersionString(char **aVersionString)
+{
+  *aVersionString = NULL;
+  if (mPlugin)
+    mPlugin->getVersionString(aVersionString, apiVersionMajor, apiVersionMinor);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::GetCurrentState(PRInt16 *_retval) {    
-  *_retval = -1;
-  if (mPlugin)
-    *_retval = mPlugin->getCurrentState();
+NS_IMETHODIMP nsScriptablePeer::Play() {
+  mPlugin->play();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsScriptablePeer::Pause() {
-  // pause movie when playing  
   if (mPlugin)
-    mPlugin->pauseMovie();
+    mPlugin->pause();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsScriptablePeer::Restart() {
-  // restart at any time
   if (mPlugin)
-    mPlugin->restartMovie();
+    mPlugin->restart();
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::SetCurrentMovie(const char * URL) 
+NS_IMETHODIMP nsScriptablePeer::GetCurrentState(PRInt16 *_retval) {    
+  *_retval = -1;
+  if (mPlugin)
+    *_retval = mPlugin->getCurrentState();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::SetCurrentMovie(const char *URL) 
 {
   if (mPlugin)
     mPlugin->setCurrentMovie(URL);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::GetCurrentMovie(char ** URL) 
+NS_IMETHODIMP nsScriptablePeer::GetCurrentMovie(char **URL) 
 {  
+  *URL = NULL;
   if (mPlugin)
     *URL = mPlugin->getCurrentMovie();
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::GetPlayPosition(PRInt32 * rval)
+NS_IMETHODIMP nsScriptablePeer::SetPlayPosition(PRInt32 milliseconds, PRBool *_retval)
 {
-  long t = -1;
+  *_retval = FALSE;
   if (mPlugin)
-    t = mPlugin->getPlayPosition();
-  *rval = t;
+    *_retval = mPlugin->setPlayPosition(milliseconds);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::RegisterCallbackObject(nsILibOggCallback *cbObj)
+NS_IMETHODIMP nsScriptablePeer::GetPlayPosition(PRInt32 *_retval)
 {
+  *_retval = -1;
   if (mPlugin)
-    mPlugin->setCallbackObject(cbObj);
+    *_retval = mPlugin->getPlayPosition();
   return NS_OK;
 }
 
+NS_IMETHODIMP nsScriptablePeer::SetVolume(float volume) {
+  if (mPlugin)
+    mPlugin->setVolume(volume);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::GetVolume(float *volume) {
+  *volume = (float)0.0;
+  if (mPlugin)
+    *volume = mPlugin->getVolume();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::GetWindowWidth(PRInt32 *_retval) {
+  *_retval = -1;
+  if (mPlugin)
+    *_retval = mPlugin->getWindowWidth();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::GetWindowHeight(PRInt32 *_retval) {
+  *_retval = -1;
+  if (mPlugin)
+    *_retval = mPlugin->getWindowHeight();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::GetBufferedTime(PRInt32 *_retval) {
+  *_retval = -1;
+  if (mPlugin)
+    *_retval = mPlugin->getBufferedTime();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::GetMovieLength(PRInt32 *_retval) {
+  *_retval = -1;
+  if (mPlugin)
+    *_retval = mPlugin->getMovieLength();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsScriptablePeer::RetrieveAnnotations(char **xmlData) {
   *xmlData = NULL;
   if (mPlugin)
-    *xmlData = mPlugin->retrieveAllAnnotations();
+    *xmlData = mPlugin->retrieveAnnotations();
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::SetVolume(float volume) {
+NS_IMETHODIMP nsScriptablePeer::RegisterCMMLCallback(nsILibOggCallbackString *cbObj)
+{
   if (mPlugin)
-    mPlugin->setVolume(volume);
+    mPlugin->registerCMMLCallback(cbObj);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::GetVolume(float* volume) {
-  *volume = (float)0.0;
+NS_IMETHODIMP nsScriptablePeer::RegisterEndPlayCallback(nsILibOggCallbackNoArg *cbObj)
+{
   if (mPlugin)
-    *volume = mPlugin->getVolume();
+    mPlugin->registerEndPlayCallback(cbObj);
   return NS_OK;
 }
 
+/* //!todo
 NS_IMETHODIMP nsScriptablePeer::RegisterPlaylistCallback(const char *playlistCallback) {
   if (mPlugin)
     mPlugin->setPlaylistCallback(playlistCallback);
@@ -214,13 +268,4 @@
     mPlugin->appendMovie(url);
   return NS_OK;
 }
-
-//
-// the following method will be callable from JavaScript
-//
-NS_IMETHODIMP nsScriptablePeer::GetVersion(char * *aVersion)
-{
-  if (mPlugin)
-    mPlugin->getVersion(aVersion);
-  return NS_OK;
-}
+*/

Modified: liboggplay/trunk/plugin/test/test.html
===================================================================
--- liboggplay/trunk/plugin/test/test.html	2007-06-21 14:14:59 UTC (rev 3025)
+++ liboggplay/trunk/plugin/test/test.html	2007-06-22 07:57:43 UTC (rev 3026)
@@ -1,152 +1,252 @@
-<HTML>
-<HEAD>
-<TITLE>Liboggplay Plug-in Test Page</TITLE>
-</HEAD>
+<html>
+<head>
+<title>Liboggplay Plug-in Test Page</title>
+</head>
+
+<body onkeypress='KeyPressed(event)'>
+<center>
+
+<h1>Example Liboggplay Plug-in</h1>
+Hooray, it's a movie in a box!
+<br><br>
+
+<embed type="application/liboggplay" src="http://media.annodex.net/cmmlwiki/OSSForum-Intro.axv" width=320 height=240>
+<div id="cmml"></div>
+</embed>
+<br>
+
+<form name="api">
+<table>
+<tr><td width="160">
+<input type="button" value="Play" onclick='Play()'/><br>
+<input type="button" value="Pause" onclick='Pause()'/><br>
+<input type="button" value="Restart" onclick='Restart()'/><br>
+<input type="button" value="Get current state" onclick='GetCurrentState()'/><br>
+<input type="button" value="Get version string" onclick='GetVersionString()'/><br>
+</td><td width="180">
+<input type="button" value="Retrieve annotations" onclick='RetrieveAnnotations()'/><br>
+<input type="button" value="Get current movie" onclick='GetCurrentMovie()'/><br>
+<input type="button" value="Set play position" onclick='SetPlayPosition()'/><br>
+<input type="button" value="Get play position" onclick='GetPlayPosition()'/><br>
+</td><td>
+<input type="button" value="Set volume" onclick='SetVolume()'/><br>
+<input type="button" value="Get volume" onclick='GetVolume()'/><br>
+<input type="button" value="Get window size" onclick='GetWindowSize()'/><br>
+<input type="button" value="Get buffered time" onclick='GetBufferedTime()'/><br>
+<input type="button" value="Get movie length" onclick='GetMovieLength()'/><br>
+</td><td>
+</td></tr>
+<tr><td><br></td></tr>
+<tr valign="top"><td>
+<input type="button" value="Set movie:" onclick='SetCurrentMovie()'/><br>
+<label for="r1"><input id="r1" type="radio" name="movie" value="OSSForum-Intro" checked/>OSSForum-Intro</label><br>
+<label for="r2"><input id="r2" type="radio" name="movie" value="CCFilm"/>CCFilm</label><br>
+<label for="r3"><input id="r3" type="radio" name="movie" value="MarcinCanoe"/>MarcinCanoe</label><br>
+</td><td>
+<input type="button" value="Register:" onclick='RegisterCMMLCallback()'/>
+<label for="c1"><input id="c1" type="checkbox" name="cbCMML" checked/>CMML</label><br>
+<input type="button" value="Register:" onclick='RegisterEndPlayCallback()'/>
+<label for="c2"><input id="c2" type="checkbox" name="cbEndPlay" checked/>EndPlay</label><br>
+</td><td>
+<input type="button" value="Clear CMML" onclick='clearCMML()'/><br>
+</td></tr>
+</table>
+</form>
+
+<form name="io">
+Input<br>
+<input type="text" name="input" size="20">
+<br><br>
+Output<br>
+<textarea name="output" cols="60" rows="8"></textarea>
+</form>
+
 <script>
+var plugin = document.embeds[0];
+var api    = document.api;
+var input  = document.io.input;
+var output = document.io.output;
 
+function GetVersionString() {
+  output.value = "Version: " + plugin.getVersionString();
+}
 
-function KeyPressed(e) {
+function Play() {
+  plugin.play();
+}
 
-  var plugin = document.embeds[0];
-  if (String.fromCharCode(e.which) == " ")
-    alert(plugin.getPlayPosition());          
-  return true;
+function Pause() {
+  plugin.pause();
 }
 
-</script>
-<BODY onkeypress='KeyPressed(event)'>
+function Restart() {
+  plugin.restart();
+}
 
-<center>
-<h1> Example Liboggplay Plug-in </h1>
+function GetCurrentState() {
+  var states = ["paused", "playing", "finished"];
+  var s = plugin.getCurrentState();
+  output.value = "Current state: " + states[s] + " (" + s + ")";
+}
 
-Hooray, it's a movie in a box!
-</center>
+function SetCurrentMovie() {
+  for (i = 0; i < api.movie.length; i++) {
+    if (api.movie[i].checked) {
+      var s = "http://media.annodex.net/cmmlwiki/" + api.movie[i].value + ".axv";
+      plugin.setCurrentMovie(s);
+      output.value = "Current movie set to " + s;
+      return;
+    }
+  }
+}
 
-<br><br>
+function GetCurrentMovie() {
+  output.value = "Current movie: " + plugin.getCurrentMovie();
+}
 
-<center>
+function SetPlayPosition() {
+  var v = +input.value;
+  if (isNaN(v)) {
+    output.value = "Enter a numeric value";
+  } else {
+    plugin.setPlayPosition(v);
+    output.value = "Play position set to " + v + " ms";
+  }
+}
 
-<embed type="application/liboggplay" src="http://media.annodex.net/cmmlwiki/CCFilm.axv" width=640 height=480>
+function GetPlayPosition() {
+  output.value = "Play position: " + plugin.getPlayPosition() + " ms";
+}
 
-<div id="cmml"></div>
+function SetVolume() {
+  var v = +input.value;
+  if (isNaN(v) || v < 0 || v > 1) {
+    output.value = "Enter a value from 0 to 1";
+  } else {
+    plugin.setVolume(v);
+    output.value = "Volume set to " + v;
+  }
+}
 
-<!--
-"http://media.annodex.net/cmmlwiki/SFD2005-Trailer.axv" width=240 height=160
-<param name="movie" value="FUBAR"/>
--->
-</embed>
+function GetVolume() {
+  output.value = "Volume: " + plugin.getVolume();
+}
 
-<br>
+function GetWindowSize() {
+  output.value = "Window size: " +
+    plugin.getWindowWidth() + " x " + plugin.getWindowHeight();
+}
 
-<script>
-var embed = document.embeds[0];
+function GetBufferedTime() {
+  output.value = "Buffered time: " + plugin.getBufferedTime() + " ms";
+}
 
-function PlayMovie() {
-    embed.play();
-    return true;
+function GetMovieLength() {
+  output.value = "Movie length: " + plugin.getMovieLength() + " ms";
 }
 
-function PauseMovie() {
-    embed.pause();
-    return true;
+function RetrieveAnnotations() {
+  output.value = "Annotations:\n" + plugin.retrieveAnnotations();
 }
 
-function RestartMovie() {
-    embed.restart();
-    return true;
+function RegisterCMMLCallback() {
+  if (api.cbCMML.checked) {
+    plugin.registerCMMLCallback(
+      {
+        call : function(s) {showCMML(s);}
+      }
+    );
+    output.value = "Registered CMML callback";
+  } else {
+    plugin.registerCMMLCallback(null);
+    output.value = "Unregistered CMML callback";
+  }
 }
 
-function ChangeMovie(url) {
-    embed.setCurrentMovie(url);
+function RegisterEndPlayCallback() {
+  if (api.cbEndPlay.checked) {
+    plugin.registerEndPlayCallback(
+      {
+        call : function() {endPlay();}
+      }
+    );
+    output.value = "Registered EndPlay callback";
+  } else {
+    plugin.registerEndPlayCallback(null);
+    output.value = "Unregistered EndPlay callback";
+  }
 }
 
 function showCMML(data) {
-    /* clear the old CMML clip */
-    element = document.getElementById("cmml");
-    while (element.firstChild != null) {
-      element.removeChild(element.firstChild);
-    }
+  /* clear the old CMML clip */
+  var element = document.getElementById("cmml");
+  while (element.firstChild != null) {
+    element.removeChild(element.firstChild);
+  }
 
-    /* parse the data as XML */
-    document.implementation.createDocument("", "clip", null);
-    xmlDoc = (new DOMParser()).parseFromString(data, "application/xml");
+  /* parse the data as XML */
+  document.implementation.createDocument("", "clip", null);
+  var xmlDoc = (new DOMParser()).parseFromString(data, "application/xml");
 
-    /* extract the description */
-    descs = xmlDoc.getElementsByTagName("desc");
-    if (descs.length > 0)
-    {
-      desc = descs.item(0);
-      desc.normalize();
-      newpar = document.createElement("p");
-      newpar.appendChild(desc.cloneNode(true));
-      element.appendChild(newpar);
-    }
+  /* extract the description */
+  var descs = xmlDoc.getElementsByTagName("desc");
+  if (descs.length > 0) {
+    var desc = descs.item(0);
+    desc.normalize();
+    var newpar = document.createElement("p");
+    newpar.appendChild(desc.cloneNode(true));
+    element.appendChild(newpar);
+  }
 
-    /* extract the link tag and convert it to an HTML href */
-    links = xmlDoc.getElementsByTagName("a");
-    if (links.length > 0)
-    {
-      link = links.item(0);
-      link.normalize();
-      newlink = document.createElement("a");
-      newlink.setAttribute("href", link.getAttribute("href"));
-      newlink.appendChild(link.firstChild.cloneNode(true));
-      newpar = document.createElement("p");
-      newpar.appendChild(newlink);
-      element.appendChild(newpar);
-    }
+  /* extract the link tag and convert it to an HTML href */
+  var links = xmlDoc.getElementsByTagName("a");
+  if (links.length > 0) {
+    var link = links.item(0);
+    link.normalize();
+    var newlink = document.createElement("a");
+    newlink.setAttribute("href", link.getAttribute("href"));
+    newlink.appendChild(link.firstChild.cloneNode(true));
+    var newpar = document.createElement("p");
+    newpar.appendChild(newlink);
+    element.appendChild(newpar);
+  }
+}
 
-    return true;
+function endPlay() {
+  alert("End of play callback!");
 }
 
-function setCMMLCallback() {
-    embed.registerCallbackObject(
-                    {
-                      cmmlCallback : function(s) {showCMML(s);}
-                    } 
-                  );
-    return true;
+function clearCMML() {
+  var element = document.getElementById("cmml");
+  while (element.firstChild != null) {
+    element.removeChild(element.firstChild);
+  }
 }
 
+function KeyPressed(e) {
+  if (String.fromCharCode(e.which) == " ")
+    alert(plugin.getPlayPosition());
+
+  if (String.fromCharCode(e.which) == "p") {
+    var state = plugin.getCurrentState();
+    switch (state) {
+      case 0: //PAUSED
+        plugin.play();
+        break;
+      case 1: //PLAYING
+        plugin.pause();
+        break;
+      case 2: //FINISHED
+        plugin.restart();
+        break;
+      default:
+        alert("getCurrentState returned " + state);
+        break;
+    }
+  }
+}
 </script>
-<form name="navigation">
-<table>
-<tr>
-<td align="right">
-<input type="button" value="Play Me!" onclick='PlayMovie()'>
-</td>
-<td align="left">
-<input type="button" value="Dont Play Me!" onclick='PauseMovie()'>
-</td>
-<td align="left">
-<input type="button" value="Restart Me!" onclick='RestartMovie()'>
-</td>
-</tr>
-</table>
-</form>
 
-<br>
-<form name="navigation">
-<table>
-<tr>
-<td align="right">
-<input type="button" value="Change Dat Funky Movah!" onclick='ChangeMovie("http://media.annodex.net/cmmlwiki/OSSForum-Intro.axv")'>
-</td>
-<td align="left">
-<input type="button" value="Roll back!" onclick='ChangeMovie("http://media.annodex.net/cmmlwiki/CCFilm.axv")'>
-</td>
-</tr>
-<tr>
-<td align="center" colspan="2">
-<input type="button" value="Receive CMML Callbacks" onclick='setCMMLCallback()'>
-</td>
-</tr>
-</table>
-</form>
-
-Press space to retrieve the current movie time in milliseconds.
-
 </center>
-
-</BODY>
-</HTML>
+</body>
+</html>



More information about the commits mailing list