No issues found
1 /*
2 * rb-lirc-plugin.c
3 *
4 * Copyright (C) 2006 Jonathan Matthew
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * The Rhythmbox authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Rhythmbox. This permission is above and beyond the permissions granted
14 * by the GPL license by which Rhythmbox is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <string.h>
34 #include <unistd.h>
35
36 #include <glib.h>
37 #include <glib-object.h>
38 #include <glib/gi18n-lib.h>
39 #include <gmodule.h>
40 #include <lirc/lirc_client.h>
41
42 #include "rb-plugin-macros.h"
43 #include "rb-shell.h"
44 #include "rb-debug.h"
45 #include "rb-util.h"
46 #include "rb-shell-player.h"
47 #include "rb-file-helpers.h"
48
49 #define RB_TYPE_LIRC_PLUGIN (rb_lirc_plugin_get_type ())
50 #define RB_LIRC_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_LIRC_PLUGIN, RBLircPlugin))
51 #define RB_LIRC_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_LIRC_PLUGIN, RBLircPluginClass))
52 #define RB_IS_LIRC_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_LIRC_PLUGIN))
53 #define RB_IS_LIRC_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_LIRC_PLUGIN))
54 #define RB_LIRC_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_LIRC_PLUGIN, RBLircPluginClass))
55
56 #define RB_IR_COMMAND_PLAY "play"
57 #define RB_IR_COMMAND_PAUSE "pause"
58 #define RB_IR_COMMAND_PLAYPAUSE "playpause"
59 #define RB_IR_COMMAND_STOP "stop"
60 #define RB_IR_COMMAND_SHUFFLE "shuffle"
61 #define RB_IR_COMMAND_REPEAT "repeat"
62 #define RB_IR_COMMAND_NEXT "next"
63 #define RB_IR_COMMAND_PREVIOUS "previous"
64 #define RB_IR_COMMAND_SEEK_FORWARD "seek_forward"
65 #define RB_IR_COMMAND_SEEK_BACKWARD "seek_backward"
66 #define RB_IR_COMMAND_VOLUME_UP "volume_up"
67 #define RB_IR_COMMAND_VOLUME_DOWN "volume_down"
68 #define RB_IR_COMMAND_MUTE "mute"
69 #define RB_IR_COMMAND_QUIT "quit"
70
71 typedef struct
72 {
73 PeasExtensionBase parent;
74 RBShellPlayer *shell_player;
75 struct lirc_config *lirc_config;
76 GIOChannel *lirc_channel;
77 } RBLircPlugin;
78
79 typedef struct
80 {
81 PeasExtensionBaseClass parent_class;
82 } RBLircPluginClass;
83
84 G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
85
86 static void rb_lirc_plugin_init (RBLircPlugin *plugin);
87
88 RB_DEFINE_PLUGIN (RB_TYPE_LIRC_PLUGIN, RBLircPlugin, rb_lirc_plugin,)
89
90 static void
91 rb_lirc_plugin_init (RBLircPlugin *plugin)
92 {
93 rb_debug ("RBLircPlugin initialising");
94 }
95
96 static gboolean
97 rb_lirc_plugin_read_code (GIOChannel *source,
98 GIOCondition condition,
99 RBLircPlugin *plugin)
100 {
101 char *code;
102 char *str = NULL; /* owned by lirc config, must not be freed */
103 int ok;
104 gboolean processed = FALSE;
105
106 if (condition & (G_IO_ERR | G_IO_HUP)) {
107 /* TODO: retry after a minute? */
108 rb_debug ("LIRC connection broken. sorry.");
109 return FALSE;
110 }
111
112 lirc_nextcode (&code);
113 if (code == NULL) {
114 rb_debug ("Got incomplete lirc code");
115 return TRUE;
116 }
117
118 do {
119 ok = lirc_code2char (plugin->lirc_config, code, &str);
120
121 if (ok != 0) {
122 rb_debug ("couldn't convert lirc code \"%s\" to string", code);
123 } else if (str == NULL) {
124 if (processed == FALSE)
125 rb_debug ("unknown LIRC code \"%s\"", code);
126 break;
127 } else if (strcmp (str, RB_IR_COMMAND_PLAY) == 0) {
128 gboolean playing;
129 rb_shell_player_get_playing (plugin->shell_player, &playing, NULL);
130 if (playing == FALSE)
131 rb_shell_player_playpause (plugin->shell_player, FALSE, NULL);
132 } else if (strcmp (str, RB_IR_COMMAND_PAUSE) == 0) {
133 rb_shell_player_pause (plugin->shell_player, NULL);
134 } else if (strcmp (str, RB_IR_COMMAND_PLAYPAUSE) == 0) {
135 rb_shell_player_playpause (plugin->shell_player, FALSE, NULL);
136 } else if (strcmp (str, RB_IR_COMMAND_STOP) == 0) {
137 rb_shell_player_stop (plugin->shell_player);
138 } else if (strcmp (str, RB_IR_COMMAND_SHUFFLE) == 0) {
139 gboolean shuffle;
140 gboolean repeat;
141 if (rb_shell_player_get_playback_state (plugin->shell_player, &shuffle, &repeat)) {
142 rb_shell_player_set_playback_state (plugin->shell_player, !shuffle, repeat);
143 }
144 } else if (strcmp (str, RB_IR_COMMAND_REPEAT) == 0) {
145 gboolean shuffle;
146 gboolean repeat;
147 if (rb_shell_player_get_playback_state (plugin->shell_player, &shuffle, &repeat)) {
148 rb_shell_player_set_playback_state (plugin->shell_player, shuffle, !repeat);
149 }
150 } else if (strcmp (str, RB_IR_COMMAND_NEXT) == 0) {
151 rb_shell_player_do_next (plugin->shell_player, NULL);
152 } else if (strcmp (str, RB_IR_COMMAND_PREVIOUS) == 0) {
153 rb_shell_player_do_previous (plugin->shell_player, NULL);
154 } else if (strcmp (str, RB_IR_COMMAND_SEEK_FORWARD) == 0) {
155 rb_shell_player_seek (plugin->shell_player, FFWD_OFFSET, NULL);
156 } else if (strcmp (str, RB_IR_COMMAND_SEEK_BACKWARD) == 0) {
157 rb_shell_player_seek (plugin->shell_player, -RWD_OFFSET, NULL);
158 } else if (strcmp (str, RB_IR_COMMAND_VOLUME_UP) == 0) {
159 rb_shell_player_set_volume_relative (plugin->shell_player, 0.1, NULL);
160 } else if (strcmp (str, RB_IR_COMMAND_VOLUME_DOWN) == 0) {
161 rb_shell_player_set_volume_relative (plugin->shell_player, -0.1, NULL);
162 } else if (strcmp (str, RB_IR_COMMAND_MUTE) == 0) {
163 gboolean mute;
164 if (rb_shell_player_get_mute (plugin->shell_player, &mute, NULL)) {
165 rb_shell_player_set_mute (plugin->shell_player, !mute, NULL);
166 }
167 } else if (strcmp (str,RB_IR_COMMAND_QUIT) == 0) {
168 RBShell *shell;
169
170 g_object_get (plugin, "object", &shell, NULL);
171 rb_shell_quit (shell, NULL);
172 g_object_unref (shell);
173 /* the plugin will have been deactivated, so we can't continue the loop */
174 break;
175 }
176 processed = TRUE;
177 } while (ok == 0);
178 g_free (code);
179
180 return TRUE;
181 }
182
183 static void
184 impl_activate (PeasActivatable *bplugin)
185 {
186 int fd;
187 char *path;
188 RBLircPlugin *plugin = RB_LIRC_PLUGIN (bplugin);
189 RBShell *shell;
190
191 g_object_get (plugin, "object", &shell, NULL);
192
193 g_object_get (shell, "shell-player", &plugin->shell_player, NULL);
194
195 rb_debug ("Activating lirc plugin");
196
197 fd = lirc_init ("Rhythmbox", 1);
198 if (fd < 0) {
199 rb_debug ("Couldn't initialize lirc");
200 g_object_unref (shell);
201 return;
202 }
203
204 /* Load the default Rhythmbox setup */
205 path = rb_find_plugin_data_file (G_OBJECT (plugin), "rhythmbox_lirc_default");
206 if (path == NULL || lirc_readconfig (path, &plugin->lirc_config, NULL) == -1) {
207 g_free (path);
208 close (fd);
209 rb_debug ("Couldn't read lirc configuration");
210 g_object_unref (shell);
211 return;
212 }
213 g_free (path);
214
215 lirc_readconfig (NULL, &plugin->lirc_config, NULL);
216
217 plugin->lirc_channel = g_io_channel_unix_new (fd);
218 g_io_channel_set_encoding (plugin->lirc_channel, NULL, NULL);
219 g_io_channel_set_buffered (plugin->lirc_channel, FALSE);
220 g_io_add_watch (plugin->lirc_channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
221 (GIOFunc) rb_lirc_plugin_read_code, plugin);
222
223 g_object_unref (shell);
224 }
225
226 static void
227 impl_deactivate (PeasActivatable *bplugin)
228 {
229 RBLircPlugin *plugin = RB_LIRC_PLUGIN (bplugin);
230 GError *error = NULL;
231
232 rb_debug ("Deactivating lirc plugin");
233
234 if (plugin->lirc_channel) {
235 g_io_channel_shutdown (plugin->lirc_channel, FALSE, &error);
236 if (error != NULL) {
237 g_warning ("Couldn't destroy lirc connection: %s",
238 error->message);
239 g_error_free (error);
240 }
241 plugin->lirc_channel = NULL;
242 }
243
244 if (plugin->lirc_config) {
245 lirc_freeconfig (plugin->lirc_config);
246 plugin->lirc_config = NULL;
247
248 lirc_deinit ();
249 }
250
251 if (plugin->shell_player) {
252 g_object_unref (G_OBJECT (plugin->shell_player));
253 plugin->shell_player = NULL;
254 }
255 }
256
257 G_MODULE_EXPORT void
258 peas_register_types (PeasObjectModule *module)
259 {
260 rb_lirc_plugin_register_type (G_TYPE_MODULE (module));
261 peas_object_module_register_extension_type (module,
262 PEAS_TYPE_ACTIVATABLE,
263 RB_TYPE_LIRC_PLUGIN);
264 }