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);
184
169
if (title == NULL) {
185
170
/* Translators: the parameter is a number used to identify this playlist entry */
186
171
title = g_strdup_printf (_("Untitled %d"), i);
203
188
strncpy(buf, "GVOLACK", strlen ("GVOLACK"));
204
volume = bacon_video_widget_get_volume (tp->bvw);
189
volume = bacon_video_widget_get_volume (tp->priv->bvw);
205
190
if (volume >= 1.0)
206
191
buf[7] = (unsigned char) 255;
218
203
read_response (tp, source, &buf, 1);
219
204
volume = (double) buf / (double) 256;
220
bacon_video_widget_set_volume (tp->bvw, volume);
205
bacon_video_widget_set_volume (tp->priv->bvw, volume);
240
225
read_response (tp, source, &buf, 1);
241
totem_action_remote_set_setting (tp->totem, setting, buf != 0);
226
totem_action_remote_set_setting (tp->priv->totem, setting, buf != 0);
245
230
seek_to_pos (TotemBemusedPlugin *tp, GIOChannel *source)
250
235
read_response (tp, source, buf, 4);
252
time += buf[1] << 16;
236
_time = buf[0] << 24;
237
_time += buf[1] << 16;
238
_time += buf[2] << 8;
256
totem_action_seek_time (tp->totem, (gint64) time * 1000, FALSE);
241
totem_action_seek_time (tp->priv->totem, (gint64) _time * 1000, FALSE);
365
351
send_response_flush (tp, source, "INFOACK", strlen ("INFOACK"), FALSE);
367
353
send_response_flush (tp, source, "INF2ACK", strlen ("INF2ACK"), FALSE);
368
if (totem_is_playing (tp->totem) != FALSE)
354
if (totem_is_playing (priv->totem) != FALSE)
370
else if (totem_is_paused (tp->totem) != FALSE)
356
else if (totem_is_paused (priv->totem) != FALSE)
375
361
send_response_flush (tp, source, &status, 1, FALSE);
376
STUFF4((int) bacon_video_widget_get_stream_length (tp->bvw) / 1000);
377
STUFF4((int) bacon_video_widget_get_current_time (tp->bvw) / 1000);
378
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);
379
365
send_response_flush (tp, source, &status, 1, FALSE);
380
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);
381
367
send_response_flush (tp, source, &status, 1, FALSE);
383
title = totem_get_short_title (tp->totem);
369
title = totem_get_short_title (priv->totem);
384
370
g_message ("written info for %s", title);
385
371
if (title == NULL) {
386
372
flush_response (tp, source);
398
384
set_playlist_at_pos (TotemBemusedPlugin *tp, GIOChannel *source)
403
389
read_response (tp, source, buf, 2);
404
index = (buf[0] << 8) + buf[1];
405
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);
451
437
handle_command (TotemBemusedPlugin *tp, GIOChannel *source, const char *cmd)
439
TotemBemusedPluginPrivate *priv = tp->priv;
453
441
g_message ("cmd: %s", cmd);
463
451
} else CMD_IS("FADE") {
465
453
} else CMD_IS("FFWD") {
466
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_SEEK_FORWARD, NULL);
454
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_SEEK_FORWARD, NULL);
467
455
} else CMD_IS("FINF") {
468
456
write_detailed_file_info (tp, source);
469
457
} else CMD_IS("GVOL") {
477
465
} else CMD_IS("LIST") {
478
466
write_directory_listing (tp, source, TRUE);
479
467
} else CMD_IS("NEXT") {
480
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_NEXT, NULL);
468
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_NEXT, NULL);
481
469
} else CMD_IS("PAUS") {
482
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_PAUSE, NULL);
470
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_PAUSE, NULL);
483
471
} else CMD_IS("PLAY") {
484
472
add_or_enqueue (tp, source, TOTEM_REMOTE_COMMAND_REPLACE);
485
473
} else CMD_IS("PLEN") {
487
475
} else CMD_IS("PLST") {
488
476
write_playlist (tp, source);
489
477
} else CMD_IS("PREV") {
490
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_PREVIOUS, NULL);
478
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_PREVIOUS, NULL);
491
479
} else CMD_IS("REPT") {
492
480
set_setting (tp, source, TOTEM_REMOTE_SETTING_REPEAT);
493
481
} else CMD_IS("RMAL") {
494
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_REPLACE, NULL);
482
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_REPLACE, NULL);
495
483
} else CMD_IS("RWND") {
496
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_SEEK_BACKWARD, NULL);
484
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_SEEK_BACKWARD, NULL);
497
485
} else CMD_IS("SHFL") {
498
486
set_setting (tp, source, TOTEM_REMOTE_SETTING_SHUFFLE);
499
487
} else CMD_IS("SEEK") {
500
488
seek_to_pos (tp, source);
501
489
} else CMD_IS("SHUT") {
502
totem_action_remote (tp->totem, TOTEM_REMOTE_COMMAND_QUIT, NULL);
490
totem_action_remote (priv->totem, TOTEM_REMOTE_COMMAND_QUIT, NULL);
503
491
} else CMD_IS("STEN") {
504
492
//stop at end of track
505
493
} else CMD_IS("SLCT") {
528
516
if (condition & G_IO_IN || condition & G_IO_PRI) {
532
520
status = G_IO_STATUS_NORMAL;
534
522
while (status == G_IO_STATUS_NORMAL) {
535
523
memset(buf, 0, 5);
536
status = g_io_channel_read_chars (source, buf, 4, &read, NULL);
524
status = g_io_channel_read_chars (source, buf, 4, &num_read, NULL);
538
526
if (status == G_IO_STATUS_NORMAL)
539
527
handle_command (tp, source, buf);
557
server_watch_func (GIOChannel *source, GIOCondition condition, gpointer data)
545
server_watch_func (GIOChannel *source, GIOCondition condition, TotemBemusedPlugin *tp)
559
TotemBemusedPlugin *tp = (TotemBemusedPlugin *) data;
547
TotemBemusedPluginPrivate *priv = tp->priv;
561
549
g_message ("server_watch_func");
581
569
//FIXME check batostr(&ba) is our expected client
582
570
g_message ("connected from %s", batostr(&ba));
585
g_object_unref (G_OBJECT (tp->bvw));
586
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));
588
tp->client_iochan = g_io_channel_unix_new (client_fd);
589
g_io_channel_set_encoding (tp->client_iochan, NULL, NULL);
590
g_io_channel_set_buffered (tp->client_iochan, FALSE);
591
g_io_channel_set_flags (tp->client_iochan,
592
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,
594
tp->client_watch_id = g_io_add_watch (tp->client_iochan,
582
priv->client_watch_id = g_io_add_watch (priv->client_iochan,
595
583
G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
596
584
client_watch_func,
598
g_io_channel_unref (tp->client_iochan);
586
g_io_channel_unref (priv->client_iochan);
688
676
/* Object functions */
691
totem_bemused_plugin_class_init (TotemBemusedPluginClass *klass)
693
GObjectClass *object_class = G_OBJECT_CLASS (klass);
694
TotemPluginClass *plugin_class = TOTEM_PLUGIN_CLASS (klass);
696
object_class->finalize = totem_bemused_plugin_finalize;
698
plugin_class->activate = impl_activate;
699
plugin_class->deactivate = impl_deactivate;
703
totem_bemused_plugin_init (TotemBemusedPlugin *plugin)
708
totem_bemused_plugin_finalize (GObject *object)
710
G_OBJECT_CLASS (totem_bemused_plugin_parent_class)->finalize (object);
714
impl_activate (TotemPlugin *plugin,
678
impl_activate (PeasActivatable *plugin)
718
680
TotemBemusedPlugin *tp = TOTEM_BEMUSED_PLUGIN (plugin);
681
TotemBemusedPluginPrivate *priv = tp->priv;
720
683
struct sockaddr_rc addr;
685
priv->totem = g_object_get_data (G_OBJECT (plugin), "object");
724
687
fd = socket (PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
726
689
g_message ("couldn't create socket");
727
690
//FIXME set error
731
694
g_message ("socket created");
734
tp->sdp_session = sdp_svc_add_spp (channel,
697
priv->sdp_session = sdp_svc_add_spp (channel,
735
698
BEMUSED_SVC_NAME,
736
699
BEMUSED_SVC_DESC,
737
700
BEMUSED_SVC_PROV,
738
701
BEMUSED_SVC_UUID);
739
if (tp->sdp_session == NULL) {
702
if (priv->sdp_session == NULL) {
741
704
g_message ("registering service failed");
745
708
addr.rc_family = AF_BLUETOOTH;
749
712
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
751
sdp_svc_del (tp->sdp_session);
714
sdp_svc_del (priv->sdp_session);
752
715
g_message ("couldn't bind");
756
719
g_message ("bind launched");
758
721
if (listen (fd, 10) < 0) {
760
723
g_message ("couldn't listen");
761
sdp_svc_del (tp->sdp_session);
724
sdp_svc_del (priv->sdp_session);
765
728
g_message ("listen launched");
767
tp->server_iochan = g_io_channel_unix_new (fd);
768
g_io_channel_set_encoding (tp->server_iochan, NULL, NULL);
769
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,
770
733
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
734
(GIOFunc) server_watch_func,
773
g_io_channel_unref (tp->server_iochan);
736
g_io_channel_unref (priv->server_iochan);
775
738
g_message ("io chan set");
783
impl_deactivate (TotemPlugin *plugin,
744
impl_deactivate (PeasActivatable *plugin)
786
totem_remove_sidebar_page (totem, "sidebar-test");
787
g_message ("Just removed a test sidebar");