~ubuntu-branches/ubuntu/trusty/parole/trusty-proposed

« back to all changes in this revision

Viewing changes to browser-plugin/plugin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Yves-Alexis Perez
  • Date: 2010-04-28 21:42:11 UTC
  • Revision ID: james.westby@ubuntu.com-20100428214211-i7olyr9ch8tnpnaf
Tags: upstream-0.2.0.2
ImportĀ upstreamĀ versionĀ 0.2.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 * Alternatively, the contents of this file may be used under the terms of
 
25
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
26
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
27
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
28
 * of those above. If you wish to allow use of your version of this file only
 
29
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
30
 * use your version of this file under the terms of the MPL, indicate your
 
31
 * decision by deleting the provisions above and replace them with the notice
 
32
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
33
 * the provisions above, a recipient may use your version of this file under
 
34
 * the terms of any one of the MPL, the GPL or the LGPL.
 
35
 *
 
36
 * ***** END LICENSE BLOCK ***** */
 
37
 
 
38
#include "plugin.h"
 
39
#include "plugin_setup.h"
 
40
#include "plugin_types.h"
 
41
 
 
42
static int32_t STREAMBUFSIZE = 0x0FFFFFFF;
 
43
 
 
44
NPError NS_PluginInitialize();
 
45
void NS_PluginShutdown();
 
46
NPError NS_PluginGetValue(NPPVariable aVariable, void *aValue);
 
47
 
 
48
//////////////////////////////////////
 
49
//
 
50
// general initialization and shutdown
 
51
//
 
52
NPError NS_PluginInitialize()
 
53
{
 
54
    return NPERR_NO_ERROR;
 
55
}
 
56
 
 
57
void NS_PluginShutdown()
 
58
{
 
59
}
 
60
 
 
61
// get values per plugin
 
62
NPError NS_PluginGetValue(NPPVariable aVariable, void *aValue)
 
63
{
 
64
    return PluginGetValue(aVariable, aValue);
 
65
}
 
66
 
 
67
 
 
68
//////////////////////
 
69
/*
 
70
 * Callbacks.
 
71
 */
 
72
static gboolean
 
73
parole_plugin_ping (gpointer data)
 
74
{
 
75
    CPlugin *plugin = (CPlugin*)data;
 
76
    
 
77
    dbus_g_proxy_call_no_reply  (plugin->proxy, "Ping",
 
78
                                 G_TYPE_INVALID,
 
79
                                 G_TYPE_INVALID);
 
80
    return TRUE;
 
81
}
 
82
 
 
83
static void
 
84
parole_plugin_player_exiting_cb (DBusGProxy *proxy, gpointer data)
 
85
{
 
86
    //g_debug ("Player exiting");
 
87
    
 
88
    CPlugin *plugin = (CPlugin*)data;
 
89
    
 
90
    plugin->player_exited = TRUE;
 
91
    if ( plugin->ping_id != 0 )
 
92
        g_source_remove (plugin->ping_id);
 
93
}
 
94
 
 
95
static void
 
96
parole_plugin_player_ready_cb (DBusGProxy *proxy, gpointer data)
 
97
{
 
98
    //g_debug ("Player ready");
 
99
    
 
100
    CPlugin *plugin = (CPlugin*)data;
 
101
    
 
102
    plugin->player_ready = TRUE;
 
103
    
 
104
    if ( plugin->ping_id == 0 )
 
105
    {
 
106
        plugin->ping_id = g_timeout_add_seconds (10, (GSourceFunc) parole_plugin_ping, plugin);
 
107
    }
 
108
    
 
109
    
 
110
}
 
111
 
 
112
////////////////////////////////////////
 
113
//
 
114
// CPlugin class implementation
 
115
//
 
116
CPlugin::CPlugin (NPP pNPInstance)
 
117
{
 
118
    //g_debug ("Constructor");
 
119
    
 
120
    mInstance = pNPInstance;
 
121
    mInitialized = TRUE;
 
122
    
 
123
    GError *error = NULL;
 
124
    
 
125
    proxy          = NULL;
 
126
    murl           = NULL;
 
127
    cache          = NULL;
 
128
    tmp_file       = NULL;
 
129
    
 
130
    child_pid      = 0;
 
131
    
 
132
    window_set     = FALSE;
 
133
    is_playlist    = FALSE;
 
134
    checked        = FALSE;
 
135
    player_ready   = FALSE;
 
136
    player_started = FALSE;
 
137
    player_spawned = FALSE;
 
138
    player_exited  = FALSE;
 
139
    player_playing = FALSE;
 
140
    ping_id        = 0;
 
141
    
 
142
    bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
 
143
    
 
144
    if ( error )
 
145
    {
 
146
        g_warning ("Failed to get session bus %s", error->message);
 
147
        g_error_free (error);
 
148
    }
 
149
}
 
150
 
 
151
CPlugin::~CPlugin()
 
152
{
 
153
    if ( ping_id != 0 )
 
154
        g_source_remove (ping_id);
 
155
    
 
156
    StopPlayer ();
 
157
    
 
158
    if ( tmp_file )
 
159
    {
 
160
        remove (tmp_file);
 
161
        g_free (tmp_file);
 
162
    }
 
163
    
 
164
    if ( cache )
 
165
        fclose (cache);
 
166
    
 
167
    if ( bus )
 
168
        dbus_g_connection_unref (bus);
 
169
 
 
170
    if ( murl )
 
171
        g_free (murl);
 
172
 
 
173
    if ( proxy )
 
174
    {
 
175
        dbus_g_proxy_disconnect_signal (proxy, "Exiting",
 
176
                                        G_CALLBACK (parole_plugin_player_exiting_cb), this);
 
177
                                     
 
178
        dbus_g_proxy_disconnect_signal (proxy, "Ready",
 
179
                                        G_CALLBACK (parole_plugin_player_ready_cb), this);
 
180
                                       
 
181
        g_object_unref (proxy);
 
182
    }
 
183
    
 
184
    mInstance = NULL;
 
185
}
 
186
 
 
187
NPBool CPlugin::init(NPWindow * pNPWindow)
 
188
{
 
189
    if (pNPWindow == NULL)
 
190
        return FALSE;
 
191
 
 
192
    mInitialized = TRUE;
 
193
 
 
194
    return mInitialized;
 
195
}
 
196
 
 
197
void CPlugin::SendPlay (const gchar *url)
 
198
{
 
199
    GError *error = NULL;
 
200
    g_return_if_fail (proxy);
 
201
    
 
202
    //g_debug ("Sending play request of stream %s", url);
 
203
    dbus_g_proxy_call (proxy, "PlayUrl", &error,
 
204
                       G_TYPE_STRING, url,
 
205
                       G_TYPE_INVALID,
 
206
                       G_TYPE_INVALID);
 
207
                       
 
208
    player_playing = TRUE;
 
209
    
 
210
    if ( error )
 
211
    {
 
212
        g_critical ("Failed to play stream %s : %s", url, error->message);
 
213
        g_error_free (error);
 
214
        player_playing = FALSE;
 
215
    }
 
216
}
 
217
 
 
218
void
 
219
CPlugin::SendList (const gchar *filename)
 
220
{
 
221
    GError *error = NULL;
 
222
    g_return_if_fail (proxy);
 
223
    
 
224
    //g_debug ("Sending play request of playlist %s", filename);
 
225
    
 
226
    dbus_g_proxy_call (proxy, "PlayList", &error,
 
227
                       G_TYPE_STRING, filename,
 
228
                       G_TYPE_INVALID,
 
229
                       G_TYPE_INVALID);
 
230
                       
 
231
    player_playing = TRUE;
 
232
    
 
233
    if ( error )
 
234
    {
 
235
        g_critical ("Failed to play list %s : %s", filename, error->message);
 
236
        g_error_free (error);
 
237
        player_playing = FALSE;
 
238
    }
 
239
}
 
240
 
 
241
NPError CPlugin::RunPlayer ()
 
242
{
 
243
    gchar *command[4];
 
244
    gchar *socket;
 
245
    gchar *app;
 
246
    GError *error = NULL;
 
247
 
 
248
    socket = g_strdup_printf ("%ld", window);
 
249
    
 
250
    app = g_build_filename (LIBEXECDIR, "parole-media-plugin", NULL);
 
251
 
 
252
    command[0] = app;
 
253
    command[1] = (gchar *)"--socket-id";
 
254
    command[2] = socket;
 
255
    command[3] = NULL;
 
256
 
 
257
    if ( !g_spawn_async (NULL, 
 
258
                         command,
 
259
                         NULL,
 
260
                         (GSpawnFlags) 0,
 
261
                         NULL, NULL,
 
262
                         &child_pid, 
 
263
                         &error) )
 
264
    {
 
265
        g_critical ("Failed to spawn command : %s", error->message);
 
266
        g_error_free (error);
 
267
        return NPERR_GENERIC_ERROR;
 
268
    }
 
269
 
 
270
    player_spawned = TRUE;
 
271
 
 
272
    g_free (socket);
 
273
    g_free (app);
 
274
 
 
275
    GetProxy ();
 
276
 
 
277
    return NPERR_NO_ERROR;
 
278
}    
 
279
 
 
280
void CPlugin::GetProxy ()
 
281
{
 
282
    gchar *dbus_name;
 
283
    
 
284
    g_return_if_fail (bus != NULL);
 
285
    
 
286
    dbus_name = g_strdup_printf ("org.Parole.Media.Plugin%ld", window);
 
287
    
 
288
    proxy = dbus_g_proxy_new_for_name (bus, 
 
289
                                       dbus_name,
 
290
                                       "/org/Parole/Media/Plugin",
 
291
                                       "org.Parole.Media.Plugin");
 
292
    
 
293
    if ( proxy == NULL) 
 
294
        g_critical ("Unable to create proxy for %s", dbus_name);
 
295
    else
 
296
    {
 
297
        dbus_g_proxy_add_signal (proxy, "Error", G_TYPE_INVALID);
 
298
        dbus_g_proxy_add_signal (proxy, "Finished", G_TYPE_INVALID);
 
299
        dbus_g_proxy_add_signal (proxy, "Exiting", G_TYPE_INVALID);
 
300
        dbus_g_proxy_add_signal (proxy, "Ready", G_TYPE_INVALID);
 
301
        
 
302
        dbus_g_proxy_connect_signal (proxy, "Exiting",
 
303
                                     G_CALLBACK (parole_plugin_player_exiting_cb), this, NULL);
 
304
                                     
 
305
        dbus_g_proxy_connect_signal (proxy, "Ready",
 
306
                                     G_CALLBACK (parole_plugin_player_ready_cb), this, NULL);
 
307
    }
 
308
}
 
309
 
 
310
NPError CPlugin::SetWindow(NPWindow * aWindow)
 
311
{
 
312
    //g_debug ("SetWindow");
 
313
    
 
314
    if ( aWindow == NULL )
 
315
        return NPERR_NO_ERROR;
 
316
    
 
317
    if ( window_set == FALSE)
 
318
    {
 
319
        window = (Window) aWindow->window;
 
320
        window_set = TRUE;
 
321
        return RunPlayer ();
 
322
    }
 
323
    
 
324
    return NPERR_NO_ERROR;
 
325
}
 
326
 
 
327
void CPlugin::shut()
 
328
{
 
329
    //g_debug ("Shut");
 
330
    
 
331
    if ( player_ready )
 
332
    {
 
333
        //g_debug ("Sending Stop signal");
 
334
        dbus_g_proxy_call_no_reply (proxy, "Stop",
 
335
                                    G_TYPE_INVALID,
 
336
                                    G_TYPE_INVALID);
 
337
 
 
338
    }
 
339
}
 
340
 
 
341
NPBool CPlugin::isInitialized()
 
342
{
 
343
    return mInitialized;
 
344
}
 
345
 
 
346
void CPlugin::StopPlayer ()
 
347
{
 
348
    if ( player_spawned )
 
349
    {
 
350
        if ( player_ready )
 
351
        {
 
352
            gint num_tries = 0;
 
353
            
 
354
            do
 
355
            {
 
356
                GError *error = NULL;
 
357
                //g_debug ("Sending Quit message");
 
358
                dbus_g_proxy_call (proxy, "Quit", &error,
 
359
                                   G_TYPE_INVALID,
 
360
                                   G_TYPE_INVALID);
 
361
                    
 
362
                /*
 
363
                 * This might happen if the browser unload the plugin quickly
 
364
                 * while the process didn't get the dbus name.
 
365
                 */
 
366
                if ( error )
 
367
                {
 
368
#ifdef DEBUG
 
369
                    //g_debug ("Failed to stop the backend via D-Bus %s", error->message);
 
370
#endif
 
371
                    if ( g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NO_REPLY ) ||
 
372
                         g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN) )
 
373
                    {
 
374
                        g_error_free (error);
 
375
                        g_main_context_iteration(NULL, FALSE);
 
376
                        g_usleep (100000);
 
377
                        num_tries++;
 
378
                        //g_debug ("No reply, probably not ready, re-trying");
 
379
                    }
 
380
                    else
 
381
                        break;
 
382
                }
 
383
                else
 
384
                    break;
 
385
                
 
386
            } while (num_tries  < 4  && player_exited != TRUE);
 
387
        }
 
388
        else
 
389
        {
 
390
            char cmd[128];
 
391
            g_snprintf (cmd, 128, "kill -9 %d", child_pid);
 
392
            g_spawn_command_line_async (cmd, NULL);
 
393
        }
 
394
    }
 
395
}
 
396
 
 
397
NPError CPlugin::NewStream (NPMIMEType type, NPStream * stream, NPBool seekable, uint16_t * stype)
 
398
{
 
399
    if ( murl == NULL )
 
400
    {
 
401
        murl = g_strdup (stream->url);
 
402
        //g_debug ("NewStream=%s", murl);
 
403
    }
 
404
    
 
405
    return NPERR_NO_ERROR;
 
406
}
 
407
 
 
408
NPError CPlugin::DestroyStream(NPStream * stream, NPError reason)
 
409
{
 
410
    /*
 
411
    g_debug ("DestroyStream reason = %i for %s\n", reason, stream->url);
 
412
    
 
413
    if ( reason == NPRES_DONE )
 
414
    {
 
415
        g_debug ("NPRES_DONE");
 
416
    }
 
417
    else if ( reason == NPRES_USER_BREAK )
 
418
    {
 
419
        g_debug ("NPRES_USER_BREAK");
 
420
        
 
421
    }
 
422
    else if ( reason == NPRES_NETWORK_ERR )
 
423
    {
 
424
        g_debug ("NPRES_NETWORK_ERR");
 
425
    }
 
426
    */
 
427
    return NPERR_NO_ERROR;
 
428
}
 
429
 
 
430
void CPlugin::URLNotify (const char *url, NPReason reason, void *notifyData)
 
431
{
 
432
    //g_debug ("Url notify %s reason %i", url, reason);
 
433
}
 
434
 
 
435
void CPlugin::StreamAsFile (NPStream * stream, const char *fname)
 
436
{
 
437
    //g_debug ("StreamAsFile url=%s fname=%s", stream->url, fname);
 
438
}
 
439
 
 
440
int32_t CPlugin::WriteReady (NPStream * stream)
 
441
{
 
442
    //g_debug ("WriteReady url=%s", stream->url);
 
443
    
 
444
    if ( mode != NP_FULL && mode != NP_EMBED )
 
445
    {
 
446
        NPN_DestroyStream (mInstance, stream, NPRES_DONE);
 
447
        return -1;
 
448
    }
 
449
    
 
450
    return  player_ready ? STREAMBUFSIZE  : 0;
 
451
}
 
452
    
 
453
int32_t CPlugin::Write (NPStream * stream, int32_t offset, int32_t len, void *buffer)
 
454
{
 
455
    static int32_t wrotebytes = -1;
 
456
    
 
457
    if ( checked == FALSE )
 
458
    {
 
459
        gchar c;
 
460
        
 
461
        /* Check if the url is a playlist */
 
462
        //g_debug ("Checking if stream is a playlist");
 
463
        is_playlist = TRUE;
 
464
        char *data = (char *) buffer;
 
465
        for ( int32_t i = 0; i < len; i++)
 
466
        {
 
467
            c = data[i];
 
468
            if ( g_ascii_iscntrl (c) && !g_ascii_isspace (c) )
 
469
            {
 
470
                is_playlist = FALSE;
 
471
                break;
 
472
            }
 
473
        }
 
474
        checked = TRUE;
 
475
    }
 
476
 
 
477
    if ( is_playlist )
 
478
    {
 
479
        tmp_file = g_strdup_printf ("/tmp/parole-plugin-player-%ld", window);
 
480
            
 
481
        if (cache == NULL)
 
482
        {
 
483
            cache = fopen (tmp_file, "w");
 
484
            g_warn_if_fail (cache != NULL);
 
485
        }
 
486
        
 
487
        if ( cache )
 
488
        {
 
489
            fseek (cache, offset, SEEK_SET);
 
490
            wrotebytes += fwrite (buffer, 1, MAX (len, STREAMBUFSIZE), cache);
 
491
            //g_debug ("Wrotebytes=%d offset=%d data=%s", wrotebytes, offset, (gchar*)buffer);
 
492
        }
 
493
        
 
494
        if ( wrotebytes >= 0 )
 
495
        {
 
496
            fclose (cache);
 
497
            cache = NULL;
 
498
            
 
499
            SendList (tmp_file);
 
500
        }
 
501
    }
 
502
    else if ( player_ready && player_playing == FALSE  )
 
503
    {
 
504
        SendPlay (stream->url);
 
505
        return len;
 
506
    }
 
507
    
 
508
    return wrotebytes;
 
509
}