Minor cleanups (memory, D-Bus, signals)
[headphoned.git] / src / headphoned.c
blobba45861fdd490db092e3b72954ebd89ae1322ab1
1 /**
2 * headphoned for the Nokia N8x0 and the N900
4 * The headphone daemon watches the state of the headphone
5 * plug (connected, disconnected) and carries out actions
6 * based on these events.
8 * Currently supported:
9 * * Send "pause" to the media player on disconnect
10 * * Maintain different volume settings for each state
12 * Initial working version: 2009-10-21
14 * Copyright (c) 2009-2010 Thomas Perl <thpinfo.com>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this package; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 **/
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <assert.h>
34 #include <glib.h>
35 #include <gconf/gconf-client.h>
36 #include <libosso.h>
37 #include <dbus/dbus.h>
38 #include <fcntl.h>
40 #include "config.h"
42 #define STATE_FILE "/sys/devices/platform/gpio-switch/headphone/state"
43 #define STATE_CONNECTED_STR "connected"
44 #define STATE_DISCONNECTED_STR "disconnected"
46 #define GCONF_VOLUME_CONTROL "/apps/osso/sound/master_volume"
48 #ifdef DIABLO
49 # define MEDIA_SERVER_SRVC "com.nokia.osso_media_server"
50 # define MEDIA_SERVER_PATH "/com/nokia/osso_media_server"
51 # define MEDIA_SERVER_INTF "com.nokia.osso_media_server.music"
52 #else
53 # define MEDIA_SERVER_SRVC "com.nokia.mafw.renderer.Mafw-Gst-Renderer-Plugin.gstrenderer"
54 # define MEDIA_SERVER_PATH "/com/nokia/mafw/renderer/gstrenderer"
55 # define MEDIA_SERVER_INTF "com.nokia.mafw.renderer"
56 #endif
58 #define PANUCCI_SRVC "org.panucci.panucciInterface"
59 #define PANUCCI_PATH "/panucciInterface"
60 #define PANUCCI_INTF "org.panucci.panucciInterface"
62 #define MPLAYER_FIFO "/etc/headphoned/mplayer-input"
64 enum { STATE_UNKNOWN, STATE_CONNECTED, STATE_DISCONNECTED, STATE_COUNT };
66 typedef struct {
67 GConfClient* client;
68 DBusConnection* session_bus;
69 osso_context_t* osso;
70 guint state;
71 gint volume[STATE_COUNT];
72 gboolean initial;
73 } Headphoned;
75 static
76 GMainLoop* loop = NULL;
78 static void
79 sig_handler (int sig G_GNUC_UNUSED)
81 if (loop && g_main_loop_is_running (loop)) {
82 g_main_loop_quit (loop);
86 void
87 on_volume_changed(GConfClient* client, guint gnxn_id, GConfEntry* entry,
88 gpointer data)
90 Headphoned* headphoned = (Headphoned*)data;
91 headphoned->volume[headphoned->state] =
92 gconf_value_get_int(entry->value);
95 Headphoned*
96 headphoned_new()
98 Headphoned* this = g_new0(Headphoned, 1);
100 this->osso = osso_initialize("headphoned", "1.0", FALSE, NULL);
101 assert(this->osso != NULL);
103 #ifdef ENABLE_VOLUME_CONTROL
104 this->client = gconf_client_get_default();
105 gconf_client_add_dir(this->client, GCONF_VOLUME_CONTROL,
106 GCONF_CLIENT_PRELOAD_NONE, NULL);
107 gconf_client_notify_add(this->client, GCONF_VOLUME_CONTROL,
108 on_volume_changed, this, NULL, NULL);
109 #endif
111 this->session_bus = (DBusConnection*)osso_get_dbus_connection(this->osso);
112 this->initial = TRUE;
114 return this;
117 gboolean
118 on_file_changed(GIOChannel* source, GIOCondition condition, gpointer data)
120 Headphoned* headphoned = (Headphoned*)data;
121 #ifdef ENABLE_VOLUME_CONTROL
122 gint volume = headphoned->volume[headphoned->state];
123 #endif
124 gchar* result;
125 int mplayer_fifo;
127 g_io_channel_seek_position(source, 0, G_SEEK_SET, NULL);
128 g_io_channel_read_line(source, &result, NULL, NULL, NULL);
129 g_strstrip(result);
131 if (g_ascii_strcasecmp(result, STATE_CONNECTED_STR) == 0) {
132 headphoned->state = STATE_CONNECTED;
133 } else {
134 headphoned->state = STATE_DISCONNECTED;
135 #ifdef ENABLE_PAUSE_ON_DISCONNECT
136 if (headphoned->initial == FALSE) {
137 /* Nokia Media Player */
138 osso_rpc_run(headphoned->osso,
139 MEDIA_SERVER_SRVC,
140 MEDIA_SERVER_PATH,
141 MEDIA_SERVER_INTF,
142 "pause",
143 NULL,
144 DBUS_TYPE_INVALID);
146 /* Panucci */
147 if (dbus_bus_name_has_owner(headphoned->session_bus,
148 PANUCCI_SRVC,
149 NULL)) {
150 osso_rpc_run(headphoned->osso,
151 PANUCCI_SRVC,
152 PANUCCI_PATH,
153 PANUCCI_INTF,
154 "pause",
155 NULL,
156 DBUS_TYPE_INVALID);
159 /* MPlayer */
160 if ((mplayer_fifo = open(MPLAYER_FIFO,
161 O_WRONLY | O_NONBLOCK)) != -1) {
162 write(mplayer_fifo, "pause\n", 6);
163 close(mplayer_fifo);
166 #endif
169 #ifdef ENABLE_VOLUME_CONTROL
170 gint new_volume = headphoned->volume[headphoned->state];
171 if (new_volume != volume) {
172 gconf_client_set_int(headphoned->client, GCONF_VOLUME_CONTROL,
173 new_volume, NULL);
174 /*gconf_client_suggest_sync(headphoned->client, NULL);
175 gconf_client_clear_cache(headphoned->client);*/
177 #endif
178 headphoned->initial = FALSE;
180 g_free(result);
181 return TRUE;
185 main(int argc, char* argv[])
187 Headphoned *headphoned;
188 g_type_init();
190 signal(SIGINT, sig_handler);
191 signal(SIGQUIT, sig_handler);
192 signal(SIGTERM, sig_handler);
194 loop = g_main_loop_new(NULL, FALSE);
195 headphoned = headphoned_new();
197 GIOChannel* state = g_io_channel_new_file(STATE_FILE, "r", NULL);
198 g_io_add_watch(state, G_IO_PRI, on_file_changed, headphoned);
200 g_main_loop_run(loop);
202 #ifdef ENABLE_VOLUME_CONTROL
203 if (headphoned->client) {
204 gconf_client_remove_dir(headphoned->client, GCONF_VOLUME_CONTROL, NULL);
205 g_object_unref(headphoned->client);
207 #endif
209 if (state) {
210 g_io_channel_unref(state);
213 osso_deinitialize(headphoned->osso);
214 g_free(headphoned);
215 return 0;