Launch player process only after we have received both the XID and the stream to...
authorIlpo Ruotsalainen <ilpo.ruotsalainen@movial.fi>
Mon, 29 Sep 2008 11:45:53 +0000 (14:45 +0300)
committerIlpo Ruotsalainen <ilpo.ruotsalainen@movial.fi>
Mon, 29 Sep 2008 11:45:53 +0000 (14:45 +0300)
Shortcut file:// URIs directly to the player.

isatis-plugin/plugin.c

index 333efcf..5363688 100644 (file)
@@ -31,6 +31,8 @@ struct plugin_private
        int data_fd;
        pid_t player_pid;
        int has_stream;
+       char *uri;
+       unsigned long xid;
 };
 
 #define GET_PLUGIN_PRIVATE(i, x)           \
@@ -41,6 +43,83 @@ struct plugin_private
     x = (i)->pdata;                        \
        } while (0)
 
+static NPNetscapeFuncs host_funcs;
+
+static NPError NPP_SpawnPlayer(NPP instance)
+{
+       int r;
+       int pipe_fds[2];
+       struct plugin_private *priv;
+
+       DBG(("NPP_SpawnPlayer(%p)\n", instance));
+
+       GET_PLUGIN_PRIVATE(instance, priv);
+
+       if (pipe(pipe_fds) < 0)
+       {
+               DBG(("  pipe() failed: %s\n", strerror(errno)));
+               return NPERR_GENERIC_ERROR;
+       }
+
+       r = fork();
+
+       switch (r)
+       {
+               case 0:
+                       /* Child process */
+                       {
+                               char xid_buf[32];
+                               char uri_buf[32];
+                               char *uri;
+
+                               /* Close the input side of the pipe in the child process */
+                               close(pipe_fds[1]);
+
+                               snprintf(xid_buf, sizeof(xid_buf), "0x%lx", priv->xid);
+
+                               if (priv->uri)
+                                       uri = priv->uri;
+                               else
+                               {
+                                       snprintf(uri_buf, sizeof(uri_buf), "fd://%d", pipe_fds[0]);
+
+                                       uri = uri_buf;
+                               }
+
+                               execl(BINDIR "/isatis-player",
+                                               "isatis-player",
+                                               "--xid",
+                                               xid_buf,
+                                               uri,
+                                               NULL);
+
+                               DBG(("exec() failed\n"));
+                               _exit(1);
+                       }
+
+               default:
+                       /* Parent process */
+                       break;
+
+               case -1:
+                       /* Error */
+                       DBG(("  fork() failed: %s\n", strerror(errno)));
+                       return NPERR_GENERIC_ERROR;
+       }
+
+       DBG(("  child pid is %d\n", r));
+
+       /* Close the output side of the pipe in the parent process */
+       close(pipe_fds[0]);
+
+       fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK);
+
+       priv->player_pid = r;
+       priv->data_fd = pipe_fds[1];
+
+       return NPERR_NO_ERROR;
+}
+
 NPError NPP_New(NPMIMEType type, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved)
 {
        struct plugin_private *priv;
@@ -57,6 +136,8 @@ NPError NPP_New(NPMIMEType type, NPP instance, uint16 mode, int16 argc, char *ar
        priv->data_fd = -1;
        priv->player_pid = 0;
        priv->has_stream = 0;
+       priv->uri = NULL;
+       priv->xid = 0;
 
        return NPERR_NO_ERROR;
 }
@@ -71,6 +152,9 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save)
 
        if (priv)
        {
+               if (priv->uri)
+                       free(priv->uri);
+
                if (priv->data_fd != -1)
                        close(priv->data_fd);
 
@@ -101,8 +185,6 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save)
 NPError NPP_SetWindow(NPP instance, NPWindow *window)
 {
        struct plugin_private *priv;
-       int r;
-       int pipe_fds[2];
 
        DBG(("NPP_SetWindow(%p, %p)\n", instance, window));
 
@@ -114,60 +196,11 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window)
        if (priv->player_pid > 0)
                return NPERR_NO_ERROR;
 
-       if (pipe(pipe_fds) < 0)
-       {
-               DBG(("  pipe() failed: %s\n", strerror(errno)));
-               return NPERR_GENERIC_ERROR;
-       }
-
-       r = fork();
-
-       switch (r)
-       {
-               case 0:
-                       /* Child process */
-                       {
-                               char xid_buf[32];
-                               char uri[32];
-
-                               /* Close the input side of the pipe in the child process */
-                               close(pipe_fds[1]);
-
-                               /* XXX Pass the stream length (if known) to child, and shortcut file:// URIs XXX */
-
-                               snprintf(xid_buf, sizeof(xid_buf), "0x%x", (unsigned int)window->window);
-                               snprintf(uri, sizeof(uri), "fd://%d", pipe_fds[0]);
-
-                               execl(BINDIR "/isatis-player",
-                                               "isatis-player",
-                                               "--xid",
-                                               xid_buf,
-                                               uri,
-                                               NULL);
-
-                               DBG(("exec() failed\n"));
-                               _exit(1);
-                       }
-
-               default:
-                       /* Parent process */
-                       break;
-
-               case -1:
-                       /* Error */
-                       DBG(("  fork() failed: %s\n", strerror(errno)));
-                       return NPERR_GENERIC_ERROR;
-       }
-
-       DBG(("  child pid is %d\n", r));
+       priv->xid = (unsigned long)window->window;
 
-       /* Close the output side of the pipe in the parent process */
-       close(pipe_fds[0]);
-
-       fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK);
-
-       priv->player_pid = r;
-       priv->data_fd = pipe_fds[1];
+       /* Delay child startup until we get the stream we're going to play */
+       if (priv->has_stream)
+               return NPP_SpawnPlayer(instance);
 
        return NPERR_NO_ERROR;
 }
@@ -188,8 +221,22 @@ NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool se
 
        priv->has_stream = 1;
 
+       DBG(("  stream->url = %s\n", stream->url));
+
+       /* Shortcut file:// URIs to direct file access */
+       if (!strncmp("file://", stream->url, 7))
+       {
+               priv->uri = strdup(stream->url);
+
+               CallNPN_DestroyStreamProc(host_funcs.destroystream, instance, stream, NPRES_DONE);
+       }
+
        *stype = NP_NORMAL;
 
+       /* If we already have the XID we can launch the player process now */
+       if (priv->xid)
+               return NPP_SpawnPlayer(instance);
+
        return NPERR_NO_ERROR;
 }
 
@@ -318,6 +365,8 @@ NPError NP_Initialize(NPNetscapeFuncs *host_vtable, NPPluginFuncs *plugin_vtable
        plugin_vtable->write         = NewNPP_WriteProc(NPP_Write);
        plugin_vtable->getvalue      = NewNPP_GetValueProc(NPP_GetValue);
 
+       memcpy(&host_funcs, host_vtable, sizeof(host_funcs));
+
        /* Not sure if missing XEmbed should be fatal error; GTK seems quite unhappy without it, even though
         * technically things should work (albeit with focus issues and such) */
        err = CallNPN_GetValueProc(host_vtable->getvalue, NULL, NPNVSupportsXEmbedBool, &hasxembed);