plugin-threads.cpp
上传用户:hongyu5696
上传日期:2018-01-22
资源大小:391k
文件大小:61k
源码类别:

PlugIns编程

开发平台:

Unix_Linux

  1. #include "plugin.h"
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <sys/time.h>
  5. #include "plugin-setup.h"
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <sys/wait.h>
  9. #include <sys/param.h>
  10. #include <errno.h>
  11. extern int DEBUG;
  12. extern int errno;
  13. static void sig_child(int signo)
  14. {
  15.     wait(NULL);
  16. }
  17. /*
  18.  * Copyright (c) 2002 - 2003
  19.  * NetGroup, Politecnico di Torino (Italy)
  20.  * All rights reserved.
  21.  * 
  22.  * Redistribution and use in source and binary forms, with or without 
  23.  * modification, are permitted provided that the following conditions 
  24.  * are met:
  25.  * 
  26.  * 1. Redistributions of source code must retain the above copyright 
  27.  * notice, this list of conditions and the following disclaimer.
  28.  * 2. Redistributions in binary form must reproduce the above copyright 
  29.  * notice, this list of conditions and the following disclaimer in the 
  30.  * documentation and/or other materials provided with the distribution. 
  31.  * 3. Neither the name of the Politecnico di Torino nor the names of its 
  32.  * contributors may be used to endorse or promote products derived from 
  33.  * this software without specific prior written permission. 
  34.  * 
  35.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
  36.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
  37.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
  38.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
  39.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  42.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
  43.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  44.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  45.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  46.  * 
  47.  */
  48. /* 
  49.  * the above copyright applies to pthread_suspend only 
  50.  */
  51. #ifdef GTK_ENABLED
  52. gboolean mediacallback(void *data)
  53. {
  54.     nsPluginInstance *instance;
  55.     if (DEBUG > 1)
  56. printf("in mediacallbackn");
  57.     instance = (nsPluginInstance *) data;
  58.     if (instance->mediaCompleteCallback != NULL)
  59. NPN_GetURL(instance->mInstance,
  60.    instance->mediaCompleteCallback, "_self");
  61.     if (instance->mediaCompleteWithErrorCallback != NULL)
  62. NPN_GetURL(instance->mInstance,
  63.    instance->mediaCompleteWithErrorCallback, "_self");
  64.     return FALSE;
  65. }
  66. #endif
  67. void pthread_suspend(int msec)
  68. {
  69.     struct timespec abstime;
  70.     struct timeval now;
  71.     pthread_cond_t cond;
  72.     pthread_mutex_t mutex;
  73.     pthread_mutexattr_t attr;
  74.     pthread_mutexattr_init(&attr);
  75.     pthread_mutex_init(&mutex, &attr);
  76.     pthread_mutex_lock(&mutex);
  77.     pthread_cond_init(&cond, NULL);
  78.     gettimeofday(&now, NULL);
  79.     abstime.tv_sec = now.tv_sec + msec / 1000;
  80.     abstime.tv_nsec = now.tv_usec * 1000 + (msec % 1000) * 1000 * 1000;
  81.     pthread_cond_timedwait(&cond, &mutex, &abstime);
  82.     pthread_mutex_destroy(&mutex);
  83.     pthread_cond_destroy(&cond);
  84. }
  85. //this function must be called with control_mutex locked
  86. void launchPlayerThread(nsPluginInstance * instance)
  87. {
  88.     void *thread_return;
  89.     if (DEBUG)
  90. printf("In launchPlayerThread, state = %dn", instance->state);
  91.     if (instance->threadlaunched == 1) {
  92. if (DEBUG)
  93.     printf("launchPlayerThread - joining threadn");
  94. pthread_join(instance->player_thread, &thread_return);
  95.     }
  96.     if (instance->js_state == JS_STATE_UNDEFINED) {
  97. if (DEBUG)
  98.     printf("launchPlayerThread - creating new threadn");
  99. pthread_create(&(instance->player_thread),
  100.        &(instance->thread_attr), playPlaylist,
  101.        (void *) (instance->td));
  102. instance->js_state = JS_STATE_INITIALIZING;
  103. instance->threadlaunched = 1;
  104. instance->threadsignaled = 0;
  105.     } else {
  106. printf
  107.     ("****WARNING: launching duplicate player thread, js_state = %dn",
  108.      instance->js_state);
  109. instance->threadlaunched = 0;
  110.     }
  111. }
  112. void signalPlayerThread(nsPluginInstance * instance)
  113. {
  114.     //signal the player thread
  115.     if (DEBUG) {
  116. printf("Signalling Player thread, state = %d, js_state = %dn",
  117.        instance->state, instance->js_state);
  118.     }
  119.     if (instance->threadlaunched != 1)
  120. if (DEBUG)
  121.     printf("****Player thread did not launch correctly****n");
  122.     pthread_mutex_lock(&(instance->control_mutex));
  123.     while (instance->js_state == JS_STATE_INITIALIZING) {
  124. if (DEBUG)
  125.     printf("Waiting for player thread to start....%in",
  126.    instance->js_state);
  127. pthread_mutex_unlock(&(instance->control_mutex));
  128. pthread_suspend(10);
  129. pthread_mutex_lock(&(instance->control_mutex));
  130.     }
  131.     if (instance->js_state == JS_STATE_BUFFERING
  132. || instance->js_state == JS_STATE_READY) {
  133. pthread_mutex_lock(&(instance->playlist_cond_mutex));
  134. pthread_cond_signal(&(instance->playlist_complete_cond));
  135. pthread_mutex_unlock(&(instance->playlist_cond_mutex));
  136. instance->threadsignaled = 1;
  137.     } else {
  138. if (DEBUG)
  139.     printf("****Player thread did not start correctly****n");
  140.     }
  141.     pthread_mutex_unlock(&(instance->control_mutex));
  142. }
  143. FILE *mypopen(char **argv, pid_t * pid, int *control,
  144.       nsPluginInstance * instance)
  145. {
  146.     int filedesr[2], filedesw[2], err;
  147.     pid_t child;
  148.     long flags;
  149.     sigset_t newmask;
  150.     FILE *retfd;
  151.     pipe(filedesr);
  152.     pipe(filedesw);
  153.     child = fork();
  154.     if (!child) {
  155. if (DEBUG) {
  156.     char **tmp;
  157.     tmp = argv;
  158.     printf("Starting: ");
  159.     while (*tmp)
  160. printf("%s ", *(tmp++));
  161.     printf("n");
  162. }
  163. dup2(filedesw[0], 0);
  164. dup2(filedesr[1], 1);
  165. dup2(filedesr[1], 2);
  166. close(filedesw[1]);
  167. close(filedesr[0]);
  168. setsid();
  169. setpgid(0, 0);
  170. sigemptyset(&newmask);
  171. sigaddset(&newmask, SIGTERM);
  172. sigaddset(&newmask, SIGKILL);
  173. pthread_sigmask(SIG_UNBLOCK, &newmask, 0L);
  174. usleep(500);
  175. if (execvp(argv[0], argv) < 0) {
  176.     err = errno;
  177. #ifdef GTK_ENABLED
  178.     snprintf(instance->lastmessage, 1024, "Error: %i - %s", err,
  179.      strerror(err));
  180.     g_idle_add(gtkgui_message, instance);
  181. #endif
  182.     perror("execv");
  183. }
  184. _exit(0);
  185.     } else {
  186. // setup signal handler for child
  187. signal(SIGCHLD, sig_child);
  188. sigemptyset(&newmask);
  189. sigaddset(&newmask, SIGCHLD);
  190. sigaddset(&newmask, SIGTERM);
  191. sigaddset(&newmask, SIGKILL);
  192. pthread_sigmask(SIG_UNBLOCK, &newmask, 0L);
  193. *pid = child;
  194. *control = filedesw[1];
  195. close(filedesw[0]);
  196. close(filedesr[1]);
  197. // make the operations on the control pipe non-blocking
  198. flags = fcntl(*control, F_GETFL, 0);
  199. flags |= O_NONBLOCK;
  200. #ifndef BSD
  201. flags |= O_NDELAY;
  202. #endif
  203. fcntl(*control, F_SETFL, flags);
  204. retfd = fdopen(filedesr[0], "r");
  205. return retfd;
  206.     }
  207. }
  208. void SetupPlayer(nsPluginInstance * instance, XEvent * event)
  209. {
  210.     int i;
  211.     char xval[32], yval[32];
  212.     char *filename;
  213.     char *baseurl;
  214.     char buffer[1024];
  215. #ifndef X_DISPLAY_MISSING
  216.     char *dispName = XDisplayName(NULL);
  217. #endif
  218.     bool isRemoteDisplay = false;
  219.     if (instance->threadsetup == 1)
  220. return;
  221.     if (instance->toolkitok != 0)
  222. return;
  223.     instance->td->w = instance->widget;
  224.     instance->td->instance = instance;
  225.     if (DEBUG > 1)
  226. printf("Entering SetupPlayern");
  227. #ifdef X_ENABLED
  228.     DrawUI(instance->widget, instance, _("Loading Media..."), 0, -1);
  229. #endif
  230. #ifdef GTK_ENABLED
  231.     if (instance->status != NULL)
  232. gtk_label_set_text(instance->status, _("Loading Media..."));
  233. #endif
  234.     if (instance->td->list == NULL) {
  235. instance->td->list = instance->list;
  236.     }
  237. /*
  238.     if (instance->href) {
  239. if (DEBUG)
  240.     printf("using href for urln");
  241. snprintf(instance->td->list->url, 1024, "%s", instance->href);
  242.     } else 
  243. */
  244.     if (instance->fname) {
  245. if (DEBUG)
  246.     printf("using fname for urln");
  247. snprintf(instance->td->list->url, 1024, "%s", instance->fname);
  248.     } else {
  249. if (DEBUG)
  250.     printf("using url for urln");
  251. snprintf(instance->td->list->url, 1024, "%s", instance->url);
  252.     }
  253.     if ((instance->fname == NULL) && (instance->url == NULL)) {
  254. if (DEBUG)
  255.     printf("using href for urln");
  256. snprintf(instance->td->list->url, 1024, "%s", instance->href);
  257.     }
  258.     if (instance->mode == NP_FULL) {
  259. snprintf(xval, 32, "%i", instance->window_width);
  260. snprintf(yval, 32, "%i", instance->window_height);
  261.     } else {
  262. snprintf(xval, 32, "%i", instance->embed_width);
  263. if (instance->maintain_aspect == 0 && instance->showcontrols == 1) {
  264.     snprintf(yval, 32, "%i", instance->embed_height - 16);
  265. } else {
  266.     snprintf(yval, 32, "%i", instance->embed_height);
  267. }
  268.     }
  269.     baseurl = NULL;
  270.     if (instance->baseurl == NULL) {
  271. baseurl = getURLBase(instance->td->list->url);
  272. if (baseurl != NULL) {
  273.     if (instance->baseurl == NULL) {
  274. instance->baseurl = baseurl;
  275.     } else {
  276. if (strcmp(instance->baseurl, baseurl) != 0) {
  277.     NPN_MemFree(instance->baseurl);
  278.     instance->baseurl = baseurl;
  279. } else {
  280.     NPN_MemFree(baseurl);
  281. }
  282.     }
  283. }
  284.     }
  285.     if (instance->hostname == NULL)
  286. instance->hostname = getURLHostname(instance->td->list->url);
  287.     if (instance->keep_download == 1) {
  288. instance->td->list->remove = 0;
  289. filename = getURLFilename(instance->td->list->url);
  290. snprintf(instance->td->list->fname, 1024, "%s/%s",
  291.  instance->download_dir, filename);
  292. if (filename)
  293.     NPN_MemFree(filename);
  294.     } else {
  295. if ((instance->nomediacache == 0)
  296.     && (instance->td->list->bytes > 0)) {
  297.     if (strlen(instance->td->list->fname) == 0) {
  298. snprintf(instance->td->list->fname, 1024, "%s",
  299.  tempnam("/tmp", "downloadplug-inXXXXXX"));
  300.     }
  301. } else {
  302.     // fix up the URL
  303.     pthread_mutex_lock(&(instance->playlist_mutex));
  304.     fullyQualifyURL(instance, instance->td->list->url, buffer);
  305.     if (DEBUG)
  306. printf("url %snbuffer %sn", instance->td->list->url,
  307.        buffer);
  308.     snprintf(instance->td->list->url, 1024, "%s", buffer);
  309.     pthread_mutex_unlock(&(instance->playlist_mutex));
  310. }
  311.     }
  312.     // set up the vars
  313.     i = 0;
  314.     while (i < 50) {
  315. instance->td->argv[i++] = NULL;
  316.     }
  317.     i = 0;
  318.     snprintf(buffer, 1024, "download");
  319.     instance->td->argv[i++] = strdup(buffer);
  320.     if (instance->novop == 1) {
  321. snprintf(buffer, 1024, "-vop");
  322. instance->td->argv[i++] = strdup(buffer);
  323. snprintf(buffer, 1024, "null");
  324. instance->td->argv[i++] = strdup(buffer);
  325.     } else {
  326. if (instance->vop != NULL) {
  327.     snprintf(buffer, 1024, "-vop");
  328.     instance->td->argv[i++] = strdup(buffer);
  329.     snprintf(buffer, 1024, "%s", instance->vop);
  330.     instance->td->argv[i++] = strdup(buffer);
  331.     if (strncmp(instance->vop, "scale=", 6) == 0) {
  332. snprintf(buffer, 1024, "-fs");
  333. instance->td->argv[i++] = strdup(buffer);
  334.     }
  335. }
  336.     }
  337.     if ((instance->mode == NP_EMBED) && (instance->noembed == 0)) {
  338. if (instance->window != 0) {
  339.     snprintf(buffer, 1024, "-wid");
  340.     instance->td->argv[i++] = strdup(buffer);
  341. #ifdef X_ENABLED
  342. //          instance->player_window =
  343. //              XCreateSimpleWindow(instance->display, instance->window, 0,
  344. //                                  0, instance->embed_width,
  345. //                                  instance->embed_height, 0, 0, 0);
  346.     snprintf(buffer, 1024, "0x%x", (int) instance->window);
  347.     instance->td->argv[i++] = strdup(buffer);
  348. #endif
  349. #ifdef GTK_ENABLED
  350.     if (instance->targetplayer == 1) {
  351. gtk_widget_show(instance->gtkwidget);
  352. gtk_widget_show(instance->drawing_area);
  353.     }
  354. #ifdef GTK2_ENABLED
  355.     instance->player_window =
  356. gtk_socket_get_id(GTK_SOCKET(instance->drawing_area));
  357. #endif
  358. #ifdef GTK1_ENABLED
  359.     instance->player_window =
  360. GDK_WINDOW_XWINDOW(instance->drawing_area->window);
  361. #endif /* if (instance->targetplayer == 1) */
  362.     snprintf(buffer, 1024, "0x%x", (int) instance->player_window);
  363.     instance->td->argv[i++] = strdup(buffer);
  364. #ifdef GTK2_ENABLED
  365.     instance->visible_signal_id =
  366. g_signal_connect_after(G_OBJECT(instance->gtkwidget),
  367.        "visibility-notify-event",
  368.        G_CALLBACK(window_visible),
  369.        instance);
  370. #endif
  371.     if (instance->targetplayer == 1)
  372. gtk_widget_hide(instance->gtkwidget);
  373. #endif
  374. } else {
  375.     instance->player_window = 0;
  376. }
  377.     }
  378.     if ((instance->mode == NP_FULL) && (instance->noembed == 0)) {
  379. if (instance->window != 0) {
  380.     snprintf(buffer, 1024, "-wid");
  381.     instance->td->argv[i++] = strdup(buffer);
  382. #ifdef X_ENABLED
  383.     snprintf(buffer, 1024, "0x%x", (int) instance->window);
  384.     instance->td->argv[i++] = strdup(buffer);
  385. #endif
  386. #ifdef GTK_ENABLED
  387.     gtk_widget_set_usize(GTK_WIDGET(instance->status),
  388.  instance->window_width - 20, 19);
  389. #ifdef GTK2_ENABLED
  390.     instance->player_window =
  391. gtk_socket_get_id(GTK_SOCKET(instance->drawing_area));
  392. #endif
  393. #ifdef GTK1_ENABLED
  394.     instance->player_window =
  395. GDK_WINDOW_XWINDOW(instance->drawing_area->window);
  396. #endif
  397.     snprintf(buffer, 1024, "0x%x", (int) instance->player_window);
  398.     instance->td->argv[i++] = strdup(buffer);
  399. #endif
  400. } else {
  401.     instance->player_window = 0;
  402. }
  403.     }
  404.     if ((instance->embed_width == 0)
  405. || (instance->noembed == 1)) {
  406. // do nothing
  407.     } else {
  408. if (instance->mode == NP_EMBED) {
  409. #ifndef X_DISPLAY_MISSING
  410.     // on remote display, XShm will be disabled.
  411.     // it should not specified aspect. 
  412.     if (dispName) {
  413. if (strncmp(dispName, "unix:", 5) == 0)
  414.     dispName += 4;
  415. else if (strncmp(dispName, "localhost:", 10) == 0)
  416.     dispName += 9;
  417. if (*dispName != ':' || atoi(dispName + 1) >= 10) {
  418.     isRemoteDisplay = true;
  419.     instance->maintain_aspect = 0;
  420.     if (DEBUG)
  421. printf("x11 is running on remote display.n");
  422. }
  423.     }
  424. #endif
  425.     if ((isRemoteDisplay == false)
  426. && (instance->targetplayer == 0)) {
  427. if (instance->maintain_aspect == 1) {
  428.     snprintf(buffer, 1024, "-vf");
  429.     instance->td->argv[i++] = strdup(buffer);
  430.     snprintf(buffer, 1024, "scale=%s:-3", xval);
  431.     instance->td->argv[i++] = strdup(buffer);
  432. } else {
  433.     snprintf(buffer, 1024, "-x");
  434.     instance->td->argv[i++] = strdup(buffer);
  435.     snprintf(buffer, 1024, "%s", xval);
  436.     instance->td->argv[i++] = strdup(buffer);
  437.     snprintf(buffer, 1024, "-y");
  438.     instance->td->argv[i++] = strdup(buffer);
  439.     snprintf(buffer, 1024, "%s", yval);
  440.     instance->td->argv[i++] = strdup(buffer);
  441. }
  442.     }
  443. }
  444.     }
  445. //    if (instance->rtsp_use_tcp == 1) {
  446. //      snprintf(buffer, 1024, "-rtsp-stream-over-tcp");
  447. //      instance->td->argv[i++] = strdup(buffer);
  448. //    }
  449. //    if (instance->cachesize > 0) {
  450. //      snprintf(buffer, 1024, "-cache");
  451. //      instance->td->argv[i++] = strdup(buffer);
  452. //      snprintf(buffer, 1024, "%i", instance->cachesize);
  453. //      instance->td->argv[i++] = strdup(buffer);
  454. //    } else {
  455. //      snprintf(buffer, 1024, "-nocache");
  456. //      instance->td->argv[i++] = strdup(buffer);
  457. //    }
  458. //    if (instance->loop == 1) {
  459. //      snprintf(instance->td->argv[i++], 1024, "-loop");
  460. //      snprintf(instance->td->argv[i++], 1024, "0");
  461. //    }
  462.     if (instance->vo) {
  463. snprintf(buffer, 1024, "-vo");
  464. instance->td->argv[i++] = strdup(buffer);
  465. snprintf(buffer, 1024, "%s", instance->vo);
  466. instance->td->argv[i++] = strdup(buffer);
  467. if ((strncmp(buffer, "x11", 3) == 0)
  468.     || (strstr(buffer, ",x11") != NULL)) {
  469.     snprintf(buffer, 1024, "-zoom"); /* -vo x11 needs -zoom for rescaling */
  470.     instance->td->argv[i++] = strdup(buffer);
  471. }
  472.     }
  473.     if (instance->ao) {
  474. snprintf(buffer, 1024, "-ao");
  475. instance->td->argv[i++] = strdup(buffer);
  476. snprintf(buffer, 1024, "%s", instance->ao);
  477. instance->td->argv[i++] = strdup(buffer);
  478.     }
  479.     if (instance->af) {
  480. snprintf(buffer, 1024, "-af");
  481. instance->td->argv[i++] = strdup(buffer);
  482. snprintf(buffer, 1024, "%s", instance->af);
  483. instance->td->argv[i++] = strdup(buffer);
  484.     }
  485.     if (instance->output_display) {
  486. snprintf(buffer, 1024, "-display");
  487. instance->td->argv[i++] = strdup(buffer);
  488. snprintf(buffer, 1024, "%s", instance->output_display);
  489. instance->td->argv[i++] = strdup(buffer);
  490.     }
  491.     if (instance->framedrop == 1) {
  492. snprintf(buffer, 1024, "-framedrop");
  493. instance->td->argv[i++] = strdup(buffer);
  494.     }
  495.     if (instance->autosync > 0) {
  496. snprintf(buffer, 1024, "-autosync");
  497. instance->td->argv[i++] = strdup(buffer);
  498. snprintf(buffer, 1024, "%i", instance->autosync);
  499. instance->td->argv[i++] = strdup(buffer);
  500.     }
  501.     if (instance->mc > 0) {
  502. snprintf(buffer, 1024, "-mc");
  503. instance->td->argv[i++] = strdup(buffer);
  504. snprintf(buffer, 1024, "%i", instance->mc);
  505. instance->td->argv[i++] = strdup(buffer);
  506.     }
  507.     snprintf(buffer, 1024, "-osdlevel");
  508.     instance->td->argv[i++] = strdup(buffer);
  509.     snprintf(buffer, 1024, "%i", instance->osdlevel);
  510.     instance->td->argv[i++] = strdup(buffer);
  511.     /* some extra flags for download */
  512.     snprintf(buffer, 1024, "-nojoystick"); /* annoying... */
  513.     instance->td->argv[i++] = strdup(buffer);
  514.     if (instance->noconsolecontrols) {
  515. snprintf(buffer, 1024, "-noconsolecontrols");
  516. instance->td->argv[i++] = strdup(buffer);
  517.     }
  518.     if (instance->cookies) {
  519. snprintf(buffer, 1024, "-cookies");
  520. instance->td->argv[i++] = strdup(buffer);
  521.     }
  522. //    snprintf(buffer, 1024, "-nofs");  /* no full screen */
  523. //    instance->td->argv[i++] = strdup(buffer);
  524.     snprintf(buffer, 1024, "-slave"); /* slave mode */
  525.     instance->td->argv[i++] = strdup(buffer);
  526.     instance->td->argv[i++] = NULL;
  527.     // ok we have the command line setup
  528.     if (DEBUG)
  529. printf("ready to setup threadsn");
  530.     pthread_attr_setdetachstate(&(instance->thread_attr),
  531. PTHREAD_CREATE_JOINABLE);
  532.     if (DEBUG)
  533. printf("creating thread - NP_EMBEDn");
  534. #ifdef X_ENABLED
  535.     DrawUI(instance->widget, instance, _("Getting playlist..."), 0, -1);
  536. #endif
  537. #ifdef GTK_ENABLED
  538.     if (instance->status != NULL)
  539. gtk_label_set_text(instance->status, _("Getting playlist..."));
  540. #endif
  541.     if (instance->state < STATE_GETTING_PLAYLIST)
  542. instance->state = STATE_GETTING_PLAYLIST;
  543.     if (0) {
  544. printf("SetupPlayer: printing instance->listn");
  545. printList(instance->list);
  546. printf("SetupPlayer: printing instance->td->listn");
  547. printList(instance->td->list);
  548.     }
  549.     if (DEBUG)
  550. printf("creating player threadn");
  551.     pthread_mutex_lock(&(instance->control_mutex));
  552.     instance->js_state = JS_STATE_UNDEFINED;
  553.     launchPlayerThread(instance);
  554.     instance->threadsetup = 1;
  555.     pthread_mutex_unlock(&(instance->control_mutex));
  556.     // recommended slight pause
  557.     usleep(1);
  558.     if (DEBUG)
  559. printf("MAIN THREAD DONEn");
  560. }
  561. void refresh_frame(char *buffer, _ThreadData * td, Node * node)
  562. {
  563.     int seconds;
  564.     static int oldseconds = -1;
  565.     char *start;
  566.     char *endptr;
  567.     area *runner;
  568.     area *this_area;
  569. #ifdef SMILDEBUG
  570.     static FILE *error = NULL;
  571.     char errortmp[64];
  572.     if (!error)
  573. error = fopen("/tmp/downloadplugin-smil.log", "a");
  574. #endif
  575.     /* just to be sure */
  576.     if (node == NULL || node->area == NULL)
  577. return;
  578.     start = buffer;
  579.     while ((start = strstr(start, "A:")) != NULL && strlen(start) > 7) {
  580. start += 2;
  581. seconds = (int) strtol(start, &endptr, 0);
  582. if (seconds == oldseconds || start == endptr)
  583.     continue;
  584. #ifdef SMILDEBUG
  585. strlcpy(errortmp, start, 63);
  586. errortmp[64] = 0;
  587. fprintf(error, "->seconds: %d, oldseconds: %d, buffer: '%s'n",
  588. seconds, oldseconds, errortmp);
  589. fflush(error);
  590. #endif
  591. runner = node->area;
  592. this_area = node->area;
  593. while (runner) {
  594.     if (runner->begin < seconds
  595. && runner->begin > this_area->begin)
  596. this_area = runner;
  597.     if (runner->begin == seconds) {
  598. NPN_GetURL(td->instance->mInstance,
  599.    runner->url, runner->target);
  600. break;
  601.     }
  602.     runner = runner->next;
  603. }
  604. /*
  605.  *  If it was a seek we have to follow.
  606.  */
  607. if ((oldseconds - seconds > 1 || seconds - oldseconds > 1)
  608.     && !runner)
  609.     NPN_GetURL(td->instance->mInstance, this_area->url,
  610.        this_area->target);
  611. oldseconds = seconds;
  612.     }
  613. }
  614. //return true if we should try to play this again immediately, false if not 
  615. PlayResult *playNode(ThreadData * local_td, Node * local_list,
  616.      char *local_url, int local_mmsstream, int *usefps,
  617.      int *nomouseinput, int *maybeplaylist)
  618. {
  619.     PlayResult *result = (PlayResult *) NPN_MemAlloc(sizeof(PlayResult));
  620.     char buffer[1024];
  621.     char message[1024];
  622.     int notfound;
  623.     char *vo;
  624.     char vm[10];
  625.     char *cf;
  626.     double cfpercent;
  627.     char *eos;
  628.     char *msg;
  629.     long cfbytes, flags = 0;
  630.     int i,amt;
  631.     int zerocfbytes_count = 0;
  632.     char url_copy[1024];
  633.     int c;
  634.     int length_request_count = 0;
  635.     float lastmedialength = -1.0;
  636.     int lastmediapercent = -1;
  637.     int lastpercent = -1;
  638. #ifdef GTK_ENABLED
  639.     int fsupdated = 0;
  640. #endif
  641.     result->errorcode = ERROR_NO_ERROR;
  642.     result->tryagain = TRYAGAIN_FALLBACK;
  643.     result->retval = FALSE;
  644. /*
  645.   the meaning of the above is as follows:
  646.    TRYAGAIN_TRUE:  we should definitely try playing this url again immediately
  647.    TRYAGAIN_FALSE: we should definitely NOT do that.
  648.    TRYAGAIN_FALLBACK if we should try playing this url again immediately
  649.                     only if we have a fallback url.
  650.    these are for internal use in this function only. The function
  651.    should still return either 0 or 1 (and never 2). 
  652. */
  653.     pthread_cleanup_push((void (*)(void *))
  654.  pthread_mutex_unlock,
  655.  (void *) &(local_td->instance->control_mutex));
  656.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  657.     sendCommand(local_td->instance, "get_time_length");
  658.     local_td->instance->mediaLength = 0.0;
  659.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  660.     pthread_cleanup_pop(0);
  661. #ifdef GTK_ENABLED
  662.     g_idle_add(gtkgui_save_enable, local_td->instance);
  663. //      g_idle_add(gtkgui_refreshbuttonstate, local_td->instance);
  664. #endif
  665.     // set this to 0 for every new media file;
  666.     local_td->instance->movie_height = 0;
  667.     local_td->instance->movie_width = 0;
  668.     if (local_td->instance->player != NULL) {
  669. if (DEBUG) {
  670.     printf("Getting file mode flagsn");
  671. }
  672. flags = fcntl(fileno(local_td->instance->player), F_GETFL, 0);
  673.     }
  674.     
  675.     while (1) {
  676. pthread_testcancel();
  677. if (local_td->instance->player == NULL)
  678.     break;
  679. if (feof(local_td->instance->player)) {
  680.     pthread_testcancel();
  681.     break;
  682. }
  683. pthread_testcancel();
  684. assert(local_td != NULL);
  685. assert(local_td->instance != NULL);
  686. assert(local_td->instance->control > 0);
  687. assert(local_td->instance->player != NULL);
  688. pthread_testcancel();
  689. #ifdef GTK_ENABLED
  690. //      g_idle_add(gtkgui_save_enable, local_td->instance);
  691. //      g_idle_add(gtkgui_refreshbuttonstate, local_td->instance);
  692. #endif
  693. pthread_testcancel();
  694. if (local_td->instance->player != NULL) {
  695.     // if (fgets(buffer, 1024, local_td->instance->player) == NULL) {
  696.     //  continue;
  697.     // }
  698.     // fgets is not a pthread cancel point, so we basically have to rewrite fgets
  699.     // to make this work better. If we cancel the thread while fgets is waiting for 
  700.     // for an EOS then we crash.
  701.     buffer[0] = '';
  702.     i = 0;
  703.     do {
  704. pthread_testcancel();
  705. // need to lock around the read
  706. pthread_mutex_lock(&(local_td->instance->read_mutex));
  707. if ((local_td->instance->cancelled == 0)
  708.     && (local_td->instance->player != NULL)) {
  709.     // c = fgetc(local_td->instance->player);
  710.          amt = fread(&c, 1, 1, local_td->instance->player);
  711. } else {
  712.     c = EOF;
  713.     amt = 0;
  714. }
  715. pthread_mutex_unlock(&(local_td->instance->read_mutex));
  716. if (c == EOF) {
  717.     buffer[i] = '';
  718.     break;
  719. }
  720. if (c == 0)
  721.     continue;
  722. buffer[i] = (char) c;
  723. i += amt;
  724. if (i >= 1024) {
  725.     buffer[1023] = '';
  726.     break;
  727. }
  728.     } while (((unsigned char) c != 'n'));
  729.     if (buffer[0] == '')
  730. continue;
  731.     else if (i < 1024) // make sure we don't access out of bounds
  732. buffer[i] = ''; // make sure we NULL terminate the string
  733. }
  734.   pthread_testcancel();
  735. if (DEBUG) {
  736.     if (strlen(buffer) > 0)
  737.      printf("READ: %s n", buffer);
  738. }
  739. refresh_frame(buffer, local_td, local_list);
  740.         
  741.     
  742. pthread_testcancel();
  743. if (strstr(buffer, "STREAM") != NULL) {
  744.     if (local_td->instance->player != NULL) {
  745. if (DEBUG) {
  746.     printf("Setting file mode to non-blockingn");
  747. }
  748. fcntl(fileno(local_td->instance->player), F_SETFL, flags | O_NONBLOCK);
  749.     }
  750. }    
  751. pthread_testcancel();
  752. if (strstr(buffer, "Cache size") != NULL || strstr(buffer, "Starting playback") != NULL ) {
  753.     if (local_td->instance->player != NULL) {
  754. if (DEBUG) {
  755.     printf("Setting file mode back to blockingn");
  756. }
  757. fcntl(fileno(local_td->instance->player), F_SETFL, flags);
  758.     }
  759. }    
  760.     
  761.     
  762. pthread_testcancel();
  763. if (strstr(buffer, "Cache fill:") != NULL) {
  764.     strlcpy(message, strstr(buffer, "Cache fill"), 1024);
  765.     notfound = 1;
  766.     while (notfound) {
  767. eos = strrchr(message, 'r');
  768. if (eos == NULL)
  769.     eos = message;
  770. if (strstr(eos, "Cache fill:") == NULL) {
  771.     // if we don't find "Cache fill:" then replace the r with , making message shorter
  772.     eos[0] = '';
  773.     // break out of the loop if too short
  774.     if (strlen(message) < 5)
  775. break;
  776. } else {
  777.     // if we found the last one in the message string, move from r to C in the string
  778.     eos++;
  779.     notfound = 0;
  780. }
  781.     }
  782.     // Only update the display if there is something worth displaying
  783.     if (strstr(eos, "Cache fill:") != NULL) {
  784. cf = strstr(eos, "Cache fill:");
  785. lastpercent = (int) cfpercent;
  786. i = sscanf(cf, "Cache fill: %lf %% (%ld bytes)",
  787.    &cfpercent, &cfbytes);
  788. //the following is a workaround for an download bug
  789. // we can try to fallback to mmst when we get
  790. // Cache Fill: 0% (0 bytes) several times.
  791. if (i == 2 && cfbytes == 0) {
  792.     zerocfbytes_count++;
  793. }
  794. if (DEBUG && zerocfbytes_count > 0) {
  795.     printf("Cache Fill: 0%% (0 bytes), count = %dn",
  796.    zerocfbytes_count);
  797. }
  798. if (zerocfbytes_count >= 1 &&
  799.     ((strncmp(local_url, "mms://", 6) == 0) ||
  800.      (local_mmsstream
  801.       && strncmp(local_url, "http://", 7) == 0))) {
  802.     if (DEBUG) {
  803. printf("Exiting. Will try again with mmst://n");
  804.     }
  805.     result->tryagain = TRYAGAIN_FALLBACK;
  806.     break;
  807. }
  808. snprintf(message, 1024, _("Buffering %s"), local_url);
  809. #ifdef X_ENABLED
  810. DrawUI(local_td->instance->widget,
  811.        local_td->instance, eos, -1, (int) cfpercent);
  812. #endif
  813. #ifdef GTK_ENABLED
  814. snprintf(local_td->instance->lastmessage, 1024, "%s",
  815.  message);
  816. local_td->instance->percent = (cfpercent / 100.0);
  817. if (lastpercent != cfpercent) {
  818.     g_idle_add(gtkgui_message, local_td->instance);
  819.     g_idle_add(gtkgui_progress, local_td->instance);
  820. }
  821. #endif
  822. pthread_mutex_lock(&(local_td->instance->control_mutex));
  823. local_td->instance->js_state = JS_STATE_BUFFERING;
  824. pthread_mutex_unlock(&(local_td->instance->control_mutex));
  825.     }
  826. }
  827. pthread_testcancel();
  828. if (strstr(buffer, "Starting") != NULL) {
  829.     snprintf(message, 1024, _("Playing %s"), local_url);
  830. #ifdef X_ENABLED
  831.     DrawUI(local_td->instance->widget,
  832.    local_td->instance, message, 0, -1);
  833. #endif
  834. #ifdef GTK_ENABLED
  835.     snprintf(local_td->instance->lastmessage, 1024, "%s", message);
  836.     g_idle_add(gtkgui_message, local_td->instance);
  837. #endif
  838.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  839.     local_td->instance->js_state = JS_STATE_PLAYING;
  840.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  841. }
  842. pthread_testcancel();
  843. if (strstr(buffer, "VO:") != NULL) {
  844.     fcntl(fileno(local_td->instance->player), F_SETFL, flags);
  845.     if (local_td->instance->mode == NP_EMBED
  846. && local_td->instance->noembed == 0)
  847. local_td->instance->noredraw = 1;
  848.     vo = strstr(buffer, "VO:");
  849.     sscanf(vo, "VO: [%9[^]]] %ix%i => %ix%i", vm,
  850.    &(local_list->actual_x),
  851.    &(local_list->actual_y),
  852.    &(local_list->play_x), &(local_list->play_y));
  853.     if (local_td->instance->mode == NP_EMBED
  854. && local_td->instance->noembed == 0) {
  855. if (local_td->instance->panel_height == 0)
  856.     local_td->instance->panel_height =
  857. local_td->instance->embed_height -
  858. local_list->play_y;
  859. if (local_td->instance->player_window != 0
  860.     && local_td->instance->movie_height !=
  861.     local_list->play_y) {
  862.     local_td->instance->movie_height = local_list->play_y;
  863.     local_td->instance->movie_width = local_list->play_x;
  864. #ifdef GTK_ENABLED
  865.     g_idle_add(gtkgui_resize, local_td->instance);
  866.     g_idle_add(gtkgui_draw, local_td->instance);
  867. #endif
  868. }
  869. if (DEBUG)
  870.     printf
  871. ("----player thread: panel height in thread = %in",
  872.  local_td->instance->panel_height);
  873.     } else {
  874. local_td->instance->panel_height = 16;
  875. if (local_td->instance->player_window != 0
  876.     && local_td->instance->movie_height !=
  877.     local_list->play_y) {
  878.     local_td->instance->movie_height = local_list->play_y;
  879.     local_td->instance->movie_width = local_list->play_x;
  880. #ifdef GTK_ENABLED
  881.     g_idle_add(gtkgui_resize, local_td->instance);
  882. #endif
  883. }
  884. local_td->instance->embed_height =
  885.     local_td->instance->window_height;
  886. local_td->instance->embed_width =
  887.     local_td->instance->window_width;
  888. local_td->instance->panel_height =
  889.     local_td->instance->window_height;
  890. #ifdef GTK_ENABLED
  891. g_idle_add(gtkgui_draw, local_td->instance);
  892. #endif
  893.     }
  894. }
  895. pthread_testcancel();
  896. if (strstr(buffer, "Video: no video") != NULL) {
  897.     fcntl(fileno(local_td->instance->player), F_SETFL, flags);
  898.     if (local_td->instance->panel_height == 0)
  899. local_td->instance->panel_height = 32;
  900.     local_td->instance->noredraw = 0;
  901.     local_td->instance->movie_height = 1;
  902.     local_td->instance->movie_width = 1;
  903. #ifdef GTK_ENABLED
  904.     g_idle_add(gtkgui_resize, local_td->instance);
  905.     g_idle_add(gtkgui_draw, local_td->instance);
  906. #endif
  907. }
  908. pthread_testcancel();
  909. // download answer back messages
  910. if (strstr(buffer, "ANS_LENGTH") != 0) {
  911.     if ((int) local_td->instance->mediaLength != 0)
  912. lastmedialength = local_td->instance->mediaLength;
  913.     msg = strstr(buffer, "ANS_LENGTH");
  914.     sscanf(msg, "ANS_LENGTH=%f",
  915.    &(local_td->instance->mediaLength));
  916.     if (DEBUG > 1)
  917. printf("Media Length = %fn",
  918.        local_td->instance->mediaLength);
  919. }
  920. pthread_testcancel();
  921. // download answer back messages
  922. if (strstr(buffer, "ANS_TIME_POSITION") != 0) {
  923.     msg = strstr(buffer, "ANS_TIME_POSITION");
  924.     sscanf(msg, "ANS_TIME_POSITION=%f",
  925.    &(local_td->instance->mediaPos));
  926.     if (DEBUG > 1)
  927. printf("Media Position = %fn",
  928.        local_td->instance->mediaPos);
  929.     if ((int) local_td->instance->mediaLength > 1) {
  930. lastmediapercent = local_td->instance->mediaPercent;
  931. local_td->instance->mediaPercent =
  932.     (int) ((local_td->instance->mediaPos * 100) /
  933.    local_td->instance->mediaLength);
  934. #ifdef GTK_ENABLED
  935. if (lastmediapercent != local_td->instance->mediaPercent) {
  936.     g_idle_add(gtkgui_drawMediaProgress,
  937.        local_td->instance);
  938.     g_idle_add(gtkgui_refreshbuttonstate,
  939.        local_td->instance);
  940. }
  941. #endif
  942.     }
  943. }
  944. pthread_testcancel();
  945. if (strstr(buffer, "ANS_PERCENT_POSITION") != 0) {
  946.     msg = strstr(buffer, "ANS_PERCENT_POSITION");
  947.     sscanf(msg, "ANS_PERCENT_POSITION=%i",
  948.    &(local_td->instance->mediaPercent));
  949.     if (local_td->instance->mediaPercent == 0) {
  950. if ((int) local_td->instance->mediaLength > 1)
  951.     lastmediapercent = local_td->instance->mediaPercent;
  952. local_td->instance->mediaPercent =
  953.     (int) ((local_td->instance->mediaPos * 100) /
  954.    local_td->instance->mediaLength);
  955. #ifdef GTK_ENABLED
  956. if (lastmediapercent != local_td->instance->mediaPercent) {
  957.     g_idle_add(gtkgui_drawMediaProgress,
  958.        local_td->instance);
  959.     g_idle_add(gtkgui_refreshbuttonstate,
  960.        local_td->instance);
  961. }
  962. #endif
  963.     }
  964.     if (DEBUG > 1)
  965. printf("Percent Played = %in",
  966.        local_td->instance->mediaPercent);
  967. }
  968. pthread_testcancel();
  969. // this is only needed for the retry code
  970. if (strstr(buffer, "rA:") != 0 || strstr(buffer, "rV:") != 0) {
  971.     //audio or video is playing
  972.     msg = strstr(buffer, "rA:");
  973.     if (msg != NULL) {
  974. sscanf(msg, "rA:%f", &(local_td->instance->mediaTime));
  975. if (DEBUG > 1)
  976.     printf("mediaTime = %fn",
  977.    local_td->instance->mediaTime);
  978. #ifdef GTK_ENABLED
  979. //              g_idle_add(gtkgui_draw, local_td->instance);
  980. #endif
  981.     } else {
  982. msg = strstr(buffer, "rV:");
  983. if (msg != NULL) {
  984.     sscanf(msg, "rV:%f",
  985.    &(local_td->instance->mediaTime));
  986.     if (DEBUG > 1)
  987. printf("mediaTime = %fn",
  988.        local_td->instance->mediaTime);
  989. }
  990.     }
  991.     pthread_cleanup_push((void (*)(void *))
  992.  pthread_mutex_unlock,
  993.  (void *) &(local_td->instance->
  994.     control_mutex));
  995.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  996.     if ((local_td->instance->js_state != JS_STATE_STOPPED)
  997. && (local_td->instance->js_state != JS_STATE_PAUSED))
  998. local_td->instance->js_state = JS_STATE_PLAYING;
  999.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1000.     pthread_cleanup_pop(0);
  1001.     pthread_testcancel();
  1002.     if (local_td->instance->paused == 0) {
  1003. pthread_cleanup_push((void (*)(void *))
  1004.      pthread_mutex_unlock,
  1005.      (void *) &(local_td->instance->
  1006. control_mutex));
  1007. pthread_mutex_lock(&(local_td->instance->control_mutex));
  1008. if ((int) local_td->instance->mediaLength > 1)
  1009.     sendCommand(local_td->instance, "get_time_pos");
  1010. if (local_td->instance->mediaLength > lastmedialength) {
  1011.     sendCommand(local_td->instance, "get_time_length");
  1012. } else {
  1013.     if (length_request_count < 10) {
  1014. sendCommand(local_td->instance, "get_time_length");
  1015. length_request_count++;
  1016.     }
  1017. }
  1018. pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1019. pthread_cleanup_pop(0);
  1020. #ifdef GTK_ENABLED
  1021. if (fsupdated == 0) {
  1022.     g_idle_add(gtkgui_updatefullscreen,
  1023.        local_td->instance);
  1024.     fsupdated = 1;
  1025. }
  1026. #endif
  1027.     }
  1028.     result->tryagain = TRYAGAIN_FALSE;
  1029. }
  1030. pthread_testcancel();
  1031. if (strstr(buffer, "Connect") != NULL) {
  1032.     snprintf(message, 1024, "%s", buffer);
  1033. #ifdef X_ENABLED
  1034.     DrawUI(local_td->instance->widget,
  1035.    local_td->instance, message, 0, -1);
  1036. #endif
  1037. #ifdef GTK_ENABLED
  1038.     snprintf(local_td->instance->lastmessage, 1024, "%s", message);
  1039.     g_idle_add(gtkgui_message, local_td->instance);
  1040. #endif
  1041.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  1042.     local_td->instance->js_state = JS_STATE_WAITING;
  1043.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1044. }
  1045. pthread_testcancel();
  1046. if (strstr(buffer, "Initiated") != NULL) {
  1047.     snprintf(message, 1024, "%s", buffer);
  1048. #ifdef X_ENABLED
  1049.     DrawUI(local_td->instance->widget,
  1050.    local_td->instance, message, 0, -1);
  1051. #endif
  1052. #ifdef GTK_ENABLED
  1053.     snprintf(local_td->instance->lastmessage, 1024, "%s", message);
  1054.     g_idle_add(gtkgui_message, local_td->instance);
  1055. #endif
  1056. }
  1057. pthread_testcancel();
  1058. if (strstr(buffer, "No stream found") != NULL) {
  1059.     snprintf(message, 1024, "%s", buffer);
  1060. #ifdef X_ENABLED
  1061.     DrawUI(local_td->instance->widget,
  1062.    local_td->instance, message, 0, -1);
  1063. #endif
  1064. #ifdef GTK_ENABLED
  1065.     snprintf(local_td->instance->lastmessage, 1024, "%s", message);
  1066.     g_idle_add(gtkgui_message, local_td->instance);
  1067. #endif
  1068.     result->tryagain = TRYAGAIN_FALSE;
  1069.     result->errorcode = ERROR_NO_STREAM;
  1070.     break;
  1071. }
  1072. pthread_testcancel();
  1073. if (strstr(buffer, "Example: download -playlist ") != NULL) {
  1074.     if (*maybeplaylist == 0) {
  1075. result->tryagain = TRYAGAIN_TRUE;
  1076. *maybeplaylist = 1;
  1077.     } else {
  1078. result->tryagain = TRYAGAIN_FALSE;
  1079. result->errorcode = ERROR_NOT_PLAYLIST;
  1080.     }
  1081.     break;
  1082. }
  1083.        pthread_testcancel();
  1084.        if (strstr(buffer, "Failed to open") != NULL) {
  1085.            if ((strstr(buffer, "/dev/rtc") == NULL) 
  1086.          && (strstr(buffer, "LIRC") == NULL) 
  1087.      && (strstr(buffer, "registry file") == NULL)) { // ignore RTC device and LIRC device failures
  1088.        if (local_td->instance->currentnode->mmsstream == 1) {
  1089.     if (DEBUG)
  1090.     printf("Trying fallbackn");
  1091.     result->tryagain = TRYAGAIN_FALLBACK;
  1092.     break;
  1093.        } else {
  1094.     result->tryagain = TRYAGAIN_FALSE;
  1095.     result->errorcode = ERROR_FILE_NOT_FOUND;
  1096.     break;
  1097.        }
  1098.    }
  1099. }
  1100. pthread_testcancel();
  1101. if (strstr(buffer, "Error while decoding") != NULL) {
  1102.     if (!isMms(local_url, local_td->instance->nomediacache)) {
  1103. if (DEBUG)
  1104.     printf("Resetting stream, 1 sec rewindn");
  1105. pthread_suspend(1000);
  1106. pthread_cleanup_push((void (*)(void *))
  1107.      pthread_mutex_unlock,
  1108.      (void *) &(local_td->instance->
  1109. control_mutex));
  1110. pthread_mutex_lock(&(local_td->instance->control_mutex));
  1111. sendCommand(local_td->instance, "seek -1 0n");
  1112. pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1113. pthread_cleanup_pop(0);
  1114.     }
  1115. }
  1116. pthread_testcancel();
  1117. if (strstr(buffer, "Quit") != NULL) {
  1118.     if (DEBUG)
  1119. printf("----player thread: breaking read loop - Quitn");
  1120.     local_td->instance->js_state = JS_STATE_UNDEFINED;
  1121.     result->tryagain = TRYAGAIN_FALSE;
  1122.     result->errorcode = ERROR_QUIT;
  1123.     break;
  1124. }
  1125. pthread_testcancel();
  1126. if (strstr
  1127.     (buffer,
  1128.      "download interrupted by signal 13 in module: demux_open") !=
  1129.     NULL) {
  1130.     if (DEBUG)
  1131. printf
  1132.     ("----player thread: breaking read loop - demux_openn");
  1133.     local_td->instance->js_state = JS_STATE_UNDEFINED;
  1134.     if (local_td->instance->rtsp_use_tcp == 1) {
  1135. local_td->instance->rtsp_use_tcp = 0;
  1136. result->tryagain = TRYAGAIN_TRUE;
  1137.     } else {
  1138. result->tryagain = TRYAGAIN_FALSE;
  1139. result->errorcode = ERROR_PLAYER_INTERRUPTED;
  1140.     }
  1141.     break;
  1142. }
  1143. pthread_testcancel();
  1144. // detect Quicktime file with old codec
  1145. if (strstr(buffer, "MOV: missing header (moov/cmov) chunk!") !=
  1146.     NULL) {
  1147.     if (DEBUG) {
  1148. printf
  1149.     ("----player thread: waiting to download entire movien");
  1150.     }
  1151.     result->tryagain = TRYAGAIN_TRUE;
  1152.     while (1) {
  1153. pthread_testcancel();
  1154. usleep(100);
  1155. pthread_testcancel();
  1156. pthread_mutex_lock(&(local_td->instance->control_mutex));
  1157. local_td->instance->js_state = JS_STATE_BUFFERING;
  1158. pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1159. pthread_mutex_lock(&(local_td->instance->playlist_mutex));
  1160. local_td->instance->state = STATE_DOWNLOADING;
  1161. if (local_list->retrieved == 1) {
  1162.     local_td->instance->state = STATE_PLAYING;
  1163.     pthread_mutex_lock(&
  1164.        (local_td->instance->
  1165. control_mutex));
  1166.     local_td->instance->js_state = JS_STATE_PLAYING;
  1167.     pthread_mutex_unlock(&
  1168.  (local_td->instance->
  1169.   control_mutex));
  1170.     pthread_mutex_unlock(&
  1171.  (local_td->instance->
  1172.   playlist_mutex));
  1173.     printf("----player thread: Movie downloadedn");
  1174.     break;
  1175. }
  1176. pthread_mutex_unlock(&
  1177.      (local_td->instance->playlist_mutex));
  1178.     }
  1179.     break;
  1180. }
  1181. pthread_testcancel();
  1182. if (strstr(buffer, "FPS not specified") != NULL) {
  1183.     result->tryagain = TRYAGAIN_TRUE;
  1184.     *usefps = 1;
  1185.     break;
  1186. }
  1187. pthread_testcancel();
  1188. if (strstr(buffer, "nomouseinput") != NULL) {
  1189.     *nomouseinput = 0;
  1190.     result->tryagain = TRYAGAIN_TRUE;
  1191.     break;
  1192. }
  1193. /* pthread_testcancel();
  1194. if (strstr(buffer, "Win32 LoadLibrary failed to load") != NULL) {
  1195.     if (local_td->instance->useragent != NULL) {
  1196. free(local_td->instance->useragent);
  1197. local_td->instance->useragent = NULL;
  1198. result->tryagain = TRYAGAIN_TRUE;
  1199. break;
  1200.     }
  1201. }
  1202. */
  1203. pthread_testcancel();
  1204. if (strstr(buffer, "Exiting") != NULL) {
  1205.     if (DEBUG)
  1206. printf
  1207.     ("----player thread: breaking read loop - Exitingn");
  1208.     if (local_td->instance->mediaPercent != 0) {
  1209. local_td->instance->mediaPercent = 100;
  1210. #ifdef GTK_ENABLED
  1211. g_idle_add(gtkgui_drawMediaProgress, local_td->instance);
  1212. #endif
  1213.     }
  1214.     result->tryagain = TRYAGAIN_FALSE;
  1215.     result->errorcode = ERROR_NO_ERROR;
  1216.     break;
  1217. }
  1218. pthread_testcancel();
  1219. // break out if download crashes
  1220. if (strstr(buffer, "interrupted") != NULL) {
  1221.     if (DEBUG)
  1222. printf
  1223.     ("----player thread: breaking read loop - interruptedn");
  1224.     if (strstr(buffer, "video_read_frame") != NULL) {
  1225. local_td->instance->js_state = JS_STATE_UNDEFINED;
  1226. if (local_td->instance->rtsp_use_tcp == 1) {
  1227.     local_td->instance->rtsp_use_tcp = 0;
  1228.     result->tryagain = TRYAGAIN_TRUE;
  1229. } else {
  1230. #ifdef GTK_ENABLED
  1231.     snprintf(local_td->instance->lastmessage, 1024,
  1232.      "Error: %s", buffer);
  1233.     g_idle_add(gtkgui_message, local_td->instance);
  1234. #endif
  1235.     result->tryagain = TRYAGAIN_FALSE;
  1236.     result->errorcode = ERROR_PLAYER_INTERRUPTED;
  1237. }
  1238.     }
  1239.     break;
  1240. }
  1241. pthread_testcancel();
  1242. if (strstr(buffer, "execv") != NULL) {
  1243.     if (DEBUG)
  1244. printf
  1245.     ("----player thread: breaking read loop - execv failedn");
  1246.     local_td->instance->js_state = JS_STATE_UNDEFINED;
  1247. #ifdef GTK_ENABLED
  1248.     snprintf(local_td->instance->lastmessage, 1024, "Error: %s %s",
  1249.      local_td->argv[0], buffer);
  1250.     g_idle_add(gtkgui_message, local_td->instance);
  1251. #endif
  1252.     result->tryagain = TRYAGAIN_FALSE;
  1253.     result->errorcode = ERROR_EXECV;
  1254.     break;
  1255. }
  1256. pthread_testcancel();
  1257. if (strstr(buffer, "explicit kill") != NULL) {
  1258.     if (DEBUG)
  1259. printf("----player thread: breaking read loop - killedn");
  1260.     result->tryagain = TRYAGAIN_FALSE;
  1261.     result->errorcode = ERROR_EXPLICIT_KILL;
  1262.     break;
  1263. }
  1264. pthread_testcancel();
  1265. if (strstr(buffer, "decoder is not supposed") != NULL) {
  1266.     if (DEBUG)
  1267. printf
  1268.     ("----player thread: breaking read loop - codec failuren");
  1269. #ifdef GTK_ENABLED
  1270.     snprintf(local_td->instance->lastmessage, 1024, "Error: %s %s",
  1271.      local_td->argv[0], buffer);
  1272.     g_idle_add(gtkgui_message, local_td->instance);
  1273. #endif
  1274.     result->tryagain = TRYAGAIN_FALSE;
  1275.     result->errorcode = ERROR_CODEC_FAILURE;
  1276.     break;
  1277. }
  1278. pthread_testcancel();
  1279. if (strstr(buffer, "Failed to decode frame") != NULL) {
  1280.     if (DEBUG)
  1281. printf
  1282.     ("----player thread: breaking read loop - codec failuren");
  1283. #ifdef GTK_ENABLED
  1284.     snprintf(local_td->instance->lastmessage, 1024, "Error: %s %s",
  1285.      local_td->argv[0], buffer);
  1286.     g_idle_add(gtkgui_message, local_td->instance);
  1287. #endif
  1288.     result->tryagain = TRYAGAIN_FALSE;
  1289.     result->errorcode = ERROR_CODEC_FAILURE;
  1290.     break;
  1291. }
  1292. pthread_testcancel();
  1293. /* commmented out to make BBC site work    
  1294. if (strstr(buffer, "everything done") != NULL) {
  1295.     if (DEBUG)
  1296. printf
  1297.     ("----player thread: breaking read loop - codec issuen");
  1298.     result->tryagain = TRYAGAIN_FALSE;
  1299.     result->errorcode = ERROR_CODEC_FAILURE;
  1300.     break;
  1301. }
  1302. */
  1303. assert(local_td->instance->player != NULL);
  1304.     } // end of READ LOOP
  1305.     if (DEBUG) {
  1306. printf("----player thread: tryagain = %dn", result->tryagain);
  1307.     }
  1308.     //we always return either true or false
  1309.     if (result->tryagain == TRYAGAIN_TRUE) {
  1310. result->retval = TRUE;
  1311.     }
  1312.     if (result->tryagain == TRYAGAIN_FALSE) {
  1313. result->retval = FALSE;
  1314.     }
  1315.     if (result->tryagain == TRYAGAIN_FALLBACK) {
  1316. //fallback to msst and then to http if we can
  1317. strlcpy(url_copy, local_url, 1023);
  1318. url_copy[1023] = '';
  1319. if (strncmp(local_url, "mms://", 6) == 0) {
  1320.     snprintf(local_url, 1023, "mmst://%s", url_copy + 6);
  1321.     result->retval = TRUE;
  1322. } else if (local_mmsstream &&
  1323.    strncmp(local_url, "mmst://", 7) == 0) {
  1324.     snprintf(local_url, 1023, "http://%s", url_copy + 7);
  1325.     result->retval = TRUE;
  1326. } else {
  1327.     result->retval = FALSE;
  1328. }
  1329.         if (DEBUG) 
  1330.      printf("TRYAGAIN_FALLBACK entered, new url is %sn", local_url);
  1331.     }
  1332. #ifdef GTK_ENABLED
  1333.     if (strstr(local_td->instance->lastmessage, "Error") == NULL) {
  1334. snprintf(local_td->instance->lastmessage, 1024, _("Stopped"));
  1335. g_idle_add(gtkgui_message, local_td->instance);
  1336.     }
  1337. #endif
  1338.     return result;
  1339. }
  1340. void *playPlaylist(void *td)
  1341. {
  1342.     PlayResult *result = NULL;
  1343.     FILE *playlist;
  1344.     char cmd[2048];
  1345.     char message[1024];
  1346.     char mmsplaylist[1024];
  1347.     char buffer[1024]; // scratch pad
  1348.     char *p; // pointer to find the ( in the callback
  1349.     int argc = 0, base_argc = 0;
  1350.     ThreadData *local_td;
  1351.     Node *local_list;
  1352.     char local_url[1024];
  1353.     int local_mmsstream;
  1354.     int i;
  1355.     int loop_single = 0;
  1356.     int loop_count;
  1357.     Node *node;
  1358.     int tryagain;
  1359.     int usefps;
  1360.     int nomouseinput;
  1361.     int maybeplaylist;
  1362.     int listempty;
  1363.     int lasterror = -1;
  1364.     local_td = (ThreadData *) td;
  1365.     local_list = local_td->list;
  1366.     if (local_td == NULL)
  1367. pthread_exit(0);
  1368.     if (DEBUG)
  1369. printf("----player thread: in playPlaylistn");
  1370.     pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
  1371.  (void *) &(local_td->instance->
  1372.     playlist_cond_mutex));
  1373.     pthread_mutex_lock(&(local_td->instance->playlist_cond_mutex));
  1374.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  1375.     local_td->instance->js_state = JS_STATE_BUFFERING;
  1376.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1377.     if (DEBUG)
  1378. printf
  1379.     ("----player thread: about to go to sleep, js_state = %d, state = %dn",
  1380.      local_td->instance->js_state, local_td->instance->state);
  1381.     if (local_td->instance->state < STATE_STARTED_PLAYER) {
  1382. // wait for playlist_complete_cond to be signalled
  1383. // this should happen when we have completed getting all the playlist elements
  1384. local_td->instance->state = STATE_WAITING_FOR_SIGNAL;
  1385. pthread_cond_wait(&(local_td->instance->playlist_complete_cond),
  1386.   &(local_td->instance->playlist_cond_mutex));
  1387. pthread_mutex_unlock(&(local_td->instance->playlist_cond_mutex));
  1388. pthread_testcancel();
  1389. sleep(1);
  1390. // playlist_cond_mutex should be unlocked now
  1391. if (local_td != NULL) {
  1392.     if (DEBUG > 1)
  1393. printf("local_td = %pn", local_td);
  1394.     if (local_td->instance != NULL) {
  1395. if (DEBUG > 1)
  1396.     printf("local_td->instance = %pn",
  1397.    local_td->instance);
  1398. pthread_testcancel();
  1399. local_td->instance->state = STATE_STARTED_PLAYER;
  1400. if (DEBUG)
  1401.     printf
  1402. ("---player thread: got wakeup signal, js_state = %d, state = %dn",
  1403.  local_td->instance->js_state,
  1404.  local_td->instance->state);
  1405.     } else {
  1406. if (DEBUG)
  1407.     printf
  1408. ("We were signalled to start but local_td->instance is NULL, should not happenn");
  1409. pthread_exit(0);
  1410.     }
  1411. } else {
  1412.     if (DEBUG)
  1413. printf
  1414.     ("We were signalled to start but local_td is NULL, should not happenn");
  1415.     pthread_exit(0);
  1416. }
  1417.     } else {
  1418. local_td->instance->threadsignaled = 1;
  1419.     }
  1420.     pthread_cleanup_pop(0);
  1421.     if (DEBUG)
  1422. printf("----player thread: playPlayList - waiting completen");
  1423.     pthread_testcancel();
  1424. #ifdef X_ENABLED
  1425.     DrawUI(local_td->w, local_td->instance, _("Loading Media..."), 0, -1);
  1426. #endif
  1427. #ifdef GTK_ENABLED
  1428.     snprintf(local_td->instance->lastmessage, 1024, _("Loading Media..."));
  1429.     g_idle_add(gtkgui_message, local_td->instance);
  1430. #endif
  1431.     memset(cmd, '', 1);
  1432.     i = 0;
  1433.     if (DEBUG)
  1434. printf("----player thread: building command stringn");
  1435.     pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
  1436.  (void *) &(local_td->instance->playlist_mutex));
  1437.     pthread_mutex_lock(&(local_td->instance->playlist_mutex));
  1438.     while (local_td->argv[argc] != NULL) {
  1439. if (DEBUG)
  1440.     printf("PLAY %i:%sn", i, local_td->argv[argc]);
  1441. argc++;
  1442.     }
  1443.     base_argc = argc;
  1444.     pthread_mutex_unlock(&(local_td->instance->playlist_mutex));
  1445.     pthread_cleanup_pop(0);
  1446.     //handle qtNext
  1447.     //shouldn't this be somewhere else?
  1448.     i = 0;
  1449.     while (local_td->instance->qtNext[i] != NULL) {
  1450. node = newNode();
  1451. if (DEBUG)
  1452.     printf("----player thread: adding %sn",
  1453.    local_td->instance->qtNext[i]);
  1454. strlcpy(node->url, local_td->instance->qtNext[i], 1024);
  1455. i++;
  1456. addToEnd(local_list, node);
  1457.     }
  1458.     // preview playlist
  1459.     local_list = local_td->list;
  1460.     if (DEBUG) {
  1461. while (local_list != NULL) {
  1462.     printf
  1463. ("----player thread:nlocal_list =  %pnPL URL: %snplay = %i, cancelled= %innext= %pn",
  1464.  local_list,
  1465.  local_list->url, local_list->play,
  1466.  local_list->cancelled, local_list->next);
  1467.     local_list = local_list->next;
  1468. }
  1469.     }
  1470.     // count playable items in the list, if playable =1 and loop = 1 then add a couple of args
  1471.     if (local_td->instance->loop >= 0) {
  1472. i = 0;
  1473. local_list = local_td->list;
  1474. while (local_list != NULL) {
  1475.     if (local_list->play)
  1476. i++;
  1477.     local_list = local_list->next;
  1478. }
  1479. if (DEBUG)
  1480.     printf
  1481. ("----player thread:nFound %i files to play and loop is truen",
  1482.  i);
  1483. // if the play count is exactly 1 then tell download to loop continuously and to use the same frame buffer (should eliminate blinking)
  1484. if (i == 1) {
  1485.     loop_single = 1;
  1486.     local_td->argv[argc++] = strdup("-loop");
  1487.     snprintf(buffer, 32, "%i", local_td->instance->loop);
  1488.     local_td->argv[argc++] = strdup(buffer);
  1489.     local_td->argv[argc++] = strdup("-fixed-vo");
  1490.     base_argc = argc;
  1491. }
  1492.     }
  1493.     loop_count = local_td->instance->loop;
  1494.     if (DEBUG)
  1495. printf("----player thread: set loop_count to %in",loop_count);
  1496.     
  1497.     while (1) {
  1498. if (DEBUG)
  1499.     printf("----player thread: entering loop. loop_count = %in",loop_count);
  1500. pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
  1501.      (void *) &(local_td->instance->
  1502. playlist_mutex));
  1503. pthread_mutex_lock(&(local_td->instance->playlist_mutex));
  1504. //find a node to play
  1505. if (DEBUG)
  1506.     printf("----player thread: looking for node to playn");
  1507. listempty = 0;
  1508. local_list = local_td->list;
  1509. while (local_list != NULL) {
  1510.     if (DEBUG)
  1511. printf("----player thread: play = %i played = %i fname = %sn",local_list->play,local_list->played, local_list->fname);
  1512.     if (local_list->play && !(local_list->played)) {
  1513. break;
  1514.     }
  1515.     local_list = local_list->next;
  1516. }
  1517. if (local_list == NULL) {
  1518.     //nothing to play: will exit, unless we have loop
  1519.     // the -- is to countdown the loop
  1520.     if (DEBUG)
  1521. printf("----player thread: local_list is NULL loop_count = %in",loop_count);
  1522.        if (local_td->instance->loop != 0)
  1523. loop_count--;
  1524.     if (DEBUG)
  1525. printf("----player thread: loop_count = %i loop_single = %in",loop_count,loop_single);
  1526.     
  1527.     // we're gonna reset the playlist, because we are going to play it again
  1528.     if ((loop_count > 0) && (loop_single == 0) || (local_td->instance->loop == 0)) {
  1529. local_list = local_td->list;
  1530. while (local_list != NULL) {
  1531.     if (local_list->play)
  1532. local_list->played = 0;
  1533.     local_list = local_list->next;
  1534. }
  1535. // rescan again, find the first playable item from the top of the list.
  1536. local_list = local_td->list;
  1537. while (local_list != NULL) {
  1538.     if (local_list->play && !(local_list->played)) {
  1539. break;
  1540.     }
  1541.     local_list = local_list->next;
  1542. }
  1543.     }
  1544. }
  1545. local_td->instance->currentnode = local_list;
  1546. if (local_list == NULL) {
  1547.     if (DEBUG)
  1548. printf("----player thread: nothing on the list to playn");
  1549.     listempty = 1;
  1550.     local_mmsstream = 0;
  1551.     // update MediaCompleteWithError Callback with PLAYLIST EMPTY but only if we have not played anything
  1552.     if ((local_td->instance->mediaCompleteWithErrorCallback !=
  1553.  NULL) && (lasterror == -1)) {
  1554. if (DEBUG)
  1555.     printf("mediaCompleteWithError(before) = %sn",
  1556.    local_td->instance->
  1557.    mediaCompleteWithErrorCallback);
  1558. strlcpy(message,
  1559. local_td->instance->mediaCompleteWithErrorCallback,
  1560. 1024);
  1561. p = index(message, '(');
  1562. if (p == NULL) {
  1563.     p = message + strlen(message);
  1564. }
  1565. *p = '';
  1566. snprintf(buffer, 1024, "%s(%i);", message,
  1567.  ERROR_PLAYLIST_EMPTY);
  1568. NPN_MemFree(local_td->instance->
  1569.     mediaCompleteWithErrorCallback);
  1570. local_td->instance->mediaCompleteWithErrorCallback =
  1571.     (char *) NPN_MemAlloc(strlen(buffer));
  1572. strlcpy(local_td->instance->mediaCompleteWithErrorCallback,
  1573. buffer, strlen(buffer));
  1574. if (DEBUG)
  1575.     printf("mediaCompleteWithError(after) = %sn",
  1576.    local_td->instance->
  1577.    mediaCompleteWithErrorCallback);
  1578.     }
  1579. } else {
  1580.     //we have a node to play
  1581.     if (DEBUG)
  1582. printf("----player thread: chose url %sn",
  1583.        local_list->url);
  1584.     listempty = 0;
  1585.     snprintf(local_url, 1024, "%s", local_list->url);
  1586.     local_url[1023] = '';
  1587.     local_mmsstream = local_list->mmsstream;
  1588. }
  1589. if (local_td->instance->rtsp_use_http
  1590.     && strncmp(local_url, "rtsp://", 7) == 0)
  1591.     memcpy(local_url, "http://", 7);
  1592. pthread_mutex_unlock(&(local_td->instance->playlist_mutex));
  1593. pthread_cleanup_pop(0);
  1594. if (listempty == 1)
  1595.     break;
  1596. pthread_testcancel();
  1597. usefps = 0;
  1598. nomouseinput = local_td->instance->nomouseinput;
  1599. maybeplaylist = 0;
  1600. do {
  1601.     pthread_testcancel();
  1602.     tryagain = 0;
  1603.     argc = base_argc;
  1604.     while (argc < 50) {
  1605. if (local_td->argv[argc] != NULL)
  1606.     free(local_td->argv[argc]);
  1607. local_td->argv[argc++] = NULL;
  1608.     }
  1609.     argc = base_argc;
  1610.     unEscapeXML(local_url);
  1611.     if (DEBUG)
  1612. printf("----player thread: playing url: %sn", local_url);
  1613.     snprintf(message, 1024, _("Playing %s"), local_list->url);
  1614. #ifdef X_ENABLED
  1615.     DrawUI(local_td->w, local_td->instance, message, 0, -1);
  1616. #endif
  1617. #ifdef GTK_ENABLED
  1618.     snprintf(local_td->instance->lastmessage, 1024, "%s", message);
  1619.     g_idle_add(gtkgui_message, local_td->instance);
  1620. #endif
  1621.     pthread_cleanup_push((void (*)(void *))
  1622.  pthread_mutex_unlock,
  1623.  (void *) &(local_td->instance->
  1624.     playlist_mutex));
  1625.     pthread_mutex_lock(&(local_td->instance->playlist_mutex));
  1626.     // for rtsp streams we need to specify FPS
  1627.     if (usefps == 1) {
  1628. if (strncmp(local_list->url, "rtsp", 4) == 0) {
  1629.     local_td->argv[argc++] = strdup("-fps");
  1630.     local_td->argv[argc++] = strdup("30");
  1631. }
  1632. usefps = 0;
  1633.     }
  1634.     if (local_td->instance->rtsp_use_tcp == 1) {
  1635. if (strncmp(local_list->url, "rtsp", 4) == 0) {
  1636.     snprintf(buffer, 1024, "-rtsp-stream-over-tcp");
  1637.     local_td->argv[argc++] = strdup(buffer);
  1638. }
  1639.     }
  1640.     if (local_td->instance->useragent) {
  1641. snprintf(buffer, 1024, "-user-agent");
  1642. local_td->argv[argc++] = strdup(buffer);
  1643. snprintf(buffer, 1024, "%s",
  1644.  local_td->instance->useragent);
  1645. local_td->argv[argc++] = strdup(buffer);
  1646.     }
  1647.     if (nomouseinput) {
  1648. local_td->argv[argc++] = strdup("-nomouseinput");
  1649. //          } else {
  1650. //              nomouseinput = 0;
  1651.     }
  1652.     if (local_td->instance->starttime > 0) {
  1653. local_td->argv[argc++] = strdup("-ss");
  1654. snprintf(message, 1024, "%li",
  1655.  local_td->instance->starttime);
  1656. local_td->argv[argc++] = strdup(message);
  1657. local_td->instance->starttime = 0;
  1658.     }
  1659.     if (local_td->instance != NULL)
  1660. local_td->instance->mmsstream = local_list->mmsstream;
  1661.     if (local_list->mmsstream) {
  1662. #ifdef GTK_ENABLED
  1663. g_idle_add(gtkgui_updatebuttons, local_td->instance);
  1664. #endif
  1665. local_td->argv[argc++] = strdup("-cache");
  1666. snprintf(message, 1024, "%i",
  1667.  local_td->instance->cachesize);
  1668. local_td->argv[argc++] = strdup(message);
  1669.         if (DEBUG)
  1670. printf("pre local_url is %sn",local_url);
  1671. if (result != NULL) {
  1672. if (result->tryagain != TRYAGAIN_FALLBACK) {
  1673.     // mmsToHttp(local_url, local_list->url);
  1674. }
  1675. } else {
  1676.     if (DEBUG)
  1677. printf("result = nulln");
  1678.     // mmsToHttp(local_url, local_list->url);
  1679. }
  1680.         if (DEBUG)
  1681. printf("local_url is %sn",local_url);
  1682. local_td->argv[argc++] = strdup(local_url);
  1683. if (local_td->instance->keep_download) {
  1684.     snprintf(mmsplaylist, sizeof(mmsplaylist),
  1685.      "%s/playlist",
  1686.      local_td->instance->download_dir);
  1687.     playlist = fopen(mmsplaylist, "a");
  1688.     if (playlist != NULL) {
  1689. fprintf(playlist, "%sn", local_url);
  1690. fclose(playlist);
  1691.     }
  1692. }
  1693.     } else {
  1694. if (strlen(local_list->fname) == 0) {
  1695.     local_td->argv[argc++] = strdup("-cache");
  1696.     snprintf(message, 1024, "%i",
  1697.      local_td->instance->cachesize);
  1698.     local_td->argv[argc++] = strdup(message);
  1699.     if (local_list->playlist == 1 || maybeplaylist != 0) {
  1700. local_td->argv[argc++] = strdup("-playlist");
  1701.     }
  1702.     local_td->argv[argc++] = strdup(local_url);
  1703. } else {
  1704.     local_td->argv[argc++] = strdup("-nocache");
  1705.     if (local_list->playlist == 1 || maybeplaylist != 0)
  1706. local_td->argv[argc++] = strdup("-playlist");
  1707.     local_td->argv[argc++] = strdup(local_list->fname);
  1708. }
  1709.     }
  1710.     if (DEBUG) {
  1711. printf("----player thread: URL: %sn", local_url);
  1712.     }
  1713.     pthread_mutex_unlock(&(local_td->instance->playlist_mutex));
  1714.     pthread_cleanup_pop(0);
  1715.     pthread_testcancel();
  1716.     //start up download
  1717.     pthread_cleanup_push((void (*)(void *))
  1718.  pthread_mutex_unlock,
  1719.  (void *) &(local_td->instance->
  1720.     control_mutex));
  1721.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  1722.     local_td->instance->player =
  1723. mypopen(local_td->argv, &(local_td->instance->pid),
  1724. &(local_td->instance->control),
  1725. local_td->instance);
  1726.     if (local_td->instance->player != NULL) {
  1727. local_td->instance->js_state = JS_STATE_PLAYING;
  1728.     }
  1729.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1730.     pthread_cleanup_pop(0);
  1731.     if (result != NULL) {
  1732. lasterror = result->errorcode;
  1733. NPN_MemFree(result);
  1734. result = NULL;
  1735.     }
  1736.     local_td->instance->state = STATE_PLAYING;
  1737.     if (local_td->instance->player != NULL) {
  1738. assert(local_td->instance->control > 0);
  1739. // reset media counters
  1740. local_td->instance->mediaLength = 0.0;
  1741. local_td->instance->mediaPercent = 0;
  1742. result =
  1743.     playNode(local_td, local_list, local_url,
  1744.      local_mmsstream, &usefps, &nomouseinput,
  1745.      &maybeplaylist);
  1746. pthread_mutex_lock(&(local_td->instance->control_mutex));
  1747. local_td->instance->js_state = JS_STATE_TRANSITIONING;
  1748. pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1749. if (DEBUG)
  1750.     printf
  1751. ("----player thread: playNode returned = %dn",
  1752.  result->retval);
  1753. pthread_testcancel();
  1754. assert(local_list != NULL);
  1755. local_td->instance->mediaPercent = 0;
  1756. #ifdef GTK_ENABLED
  1757. g_idle_add(gtkgui_drawMediaProgress, local_td->instance);
  1758. #endif
  1759. if (local_td->instance->targetplayer == 0) {
  1760.     local_td->instance->movie_height = 1;
  1761.     local_td->instance->movie_width = 1;
  1762. #ifdef GTK_ENABLED
  1763.     g_idle_add(gtkgui_resize, local_td->instance);
  1764.     g_idle_add(gtkgui_draw, local_td->instance);
  1765. #endif
  1766. }
  1767. // this cancels the download of this media
  1768. // if there are more than 1, saves bandwidth
  1769. // also prevents us from playing it again
  1770. pthread_mutex_lock(&(local_td->instance->playlist_mutex));
  1771. if (result->retval == 0) {
  1772.     if (local_list->mmsstream
  1773. && (result->errorcode == ERROR_QUIT)) {
  1774. local_list->played = 0;
  1775.     } else {
  1776. local_list->played = 1;
  1777.     }
  1778. }
  1779. pthread_mutex_unlock(&
  1780.      (local_td->instance->playlist_mutex));
  1781. assert(local_td->instance != NULL);
  1782. if (DEBUG)
  1783.     printf("----player thread: played = %i - %sn",local_list->played,local_list->fname);
  1784. //close the pipes to download
  1785. assert(local_td->instance->control > 0);
  1786. close(local_td->instance->control);
  1787. local_td->instance->control = -1;
  1788. assert(local_td->instance->player != NULL);
  1789. fclose(local_td->instance->player);
  1790. local_td->instance->player = NULL;
  1791. if (DEBUG)
  1792.     printf("----player thread: close donen");
  1793. local_td->instance->state = STATE_PLAYLIST_NEXT;
  1794.     }
  1795.     // update MediaCompleteWithError Callback
  1796.     if (local_td->instance->mediaCompleteWithErrorCallback != NULL) {
  1797. if (DEBUG)
  1798.     printf("mediaCompleteWithError(before) = %sn",
  1799.    local_td->instance->
  1800.    mediaCompleteWithErrorCallback);
  1801. strlcpy(message,
  1802. local_td->instance->mediaCompleteWithErrorCallback,
  1803. 1024);
  1804. p = index(message, '(');
  1805. if (p == NULL) {
  1806.     p = message + strlen(message);
  1807. }
  1808. *p = '';
  1809. snprintf(buffer, 1024, "%s(%i);", message,
  1810.  result->errorcode);
  1811. NPN_MemFree(local_td->instance->
  1812.     mediaCompleteWithErrorCallback);
  1813. local_td->instance->mediaCompleteWithErrorCallback =
  1814.     (char *) NPN_MemAlloc(strlen(buffer));
  1815. strlcpy(local_td->instance->mediaCompleteWithErrorCallback,
  1816. buffer, strlen(buffer));
  1817. if (DEBUG)
  1818.     printf("mediaCompleteWithError(after) = %sn",
  1819.    local_td->instance->
  1820.    mediaCompleteWithErrorCallback);
  1821.     }
  1822. } while (result->retval);
  1823. // if we are in a list of mmsstreams, then we need to stop 
  1824. if (DEBUG)
  1825.     printf("mmsstream = %i errorcode = %i n",
  1826.    local_list->mmsstream, result->errorcode);
  1827. if (local_list->mmsstream && (result->errorcode == ERROR_QUIT)) {
  1828.     if (DEBUG)
  1829. printf("breaking out of next item loopn");
  1830.     break;
  1831. }
  1832. local_td->instance->currentnode = NULL;
  1833. //if we get here, either the control pipes are closed
  1834. //  or they were never opened in the first place
  1835. if (DEBUG) {
  1836.     printf("----player thread: transitioning to next itemn");
  1837. }
  1838. pthread_mutex_lock(&(local_td->instance->control_mutex));
  1839. local_td->instance->js_state = JS_STATE_TRANSITIONING;
  1840. pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1841. pthread_testcancel();
  1842. assert(local_td != NULL);
  1843. assert(local_td->instance != NULL);
  1844. pthread_testcancel();
  1845. // if we have media type that changes from video to audio 
  1846. // in X mode this will take care of that situation
  1847. local_td->instance->noredraw = 0;
  1848. /*
  1849.    assert(local_td->instance->state != STATE_PLAY_CANCELLED);
  1850.  */
  1851.     } // end main while loop
  1852.     if (DEBUG) {
  1853. printf("----player thread: nothing to playn");
  1854.     }
  1855. #ifdef GTK_ENABLED
  1856.     g_idle_add(gtkgui_stop, local_td->instance);
  1857.     // call media complete when we are done with the playlist
  1858.     if (local_td->instance->mediaCompleteCallback != NULL) {
  1859. g_idle_add(mediacallback, local_td->instance);
  1860.     }
  1861. #endif
  1862. #ifdef X_ENABLED
  1863.     if (local_td->instance->mediaCompleteCallback != NULL)
  1864. NPN_GetURL(local_td->instance->mInstance,
  1865.    local_td->instance->mediaCompleteCallback, "_self");
  1866.     if (local_td->instance->mediaCompleteWithErrorCallback != NULL)
  1867. NPN_GetURL(local_td->instance->mInstance,
  1868.    local_td->instance->mediaCompleteWithErrorCallback,
  1869.    "_self");
  1870. #endif
  1871. #ifdef GTK2_ENABLED
  1872.     if (GTK_IS_WIDGET(local_td->instance->src_event_box)) {
  1873. gtk_widget_show(local_td->instance->src_event_box);
  1874.     }
  1875. #endif
  1876.     if (DEBUG) {
  1877. printf("----player thread: callbacks completen");
  1878.     }
  1879.     // free all the data (command line parameters) that is used to start download
  1880.     pthread_mutex_lock(&(local_td->instance->control_mutex));
  1881.     local_td->instance->js_state = JS_STATE_UNDEFINED;
  1882.     argc = base_argc;
  1883.     while (argc < 50) {
  1884. if (local_td->argv[argc] != NULL)
  1885.     free(local_td->argv[argc]);
  1886. local_td->argv[argc++] = NULL;
  1887.     }
  1888.     pthread_mutex_unlock(&(local_td->instance->control_mutex));
  1889.     pthread_mutex_unlock(&(local_td->instance->playlist_cond_mutex));
  1890.     // since thread is dead, reset thread state variables.
  1891.     local_td->instance->threadsetup = 0;
  1892.     local_td->instance->threadlaunched = 0;
  1893.     local_td->instance->threadsignaled = 0;
  1894.     //once we get here, the thread is only allowed to access stack
  1895.     // variables and then exit (since another player thread may have
  1896.     // been started at this time).    
  1897.     if (DEBUG) {
  1898. printf("----player thread: normal exitn");
  1899.     }
  1900.     //pthread_exit(0);
  1901.     return NULL;
  1902. }