45
45
#include <bluetooth/sdp_lib.h>
47
47
//FIXME we shouldn't use the video widget directly
48
#include "bacon-video-widget.h"
48
#include "backend/bacon-video-widget.h"
49
49
#include "totem-plugin.h"
56
56
#define TOTEM_IS_BEMUSED_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TOTEM_TYPE_BEMUSED_PLUGIN))
57
57
#define TOTEM_BEMUSED_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TOTEM_TYPE_BEMUSED_PLUGIN, TotemBemusedPluginClass))
63
60
TotemObject *totem;
64
61
BaconVideoWidget *bvw;
65
62
guint server_watch_id;
66
63
guint client_watch_id;
67
64
GIOChannel *server_iochan, *client_iochan;
68
65
sdp_session_t *sdp_session;
73
TotemPluginClass parent_class;
74
} TotemBemusedPluginClass;
76
G_MODULE_EXPORT GType register_totem_plugin (GTypeModule *module);
77
GType totem_bemused_plugin_get_type (void) G_GNUC_CONST;
79
static void totem_bemused_plugin_init (TotemBemusedPlugin *plugin);
80
static void totem_bemused_plugin_finalize (GObject *object);
81
static gboolean impl_activate (TotemPlugin *plugin, TotemObject *totem, GError **error);
82
static void impl_deactivate (TotemPlugin *plugin, TotemObject *totem);
84
TOTEM_PLUGIN_REGISTER(TotemBemusedPlugin, totem_bemused_plugin)
66
} TotemBemusedPluginPrivate;
68
TOTEM_PLUGIN_REGISTER(TOTEM_TYPE_BEMUSED_PLUGIN, TotemBemusedPlugin, totem_bemused_plugin)
86
70
/* Bluetooth functions */
102
send_response_flush (TotemBemusedPlugin *tp, GIOChannel *source, const char *resp, gssize len, gboolean flush)
86
send_response_flush (TotemBemusedPlugin *tp, GIOChannel *source, const char *resp, gsize len, gboolean flush)
104
88
GError *error = NULL;
105
89
gsize written = 0;
113
97
flush_response (tp, source);
115
99
if (len != written)
116
g_message ("sent response: %d chars but len %d chars", (int) written, (int) len);
100
g_message ("sent response: %"G_GSIZE_FORMAT" chars but len %"G_GSIZE_FORMAT" chars", written, len);
120
send_response (TotemBemusedPlugin *tp, GIOChannel *source, const char *resp, gssize len)
104
send_response (TotemBemusedPlugin *tp, GIOChannel *source, const char *resp, gsize len)
122
106
send_response_flush (tp, source, resp, len, TRUE);
126
read_response (TotemBemusedPlugin *tp, GIOChannel *source, char *buf, gssize len)
110
read_response (TotemBemusedPlugin *tp, GIOChannel *source, char *buf, gsize len)
128
112
GError *error = NULL;
131
if (g_io_channel_read_chars (source, buf, len, &read, &error) != G_IO_STATUS_NORMAL) {
115
if (g_io_channel_read_chars (source, buf, len, &num_read, &error) != G_IO_STATUS_NORMAL) {
132
116
g_message ("error reading response: %s", error->message);
133
117
g_error_free (error);
134
} else if (len != read) {
135
g_message ("read %d chars but len %d chars", (int) read, (int) len);
118
} else if (len != num_read) {
119
g_message ("read %"G_GSIZE_FORMAT" chars but len %"G_GSIZE_FORMAT" chars", num_read, len);
140
124
read_filename (TotemBemusedPlugin *tp, GIOChannel *source)
142
126
char namelenbuf[2], *filename;
145
129
/* Read length */
146
130
read_response (tp, source, namelenbuf, 2);
160
144
write_playlist (TotemBemusedPlugin *tp, GIOChannel *source)
146
TotemBemusedPluginPrivate *priv = tp->priv;
163
148
int playlist_pos, playlist_len, i;
165
playlist_pos = totem_get_playlist_pos (tp->totem);
166
playlist_len = totem_get_playlist_length (tp->totem);
150
playlist_pos = totem_get_playlist_pos (priv->totem);
151
playlist_len = totem_get_playlist_length (priv->totem);
168
153
strncpy(buf, "PLSTACK", strlen ("PLSTACK"));
169
154
if (playlist_len == 0) {
180
165
for (i = 0; i < playlist_len; i++) {
183
title = totem_get_title_at_playlist_pos (tp->totem, i);
168
title = totem_get_title_at_playlist_pos (priv->totem, i);
170
/* Translators: the parameter is a number used to identify this playlist entry */
185
171
title = g_strdup_printf (_("Untitled %d"), i);
186
173
g_message ("pushing entry %s", title);
187
174
send_response_flush (tp, source, title, strlen (title), FALSE);
201
188
strncpy(buf, "GVOLACK", strlen ("GVOLACK"));
202
volume = bacon_video_widget_get_volume (tp->bvw);
189
volume = bacon_video_widget_get_volume (tp->priv->bvw);
203
190
if (volume >= 1.0)
204
191
buf[7] = (unsigned char) 255;
216
203
read_response (tp, source, &buf, 1);
217
204
volume = (double) buf / (double) 256;
218
bacon_video_widget_set_volume (tp->bvw, volume);
205
bacon_video_widget_set_volume (tp->priv->bvw, volume);
238
225
read_response (tp, source, &buf, 1);
239
totem_action_remote_set_setting (tp->totem, setting, buf != 0);
226
totem_action_remote_set_setting (tp->priv->totem, setting, buf != 0);
243
230
seek_to_pos (TotemBemusedPlugin *tp, GIOChannel *source)
248
235
read_response (tp, source, buf, 4);
250
time += buf[1] << 16;
236
_time = buf[0] << 24;
237
_time += buf[1] << 16;
238
_time += buf[2] << 8;
254
totem_action_seek_time (tp->totem, (gint64) time * 1000);
241
totem_action_seek_time (tp->priv->totem, (gint64) _time * 1000, FALSE);
363
351
send_response_flush (tp, source, "INFOACK", strlen ("INFOACK"), FALSE);
365
353
send_response_flush (tp, source, "INF2ACK", strlen ("INF2ACK"), FALSE);
366
if (totem_is_playing (tp->totem) != FALSE)
354
if (totem_is_playing (priv->totem) != FALSE)
368
else if (totem_is_paused (tp->totem) != FALSE)
356
else if (totem_is_paused (priv->totem) != FALSE)
373
361
send_response_flush (tp, source, &status, 1, FALSE);
374
STUFF4((int) bacon_video_widget_get_stream_length (tp->bvw) / 1000);
375
STUFF4((int) bacon_video_widget_get_current_time (tp->bvw) / 1000);
376
status = totem_action_remote_get_setting (tp->totem, TOTEM_REMOTE_SETTING_SHUFFLE);
362
STUFF4((int) bacon_video_widget_get_stream_length (priv->bvw) / 1000);
363
STUFF4((int) bacon_video_widget_get_current_time (priv->bvw) / 1000);
364
status = totem_action_remote_get_setting (priv->totem, TOTEM_REMOTE_SETTING_SHUFFLE);
377
365
send_response_flush (tp, source, &status, 1, FALSE);
378
status = totem_action_remote_get_setting (tp->totem, TOTEM_REMOTE_SETTING_REPEAT);
366
status = totem_action_remote_get_setting (priv->totem, TOTEM_REMOTE_SETTING_REPEAT);
379
367
send_response_flush (tp, source, &status, 1, FALSE);
381
title = totem_get_short_title (tp->totem);
369
title = totem_get_short_title (priv->totem);
382
370
g_message ("written info for %s", title);
383
371
if (title == NULL) {
384
372
flush_response (tp, source);
396
384
set_playlist_at_pos (TotemBemusedPlugin *tp, GIOChannel *source)
401
389
read_response (tp, source, buf, 2);
402
index = (buf[0] << 8) + buf[1];
403
totem_action_set_playlist_index (tp->totem, index);
390
idx = (buf[0] << 8) + buf[1];
391
totem_action_set_playlist_index (tp->priv->totem, idx);
449
437
handle_command (TotemBemusedPlugin *tp, GIOChannel *source, const char *cmd)
439
TotemBemusedPluginPrivate *priv = tp->priv;
451
441
g_message ("cmd: %s", cmd);
461
451
} else CMD_IS("FADE") {
463
453
} else CMD_IS("FFWD") {
464
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_SEEK_FORWARD, NULL);
454
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_SEEK_FORWARD, NULL);
465
455
} else CMD_IS("FINF") {
466
456
write_detailed_file_info (tp, source);
467
457
} else CMD_IS("GVOL") {
475
465
} else CMD_IS("LIST") {
476
466
write_directory_listing (tp, source, TRUE);
477
467
} else CMD_IS("NEXT") {
478
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_NEXT, NULL);
468
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_NEXT, NULL);
479
469
} else CMD_IS("PAUS") {
480
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_PAUSE, NULL);
470
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_PAUSE, NULL);
481
471
} else CMD_IS("PLAY") {
482
472
add_or_enqueue (tp, source, TOTEM_REMOTE_COMMAND_REPLACE);
483
473
} else CMD_IS("PLEN") {
485
475
} else CMD_IS("PLST") {
486
476
write_playlist (tp, source);
487
477
} else CMD_IS("PREV") {
488
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_PREVIOUS, NULL);
478
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_PREVIOUS, NULL);
489
479
} else CMD_IS("REPT") {
490
480
set_setting (tp, source, TOTEM_REMOTE_SETTING_REPEAT);
491
481
} else CMD_IS("RMAL") {
492
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_REPLACE, NULL);
482
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_REPLACE, NULL);
493
483
} else CMD_IS("RWND") {
494
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_SEEK_BACKWARD, NULL);
484
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_SEEK_BACKWARD, NULL);
495
485
} else CMD_IS("SHFL") {
496
486
set_setting (tp, source, TOTEM_REMOTE_SETTING_SHUFFLE);
497
487
} else CMD_IS("SEEK") {
498
488
seek_to_pos (tp, source);
499
489
} else CMD_IS("SHUT") {
500
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_QUIT, NULL);
490
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_QUIT, NULL);
501
491
} else CMD_IS("STEN") {
502
492
//stop at end of track
503
493
} else CMD_IS("SLCT") {
526
516
if (condition & G_IO_IN || condition & G_IO_PRI) {
530
520
status = G_IO_STATUS_NORMAL;
532
522
while (status == G_IO_STATUS_NORMAL) {
533
523
memset(buf, 0, 5);
534
status = g_io_channel_read_chars (source, buf, 4, &read, NULL);
524
status = g_io_channel_read_chars (source, buf, 4, &num_read, NULL);
536
526
if (status == G_IO_STATUS_NORMAL)
537
527
handle_command (tp, source, buf);
555
server_watch_func (GIOChannel *source, GIOCondition condition, gpointer data)
545
server_watch_func (GIOChannel *source, GIOCondition condition, TotemBemusedPlugin *tp)
557
TotemBemusedPlugin *tp = (TotemBemusedPlugin *) data;
547
TotemBemusedPluginPrivate *priv = tp->priv;
559
549
g_message ("server_watch_func");
579
569
//FIXME check batostr(&ba) is our expected client
580
570
g_message ("connected from %s", batostr(&ba));
583
g_object_unref (G_OBJECT (tp->bvw));
584
tp->bvw = BACON_VIDEO_WIDGET (totem_get_video_widget (tp->totem));
572
if (priv->bvw != NULL)
573
g_object_unref (G_OBJECT (priv->bvw));
574
priv->bvw = BACON_VIDEO_WIDGET (totem_get_video_widget (priv->totem));
586
tp->client_iochan = g_io_channel_unix_new (client_fd);
587
g_io_channel_set_encoding (tp->client_iochan, NULL, NULL);
588
g_io_channel_set_buffered (tp->client_iochan, FALSE);
589
g_io_channel_set_flags (tp->client_iochan,
590
g_io_channel_get_flags (tp->client_iochan) | G_IO_FLAG_NONBLOCK,
576
priv->client_iochan = g_io_channel_unix_new (client_fd);
577
g_io_channel_set_encoding (priv->client_iochan, NULL, NULL);
578
g_io_channel_set_buffered (priv->client_iochan, FALSE);
579
g_io_channel_set_flags (priv->client_iochan,
580
g_io_channel_get_flags (priv->client_iochan) | G_IO_FLAG_NONBLOCK,
592
tp->client_watch_id = g_io_add_watch (tp->client_iochan,
582
priv->client_watch_id = g_io_add_watch (priv->client_iochan,
593
583
G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
594
584
client_watch_func,
596
g_io_channel_unref (tp->client_iochan);
586
g_io_channel_unref (priv->client_iochan);
686
676
/* Object functions */
689
totem_bemused_plugin_class_init (TotemBemusedPluginClass *klass)
691
GObjectClass *object_class = G_OBJECT_CLASS (klass);
692
TotemPluginClass *plugin_class = TOTEM_PLUGIN_CLASS (klass);
694
object_class->finalize = totem_bemused_plugin_finalize;
696
plugin_class->activate = impl_activate;
697
plugin_class->deactivate = impl_deactivate;
701
totem_bemused_plugin_init (TotemBemusedPlugin *plugin)
706
totem_bemused_plugin_finalize (GObject *object)
708
G_OBJECT_CLASS (totem_bemused_plugin_parent_class)->finalize (object);
712
impl_activate (TotemPlugin *plugin,
678
impl_activate (PeasActivatable *plugin)
716
680
TotemBemusedPlugin *tp = TOTEM_BEMUSED_PLUGIN (plugin);
681
TotemBemusedPluginPrivate *priv = tp->priv;
718
683
struct sockaddr_rc addr;
685
priv->totem = g_object_get_data (G_OBJECT (plugin), "object");
722
687
fd = socket (PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
724
689
g_message ("couldn't create socket");
725
690
//FIXME set error
729
694
g_message ("socket created");
732
tp->sdp_session = sdp_svc_add_spp (channel,
697
priv->sdp_session = sdp_svc_add_spp (channel,
733
698
BEMUSED_SVC_NAME,
734
699
BEMUSED_SVC_DESC,
735
700
BEMUSED_SVC_PROV,
736
701
BEMUSED_SVC_UUID);
737
if (tp->sdp_session == NULL) {
702
if (priv->sdp_session == NULL) {
739
704
g_message ("registering service failed");
743
708
addr.rc_family = AF_BLUETOOTH;
747
712
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
749
sdp_svc_del (tp->sdp_session);
714
sdp_svc_del (priv->sdp_session);
750
715
g_message ("couldn't bind");
754
719
g_message ("bind launched");
756
721
if (listen (fd, 10) < 0) {
758
723
g_message ("couldn't listen");
759
sdp_svc_del (tp->sdp_session);
724
sdp_svc_del (priv->sdp_session);
763
728
g_message ("listen launched");
765
tp->server_iochan = g_io_channel_unix_new (fd);
766
g_io_channel_set_encoding (tp->server_iochan, NULL, NULL);
767
tp->server_watch_id = g_io_add_watch (tp->server_iochan,
730
priv->server_iochan = g_io_channel_unix_new (fd);
731
g_io_channel_set_encoding (priv->server_iochan, NULL, NULL);
732
priv->server_watch_id = g_io_add_watch (priv->server_iochan,
768
733
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
734
(GIOFunc) server_watch_func,
771
g_io_channel_unref (tp->server_iochan);
736
g_io_channel_unref (priv->server_iochan);
773
738
g_message ("io chan set");
781
impl_deactivate (TotemPlugin *plugin,
744
impl_deactivate (PeasActivatable *plugin)
784
totem_remove_sidebar_page (totem, "sidebar-test");
785
g_message ("Just removed a test sidebar");