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

tahn at svn.annodex.net tahn at svn.annodex.net
Thu Jun 28 05:29:38 PDT 2007


Author: tahn
Date: 2007-06-28 05:29:38 -0700 (Thu, 28 Jun 2007)
New Revision: 3118

Removed:
   liboggplay/trunk/plugin/plugin_playlist.c
   liboggplay/trunk/plugin/plugin_playlist.h
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_c.h
   liboggplay/trunk/plugin/plugin_gui_linux.c
   liboggplay/trunk/plugin/plugin_gui_mac.c
   liboggplay/trunk/plugin/support/nsScriptablePeer.cpp
Log:
Implemented playlists.


Modified: liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj
===================================================================
--- liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/mac/liboggplay.xcodeproj/project.pbxproj	2007-06-28 12:29:38 UTC (rev 3118)
@@ -8,8 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		2C31AFE40BF455CB002C55BF /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C31AFE30BF455CB002C55BF /* Carbon.framework */; };
-		2C81E4140C1E119F008364B7 /* plugin_playlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C81E4120C1E119F008364B7 /* plugin_playlist.h */; };
-		2C81E4150C1E119F008364B7 /* plugin_playlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 2C81E4130C1E119F008364B7 /* plugin_playlist.c */; };
+		2C613F4F0C33950A00F9298C /* plugin_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C613F4E0C33950A00F9298C /* plugin_c.h */; };
 		2C83A7A10BE86E72004C14F4 /* liboggplay.r in Rez */ = {isa = PBXBuildFile; fileRef = 2C83A7110BE85E80004C14F4 /* liboggplay.r */; };
 		2C83A8620BE96764004C14F4 /* np_mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2C83A8610BE96764004C14F4 /* np_mac.cpp */; };
 		2C83A8AB0BE9698F004C14F4 /* npp_gate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2CD58C990BD33B65001D751D /* npp_gate.cpp */; };
@@ -56,8 +55,7 @@
 
 /* Begin PBXFileReference section */
 		2C31AFE30BF455CB002C55BF /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
-		2C81E4120C1E119F008364B7 /* plugin_playlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = plugin_playlist.h; path = ../plugin_playlist.h; sourceTree = SOURCE_ROOT; };
-		2C81E4130C1E119F008364B7 /* plugin_playlist.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = plugin_playlist.c; path = ../plugin_playlist.c; sourceTree = SOURCE_ROOT; };
+		2C613F4E0C33950A00F9298C /* plugin_c.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = plugin_c.h; path = ../plugin_c.h; sourceTree = SOURCE_ROOT; };
 		2C83A7110BE85E80004C14F4 /* liboggplay.r */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.rez; path = liboggplay.r; sourceTree = "<group>"; };
 		2C83A8610BE96764004C14F4 /* np_mac.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = np_mac.cpp; sourceTree = "<group>"; };
 		2C83AB270BE9C6EB004C14F4 /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = /System/Library/Frameworks/AGL.framework; sourceTree = "<absolute>"; };
@@ -176,6 +174,7 @@
 			children = (
 				2CD58C4E0BD319C3001D751D /* plugin.cpp */,
 				2CD58C4F0BD319C3001D751D /* plugin.h */,
+				2C613F4E0C33950A00F9298C /* plugin_c.h */,
 				2CD58C4C0BD319C3001D751D /* plugin_oggplay.c */,
 				2CD58C4D0BD319C3001D751D /* plugin_oggplay.h */,
 				2CD58C4A0BD319C3001D751D /* plugin_gui_mac.c */,
@@ -184,8 +183,6 @@
 				2CD58C4B0BD319C3001D751D /* plugin_gui.h */,
 				2CF2FD420C191F8A0074A9C3 /* plugin_tools.c */,
 				2CF2FD430C191F8A0074A9C3 /* plugin_tools.h */,
-				2C81E4130C1E119F008364B7 /* plugin_playlist.c */,
-				2C81E4120C1E119F008364B7 /* plugin_playlist.h */,
 				2CA761D40BF978E10008A3B7 /* std_semaphore.h */,
 				2C9F53E10C2A5727007365C0 /* nsILibOggPlugin.idl */,
 				2CF2FD540C191FD70074A9C3 /* audio */,
@@ -307,7 +304,7 @@
 				2CA761D50BF978E10008A3B7 /* std_semaphore.h in Headers */,
 				2CD6AD870C0D355B007E42D5 /* sydney_audio_new.h in Headers */,
 				2CF2FD450C191F8A0074A9C3 /* plugin_tools.h in Headers */,
-				2C81E4140C1E119F008364B7 /* plugin_playlist.h in Headers */,
+				2C613F4F0C33950A00F9298C /* plugin_c.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -420,7 +417,6 @@
 				2C83A8AB0BE9698F004C14F4 /* npp_gate.cpp in Sources */,
 				2C96D1330C0666340015B6AC /* sydney_audio_mac.c in Sources */,
 				2CF2FD440C191F8A0074A9C3 /* plugin_tools.c in Sources */,
-				2C81E4150C1E119F008364B7 /* plugin_playlist.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

Modified: liboggplay/trunk/plugin/nsILibOggPlugin.idl
===================================================================
--- liboggplay/trunk/plugin/nsILibOggPlugin.idl	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/nsILibOggPlugin.idl	2007-06-28 12:29:38 UTC (rev 3118)
@@ -53,8 +53,8 @@
 [scriptable, uuid(482e1890-1fe5-11d5-9cf8-0260b0fbd8ac)]
 interface nsILibOggPlugin : nsISupports {
 
-  const short apiVersionMajor = 0;
-  const short apiVersionMinor = 1;
+  const short apiVersionMajor = 1;
+  const short apiVersionMinor = 0;
 
   string getVersionString();
 
@@ -82,13 +82,14 @@
   void unfreezePlaylistProgression();
   long getPlaylistLength();
   long getCurrentPlaylistPosition();
+  boolean playMovieAt(in long position);
+  boolean playlistNext();
+  boolean playlistPrev();
   string getMovieAt(in long position);
   boolean setMovieAt(in long position, in string url);
   void appendMovie(in string url);
   boolean insertMovieBefore(in long position, in string url);
   boolean removeMovieAt(in long position);
-  long getPlayPositionWithinMovie();
-  boolean setPlayPositionWithinMovie(in long milliseconds);
   string retrieveAnnotationsAt(in long position);
   long getMovieLengthAt(in long position);
   void registerPlaylistCallback(in nsILibOggCallbackNoArg callback);

Modified: liboggplay/trunk/plugin/plugin.cpp
===================================================================
--- liboggplay/trunk/plugin/plugin.cpp	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin.cpp	2007-06-28 12:29:38 UTC (rev 3118)
@@ -228,30 +228,28 @@
   mScriptablePeer(NULL),
   mOggHandle(NULL),
   mGuiHandle(NULL),
-  mSource(NULL),
   mServiceManager(NULL),
+  mProxyHost(NULL),
+  mProxyPort(80),
+  mPlaylistPos(0),
+  mReachedEndOfMovie(FALSE),
   mCmmlCallback(NULL),
-  mEndPlayCallback(NULL)
+  mEndPlayCallback(NULL),
+  mPlaylistCallback(NULL)
 #if defined(XP_MACOSX)
   ,
   mOutputCleared(FALSE)
 #elif defined (XP_WIN)
   ,
   mPollingStarted(false),
-  mPollingPeriod(POLLING_PERIOD),
-  mProxyHost(NULL),
-  mProxyPort(80)
+  mPollingPeriod(POLLING_PERIOD)
 #endif
 {
   nsISupports             * sm    = NULL;
   nsIPrefService          * prefs = NULL;
   nsIPrefBranch           * branch = NULL;
 
-  mString[0] = '\0';
-  setSource(source);
-  SEM_CREATE(mCmmlSem, 1);
-  SEM_CREATE(mEndPlaySem, 1);
-
+  // Jump through some hoops to get the proxy info
   NPN_GetValue(NULL, NPNVserviceManager, &sm);
 
   if (sm) {
@@ -264,7 +262,6 @@
     mServiceManager->GetServiceByContractID(
         "@mozilla.org/preferences-service;1",
         NS_GET_IID(nsIPrefService), (void **)&prefs);
-
   }
   
   if (prefs != NULL) {
@@ -283,10 +280,19 @@
     }
   }
 
+  // Initialise the remaining members, and create our playlist of 1
+  SEM_CREATE(mCrossThreadSem, 1);
+  appendMovie(source);
 }
 
 nsPluginInstance::~nsPluginInstance()
 {
+#if defined(XP_WIN)
+  if (mPollingStarted == true) {
+    KillTimer((HWND)mWindow->window, IDT_CALLBACK_TIMER);     
+  }
+#endif
+
   // mScriptablePeer may be also held by the browser 
   // so releasing it here does not guarantee that it is over
   // we should take precaution in case it will be called later
@@ -295,30 +301,23 @@
     mScriptablePeer->SetInstance(NULL);
     NS_IF_RELEASE(mScriptablePeer);
   }
-  if (mSource != NULL) {
-    free(mSource);
-  }
   if (mCmmlCallback != NULL) {
     NS_RELEASE(mCmmlCallback);
   }
   if (mEndPlayCallback != NULL) {
     NS_RELEASE(mEndPlayCallback);
   }
+  if (mPlaylistCallback != NULL) {
+    NS_RELEASE(mPlaylistCallback);
+  }
 
-#if defined(XP_WIN)
-  if (this->mPollingStarted == true) {
-    KillTimer((HWND)mWindow->window, IDT_CALLBACK_TIMER);     
+  for (unsigned int i = 0; i < mPlaylist.size(); i++) {
+    free(mPlaylist[i]);
   }
-#endif
-
-  SEM_CLOSE(mCmmlSem);
-  SEM_CLOSE(mEndPlaySem);
-#if defined(XP_MACOSX) || defined(XP_WIN)
   clearCmmlStrings();
-#endif
+  SEM_CLOSE(mCrossThreadSem);
 }
 
-#if defined(XP_MACOSX) || defined (XP_WIN)
 void
 nsPluginInstance::clearCmmlStrings() {
   for (unsigned int i = 0; i < mCmmlStrings.size(); i++) {
@@ -326,26 +325,7 @@
   }
   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)
 {  
@@ -376,7 +356,7 @@
 NPError
 nsPluginInstance::NewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
 {
-  printf("URL %s for this Mime-Type %s\n", (char*)type, stream->url);
+  //printf("URL %s for this Mime-Type %s\n", (char*)type, stream->url);
   return NPERR_NO_ERROR;
 }
 
@@ -387,10 +367,10 @@
   // When the browser window is resized, we usually receive one or more calls
   // to SetWindow, often with a zero-sized clip, followed by an update event
   // in HandleEvent with the correct clip. Therefore, we want to ignore the
-  // SetWindow calls and only update the clip size in the event handler.
+  // SetWindow calls and only update the clip size in HandleEvent.
   // -- MAC OS X SPECIFIC -
   if (mWindowInitialised == FALSE) {    
-    if (getSource() == NULL) {
+    if (curMovie() == NULL) {
       return NPERR_NO_ERROR;
     }
     
@@ -398,7 +378,7 @@
     // 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(getSource(), mProxyHost, mProxyPort);
+    mOggHandle = initialise_oggplay(curMovie(), mProxyHost, mProxyPort);
     mGuiHandle = initialise_gui(this, aWindow, mOggHandle);
     mWindow = aWindow;
     mWindowInitialised = TRUE;
@@ -429,8 +409,10 @@
   // which are the null event. While this is not exactly efficient, it does
   // turn out to be useful for a couple of things.
   //
-  // First, to send the cmml strings collected by onCMMLData to the browser..  
-  executeCmmlCallback();
+  // First, to process any events triggered from the display thread..
+  SEM_WAIT(mCrossThreadSem);
+  processCrossThreadCalls();
+  SEM_SIGNAL(mCrossThreadSem);
 
   // ..and second, to handle hiding our output when the user changes tabs or
   // scrolls the media off the page.
@@ -469,31 +451,13 @@
   nsPluginInstance * plugin = NULL;
   
   plugin = (nsPluginInstance *)GetWindowLongPtr(hWnd, GWL_USERDATA);  
-  plugin->executeCmmlCallback();
+  SEM_WAIT(mCrossThreadSem);
+  plugin->processCrossThreadCalls();
+  SEM_SIGNAL(mCrossThreadSem);
 }
 #endif
 
-#if defined (XP_MACOSX) || defined(XP_WIN)
-void 
-nsPluginInstance::executeCmmlCallback() {
-  // 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++) {
-        //printf("Sending CMML to Javascript: %s\n", mCmmlStrings[i]);
-        mCmmlCallback->Call(mCmmlStrings[i]);
-      }
-      clearCmmlStrings();
-    }    
-    SEM_SIGNAL(mCmmlSem);
-  }  
-}
-#endif
 
-
 // ==============================
 // ! Scriptability related code !
 // ==============================
@@ -568,6 +532,20 @@
 
 ////////////////////////////////////////
 //
+// Private helper functions
+//
+char *
+nsPluginInstance::curMovie() const {
+  return mPlaylist[mPlaylistPos];
+}
+
+bool
+nsPluginInstance::playlistIndexOk(long index) const {
+  return (index >= 0 && index < (long)mPlaylist.size());
+}
+
+////////////////////////////////////////
+//
 // Javascript API - standard playback
 //
 void
@@ -595,8 +573,8 @@
 
 void
 nsPluginInstance::restart() {
-  if (getSource() != NULL) {
-    mOggHandle = initialise_oggplay(getSource(), mProxyHost, mProxyPort);
+  if (curMovie() != NULL) {
+    mOggHandle = initialise_oggplay(curMovie(), mProxyHost, mProxyPort);
     update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
     gui_play(mGuiHandle);
   }
@@ -609,21 +587,17 @@
 
 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(), mProxyHost, mProxyPort);
-  update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
+  setMovieAt(mPlaylistPos, url);
 }
 
 char *
 nsPluginInstance::getCurrentMovie() {
   char *url = NULL;
 
-  if (getSource() != NULL) {
-    url = (char *)NPN_MemAlloc(strlen(getSource()) + 1);
+  if (curMovie() != NULL) {
+    url = (char *)NPN_MemAlloc(strlen(curMovie()) + 1);
     if (url != NULL) {
-      strcpy(url, getSource());
+      strcpy(url, curMovie());
     }
   }
   return url;
@@ -671,14 +645,7 @@
 
 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;
+  return retrieveAnnotationsAt(mPlaylistPos);
 }
 
 ////////////////////////////////////////
@@ -697,107 +664,149 @@
 
 long
 nsPluginInstance::getPlaylistLength() {
-//!todo
-  return 0;
+  return mPlaylist.size();
 }
 
 long
 nsPluginInstance::getCurrentPlaylistPosition() {
-//!todo
-  return 0;
+  return mPlaylistPos;
 }
 
+bool
+nsPluginInstance::playMovieAt(long position) {
+  if (!playlistIndexOk(position)) {
+    return FALSE;
+  }
+  mPlaylistPos = position;
+  restart();
+  return TRUE;
+}
+
+bool
+nsPluginInstance::playlistNext() {
+  if (mPlaylistPos == (int)mPlaylist.size() - 1) {
+    return FALSE;
+  }
+  mPlaylistPos++;
+  restart();
+  return TRUE;
+}
+
+bool
+nsPluginInstance::playlistPrev() {
+  if (mPlaylistPos == 0) {
+    return FALSE;
+  }
+  mPlaylistPos--;
+  restart();
+  return TRUE;
+}
+
 char *
 nsPluginInstance::getMovieAt(long position) {
-//!todo - remove bad pun
-  char *movie = NULL;
-
-  movie = (char *)NPN_MemAlloc(100);
+  if (!playlistIndexOk(position)) {
+    return NULL;
+  }
+  char *movie = (char *)NPN_MemAlloc(strlen(mPlaylist[position]) + 1);
   if (movie != NULL) {
-    strcpy(movie, "nothing to see here, movie along");
+    strcpy(movie, mPlaylist[position]);
   }
   return movie;
 }
 
 bool
 nsPluginInstance::setMovieAt(long position, const char *url) {
-//!todo
+  if (!playlistIndexOk(position)) {
+    return FALSE;
+  }
+  free(mPlaylist[position]);
+  mPlaylist[position] = strdup(url);
+  if (position == mPlaylistPos) {
+    // We can just discard our reference to the old oggplay handle; the gui
+    // code will destroy it before swapping over to the new one.
+    mOggHandle = initialise_oggplay(curMovie(), mProxyHost, mProxyPort);
+    update_gui_with_new_oggplay(mGuiHandle, mOggHandle);
+  }
   return TRUE;
 }
 
 void
 nsPluginInstance::appendMovie(const char *url) {
-//!todo
-  return;
+  mPlaylist.push_back(strdup(url));
 }
 
 bool
 nsPluginInstance::insertMovieBefore(long position, const char *url) {
-//!todo
+  if (!playlistIndexOk(position)) {
+    return FALSE;
+  }
+  mPlaylist.insert(mPlaylist.begin() + position, strdup(url));
+  if (position <= mPlaylistPos) {
+    mPlaylistPos++;
+  }
   return TRUE;
 }
 
 bool
 nsPluginInstance::removeMovieAt(long position) {
-//!todo
+  if (!playlistIndexOk(position) || mPlaylist.size() <= 1) {
+    return FALSE;
+  }
+  free(mPlaylist[position]);
+  mPlaylist.erase(mPlaylist.begin() + position);
+  // remember that mPlaylist.size() has been decremented now!
+  if ((position < mPlaylistPos && mPlaylistPos > 0) ||
+      (mPlaylistPos == (int)mPlaylist.size())) {
+    mPlaylistPos--;
+  }
+  //!todo - if this is current movie, need to progress to next...
   return TRUE;
 }
 
-long
-nsPluginInstance::getPlayPositionWithinMovie() {
-//!todo
-  return 0;
-}
-
-bool
-nsPluginInstance::setPlayPositionWithinMovie(long milliseconds) {
-//!todo
-  return TRUE;
-}
-
 char *
 nsPluginInstance::retrieveAnnotationsAt(long position) {
-//!todo
-  char *annotations = NULL;
-
-  annotations = (char *)NPN_MemAlloc(100);
+  if (!playlistIndexOk(position)) {
+    return NULL;
+  }
+  //!todo
+  char *annotations = (char *)NPN_MemAlloc(100);
   if (annotations != NULL) {
-    strcpy(annotations, "annotations ftw");
+    sprintf(annotations, "annotations for %ld ftw", position);
   }
   return annotations;
 }
 
 long
 nsPluginInstance::getMovieLengthAt(long position) {
-//!todo
-  return 0;
+  if (!playlistIndexOk(position)) {
+    return -1;
+  }
+  //!todo
+  return -1;
 }
 
-////////////////////////////////////////
+///////////////////////////////////////////
 //
-// Javascript API - callback handling
+// Javascript API - callback registration
 //
 void
 nsPluginInstance::registerCMMLCallback(nsILibOggCallbackString *cbObj) {
-  SEM_WAIT(mCmmlSem);
+  SEM_WAIT(mCrossThreadSem);
   if (mCmmlCallback != NULL) {
     NS_RELEASE(mCmmlCallback);
   }
   mCmmlCallback = cbObj;
   if (mCmmlCallback != NULL) {
     NS_ADDREF(mCmmlCallback);
-  }
-#if defined(XP_MACOSX) || defined(XP_WIN)
-  if (mCmmlCallback == NULL) {
+  } else {
     clearCmmlStrings();
   }
-#endif
-  SEM_SIGNAL(mCmmlSem);
+  SEM_SIGNAL(mCrossThreadSem);
 }
 
 void
 nsPluginInstance::registerEndPlayCallback(nsILibOggCallbackNoArg *cbObj) {
-  SEM_WAIT(mEndPlaySem);
+  SEM_WAIT(mCrossThreadSem);
   if (mEndPlayCallback != NULL) {
     NS_RELEASE(mEndPlayCallback);
   }
@@ -805,12 +814,12 @@
   if (mEndPlayCallback != NULL) {
     NS_ADDREF(mEndPlayCallback);
   }
-  SEM_SIGNAL(mEndPlaySem);
+  SEM_SIGNAL(mCrossThreadSem);
 }
 
 void
 nsPluginInstance::registerPlaylistCallback(nsILibOggCallbackNoArg *cbObj) {
-  SEM_WAIT(mPlaylistSem);
+  SEM_WAIT(mCrossThreadSem);
   if (mPlaylistCallback != NULL) {
     NS_RELEASE(mPlaylistCallback);
   }
@@ -818,73 +827,106 @@
   if (mPlaylistCallback != NULL) {
     NS_ADDREF(mPlaylistCallback);
   }
-  SEM_SIGNAL(mPlaylistSem);
+  SEM_SIGNAL(mCrossThreadSem);
 }
 
+////////////////////////////////////////
+//
+// Cross-thread event handling
+//
+// Mac and Windows don't like cross-thread calls between the GUI thread and
+// the main plugin/browser thread, so the callbacks are triggered by the
+// display thread but must be invoked by the main thread. We do this with a
+// deferred invocation model:
+//  - The callback notification functions are executed by the display thread,
+//    and simply store their data in the plugin class.
+//  - processCrossThreadCalls is executed at regular intervals by the main
+//    thread, and invokes the Javascript callback objects when needed.
+//
+// On the Mac, the "regular intervals" bit is achieved by piggybacking on the
+// constant stream of browser-originated calls to HandleEvent. On Windows we
+// use SetTimer to provide an artificial heartbeat.
+//
+// Linux doesn't have a problem with cross-thread calls, so we can execute
+// processCrossThreadCalls directly from the callback notification functions.
+
+// -- Callback notification functions --
+// These are executed in the display thread.
 void
 nsPluginInstance::onCMMLData(char **cmml_data, int cmml_size) {
-  SEM_WAIT(mCmmlSem);
+  SEM_WAIT(mCrossThreadSem);
   if (mCmmlCallback != NULL) {
-#if defined(XP_MACOSX) || defined(XP_WIN)   
-    // The Mac and Windows don't like cross-thread calls between the GUI thread
-    // and the plugin/browser thread. 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.
-    // [MACOSX]
-    //   On Mac we piggyback on the browser-originated calls to HandleEvent
-    //    to send the strings to the browser. 
-    // [Win32]
-    //   On Windows we use a timer introduced to provide an artificial
-    //   heartbeat similar to ongoing event processing on Mac.
-    // We need to make copies of the strings because the oggplay frame can be
-    // freed before we get in to HandleEvent (Mac) or timer handler funtion
-    // (Win32).
-    for (int i = 0; i < cmml_size; i++) {      
+    for (int i = 0; i < cmml_size; i++) {
+      // We need to make copies of the strings because the oggplay frame in
+      // which they're stored can be freed before processCrossThreadCalls
+      // passes them to the browser.
       mCmmlStrings.push_back(strdup(cmml_data[i]));
     }
-#else
-    for (int i = 0; i < cmml_size; i++) {
-      mCmmlCallback->Call(cmml_data[i]);
-    }
+#if defined(XP_UX)
+    processCrossThreadCalls();
 #endif
   }
-  SEM_SIGNAL(mCmmlSem);
+  SEM_SIGNAL(mCrossThreadSem);
 }
 
 void
-nsPluginInstance::onEndOfPlay() {
-  SEM_WAIT(mEndPlaySem);
-  if (mEndPlayCallback != NULL) {
-    mEndPlayCallback->Call();
-  }
-  SEM_SIGNAL(mEndPlaySem);
+nsPluginInstance::onEndOfMovie() {
+  SEM_WAIT(mCrossThreadSem);
+  mReachedEndOfMovie = TRUE;
+#if defined(XP_UX)
+  processCrossThreadCalls();
+#endif
+  SEM_SIGNAL(mCrossThreadSem);
 }
 
-void
-nsPluginInstance::onPlaylistTrackChanged() {
-  SEM_WAIT(mPlaylistSem);
-  if (mPlaylistCallback != NULL) {
-    mPlaylistCallback->Call();
-  }
-  SEM_SIGNAL(mPlaylistSem);
-}
-
 // C hooks for the callback notification functions
 extern "C" {
 void
 onCMMLData(nsPluginInstance *i, char **cmml_data, int cmml_size) {  
-  i->onCMMLData(cmml_data, cmml_size);  
+  i->onCMMLData(cmml_data, cmml_size);
 }
 
 void
-onEndOfPlay(nsPluginInstance *i) {
-  i->onEndOfPlay();
+onEndOfMovie(nsPluginInstance *i) {
+  i->onEndOfMovie();
 }
+} // extern "C"
 
+
+// -- Deferred callback processing --
+// Every call to this method must protected by mCrossThreadSem.
 void
-onPlaylistTrackChanged(nsPluginInstance *i) {
-  i->onPlaylistTrackChanged();
+nsPluginInstance::processCrossThreadCalls() {
+
+  // Send any cmml strings collected by onCMMLData.
+  if (mCmmlStrings.size() > 0) {
+    if (mCmmlCallback != NULL) {
+      for (unsigned int i = 0; i < mCmmlStrings.size(); i++) {
+        mCmmlCallback->Call(mCmmlStrings[i]);
+      }
+    }
+    clearCmmlStrings();
+  }
+
+  // End-of-movie handling.
+  if (mReachedEndOfMovie) {
+    mReachedEndOfMovie = FALSE;
+
+    // If we've reached the end of playlist, just throw the end-play callback
+    // and we're done. Otherwise, throw the playlist callback and advance to
+    // the next movie.
+    if (mPlaylistPos == (int)mPlaylist.size() - 1) {
+      if (mEndPlayCallback != NULL) {
+        mEndPlayCallback->Call();
+      }
+    } else {
+      if (mPlaylistCallback != NULL) {
+        mPlaylistCallback->Call();
+      }
+      mPlaylistPos++;
+      restart();
+    }
+  }
+
 }
-} // extern "C"
 
-

Modified: liboggplay/trunk/plugin/plugin.h
===================================================================
--- liboggplay/trunk/plugin/plugin.h	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin.h	2007-06-28 12:29:38 UTC (rev 3118)
@@ -73,11 +73,6 @@
   NPError NewStream(NPMIMEType type, NPStream* stream,  
 			NPBool seekable, uint16* stype);    
 
-// FIX ME: this method seem not to be implemented at all!!!
-#if defined(XP_UX)
-  void redraw(Widget widget, XtPointer call_data);
-#endif
-
 #if defined (XP_MACOSX) || defined(XP_WIN)
   // wrapper method (for MACOSX and Win32 only)   
   // this is used only in Win32 and MACOSX version of the plugin
@@ -111,13 +106,14 @@
   void    unfreezePlaylistProgression();
   long    getPlaylistLength();
   long    getCurrentPlaylistPosition();
+  bool    playMovieAt(long position);
+  bool    playlistNext();
+  bool    playlistPrev();
   char  * getMovieAt(long position);
   bool    setMovieAt(long position, const char *url);
   void    appendMovie(const char *url);
   bool    insertMovieBefore(long position, const char *url);
   bool    removeMovieAt(long position);
-  long    getPlayPositionWithinMovie();
-  bool    setPlayPositionWithinMovie(long milliseconds);
   char  * retrieveAnnotationsAt(long position);
   long    getMovieLengthAt(long position);
 
@@ -125,47 +121,39 @@
   void    registerEndPlayCallback(nsILibOggCallbackNoArg *cbObj);
   void    registerPlaylistCallback(nsILibOggCallbackNoArg *cbObj);
   void    onCMMLData(char **cmml_data, int cmml_size);
-  void    onEndOfPlay();
-  void    onPlaylistTrackChanged();
+  void    onEndOfMovie();
 
 private:
-  void    setSource(const char *source);
-  char  * getSource();
+  char  * curMovie() const;
+  bool    playlistIndexOk(long index) const;
+  void    clearCmmlStrings();
+  void    processCrossThreadCalls();
 
-  NPP                 mInstance;
-  NPBool              mPluginInitialised;
-  NPBool              mWindowInitialised;
-  NPWindow          * mWindow;
-  nsScriptablePeer  * mScriptablePeer;
-  void              * mOggHandle;
-  void              * mGuiHandle;
-  char              * mSource;
-  nsIServiceManager * mServiceManager;
-
+  NPP                         mInstance;
+  NPBool                      mPluginInitialised;
+  NPBool                      mWindowInitialised;
+  NPWindow                  * mWindow;
+  nsScriptablePeer          * mScriptablePeer;
+  void                      * mOggHandle;
+  void                      * mGuiHandle;
+  nsIServiceManager         * mServiceManager;
+  char                      * mProxyHost;
+  int                         mProxyPort;
+  std::vector<char*>          mPlaylist;
+  int                         mPlaylistPos;
+  NPBool                      mReachedEndOfMovie;
+  std::vector<char*>          mCmmlStrings;
   nsILibOggCallbackString   * mCmmlCallback;
   nsILibOggCallbackNoArg    * mEndPlayCallback;
   nsILibOggCallbackNoArg    * mPlaylistCallback;
-  semaphore                   mCmmlSem;
-  semaphore                   mEndPlaySem;
-  semaphore                   mPlaylistSem;
+  semaphore                   mCrossThreadSem;
 
-  char                      * mProxyHost;
-  int                         mProxyPort;
-
 #if defined(XP_WIN)
-  WNDPROC             lpOldProc;
-  bool                mPollingStarted;
-  UINT                mPollingPeriod;  
-  std::vector<char*>  mCmmlStrings;
-  void clearCmmlStrings();
+  bool                        mPollingStarted;
+  UINT                        mPollingPeriod;  
 #elif defined(XP_MACOSX)
-  NPBool              mOutputCleared;
-  std::vector<char*>  mCmmlStrings;    
-  void clearCmmlStrings();
+  NPBool                      mOutputCleared;
 #endif
-
-public:
-  char                mString[128];
 };
 
 #endif // __PLUGIN_H__

Modified: liboggplay/trunk/plugin/plugin_c.h
===================================================================
--- liboggplay/trunk/plugin/plugin_c.h	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin_c.h	2007-06-28 12:29:38 UTC (rev 3118)
@@ -3,3 +3,6 @@
 
 void 
 onCMMLData(nsPluginInstance *i, char **cmml_data, int cmml_size);
+
+void
+onEndOfMovie(nsPluginInstance *i);

Modified: liboggplay/trunk/plugin/plugin_gui_linux.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_linux.c	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin_gui_linux.c	2007-06-28 12:29:38 UTC (rev 3118)
@@ -177,6 +177,7 @@
 
     case OGGPLAY_STREAM_LAST_DATA:
       info->playback_finished = TRUE;
+      onEndOfMovie(info->pluginInstance);
       return TRUE;
 
     default:

Modified: liboggplay/trunk/plugin/plugin_gui_mac.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_mac.c	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin_gui_mac.c	2007-06-28 12:29:38 UTC (rev 3118)
@@ -425,6 +425,7 @@
           break;
         case OGGPLAY_STREAM_LAST_DATA:
           info->playback_finished = TRUE;
+          onEndOfMovie(info->plugin_instance);
           break;
       }
     }

Deleted: liboggplay/trunk/plugin/plugin_playlist.c
===================================================================
--- liboggplay/trunk/plugin/plugin_playlist.c	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin_playlist.c	2007-06-28 12:29:38 UTC (rev 3118)
@@ -1,154 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Initial Developer of the Original Code is
- * CSIRO
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Marcin Lubonski
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */    
-
-
-#include "plugin_playlist.h"
-
-
-/**
- * Private functions for management of list elements 
- */
-static void
-shift_up(PluginPlaylist *playlist, unsigned int start_pos, unsigned int end_pos) {
-  unsigned int i, j;  
-  if (playlist->data == NULL) 
-    return;    
-  
-  if ((start_pos < 1) || (end_pos > playlist->length))
-    return;
-
-  for (j = 0, i = end_pos - 1; j < end_pos - start_pos; i--, j++) {       
-      playlist->data[i] = playlist->data[i - 1];        
-  } 
-}
-
-static void
-shift_down(PluginPlaylist *playlist, unsigned int start_pos, unsigned int end_pos) {
-  unsigned int i, j;
-  if (playlist->data == NULL) 
-    return;    
-  
-  if ((start_pos < 1) || (end_pos > playlist->length))
-    return;
-
-  for (j = 0, i = start_pos - 1; j <  end_pos - start_pos; j++, i++) {       
-      playlist->data[i] = playlist->data[i + 1];    
-  }
-}
-
-/**
- * Playlist public interface
- */
-void 
-init(PluginPlaylist *playlist) {
-  playlist->data = NULL;
-  playlist->length = 0;
-}
-
-/*
- * \brief - Append new element at the end of the list
- */
-void 
-append(PluginPlaylist * playlist, void * elem) {  
-  
-  if (playlist->data == NULL) {
-    playlist->data = (void**)malloc(sizeof(void*));
-    playlist->length = 1;
-  } 
-  else 
-  {    
-    playlist->data = realloc(playlist->data, (playlist->length + 1) * sizeof(void *));   
-    playlist->length += 1;
-  }
-  
-  playlist->data[playlist->length-1] = elem;
-  return;
-}
-/*
- * \brief - Add new element at position list_pos
- */
-void 
-insert_at(PluginPlaylist*  playlist, void * elem, unsigned int list_pos) {    
-
-    if (playlist->data == NULL) {
-        if (list_pos > 1) 
-                return;
-        playlist->data = (void **)malloc(sizeof(void *));
-        playlist->length = 1;        
-    } else {
-        if (list_pos > playlist->length + 1)
-                return;        
-        playlist->data = realloc(playlist->data, (playlist->length + 1) * sizeof(void *));
-        playlist->length += 1;
-    }
-    
-    if (playlist->length > 1) {      
-      // if the existing element require shifting up
-      if (list_pos < playlist->length) {                
-        shift_up(playlist, list_pos, playlist->length);        
-      }
-    }
-    playlist->data[list_pos-1] = elem;
-    return;
-}
-
-/*
- * \brief Removes element of the playlist
- */
-void 
-remove_at(PluginPlaylist*  playlist, unsigned int list_pos) {  
-
-  if (playlist->data == NULL)
-    return;
-
-  if ((list_pos <= 0) || (list_pos > playlist->length))
-    return;
-    
-  shift_down(playlist, list_pos, playlist->length);  
-  playlist->data = realloc(playlist->data, (playlist->length - 1) * sizeof(void *));
-  playlist->length -= 1;
-  
-  return;
-}
-
-void 
-show(PluginPlaylist* playlist) {
-  unsigned int i;
-  if (playlist != NULL) {
-   for (i = 0; i < playlist->length; i++) {
-     printf("Playlist entry [%d] is : %s\n", i + 1, (char *)playlist->data[i]);
-   }
-  }
-  return;
-}

Deleted: liboggplay/trunk/plugin/plugin_playlist.h
===================================================================
--- liboggplay/trunk/plugin/plugin_playlist.h	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/plugin_playlist.h	2007-06-28 12:29:38 UTC (rev 3118)
@@ -1,63 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Initial Developer of the Original Code is
- * CSIRO
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Shane Stephens, Michael Martin
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */  
-
-#ifndef __PLUGIN_PLAYLIST__
-#define __PLUGIN_PLAYLIST__
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#define PLAYLIST_ELEM_TYPE char*
-
-typedef struct {
-  void ** data;
-  unsigned int length;
-} PluginPlaylist;
-
-void
-init(PluginPlaylist * playlist);
-
-void 
-append(PluginPlaylist * playlist, void * elem);
-
-void 
-insert_at(PluginPlaylist*  playlist, void * elem, unsigned int list_pos);
-
-void 
-remove_at(PluginPlaylist*  playlist, unsigned int list_pos);
-
-void 
-show(PluginPlaylist* playlist);
-
-#endif //__PLUGIN_PLAYLIST__

Modified: liboggplay/trunk/plugin/support/nsScriptablePeer.cpp
===================================================================
--- liboggplay/trunk/plugin/support/nsScriptablePeer.cpp	2007-06-28 12:17:24 UTC (rev 3117)
+++ liboggplay/trunk/plugin/support/nsScriptablePeer.cpp	2007-06-28 12:29:38 UTC (rev 3118)
@@ -263,6 +263,27 @@
   return NS_OK;
 }
 
+NS_IMETHODIMP nsScriptablePeer::PlayMovieAt(PRInt32 position, PRInt32 *_retval) {
+  *_retval = FALSE;
+  if (mPlugin)
+    *_retval = mPlugin->playMovieAt(position);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::PlaylistNext(PRInt32 *_retval) {
+  *_retval = FALSE;
+  if (mPlugin)
+    *_retval = mPlugin->playlistNext();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsScriptablePeer::PlaylistPrev(PRInt32 *_retval) {
+  *_retval = FALSE;
+  if (mPlugin)
+    *_retval = mPlugin->playlistPrev();
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsScriptablePeer::GetMovieAt(PRInt32 position, char **_retval) {
   *_retval = NULL;
   if (mPlugin)
@@ -297,20 +318,6 @@
   return NS_OK;
 }
 
-NS_IMETHODIMP nsScriptablePeer::GetPlayPositionWithinMovie(PRInt32 *_retval) {
-  *_retval = -1;
-  if (mPlugin)
-    *_retval = mPlugin->getPlayPositionWithinMovie();
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsScriptablePeer::SetPlayPositionWithinMovie(PRInt32 milliseconds, PRBool *_retval) {
-  *_retval = FALSE;
-  if (mPlugin)
-    *_retval = mPlugin->setPlayPositionWithinMovie(milliseconds);
-  return NS_OK;
-}
-
 NS_IMETHODIMP nsScriptablePeer::RetrieveAnnotationsAt(PRInt32 position, char **_retval) {
   *_retval = NULL;
   if (mPlugin)



More information about the commits mailing list