~audio-recorder/audio-recorder/trunk

« back to all changes in this revision

Viewing changes to src/dbus-service.c

  • Committer: Osmo Antero
  • Date: 2011-09-18 09:13:24 UTC
  • Revision ID: osmoma@gmail.com-20110918091324-wosqw4bzzhhyqz6m
VersionĀ 0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "log.h"
 
2
#include "support.h"
 
3
#include "about.h"
 
4
#include "rec-manager.h"
 
5
#include <gst/gst.h>
 
6
 
 
7
// This module creates a DBus-server for this program.
 
8
// Other programs can control the recorder by calling methods via this DBus interface.
 
9
//
 
10
//  DBus methods are:
 
11
//  get_identity(), returns program name + version, eg. "Audio Recorder 1.0".
 
12
//
 
13
//  get_state(), returns current recording state: "not running" | "on" | off" | "paused".
 
14
//
 
15
//  set_state(state), state can be one of: "start"|"stop"|"pause"|"hide"|"show"|"quit".
 
16
//                    returns "OK" or NULL if error.
 
17
//
 
18
// Ref: http://developer.gnome.org/gio/2.28/GDBusServer.html
 
19
 
 
20
#define R_DBUS_SERVER_ADDRESS "unix:abstract=audiorecorder"
 
21
 
 
22
#define R_DBUS_OBJECT_PATH "/org/gnome/API/AudioRecorder"
 
23
#define R_DBUS_INTERFACE_NAME "org.gnome.API.AudioRecorderInterface"
 
24
 
 
25
static GDBusServer *g_dbus_server = NULL;
 
26
static GDBusNodeInfo *g_introspection_data = NULL;
 
27
 
 
28
// Signatures for the methods we are exporting.
 
29
// DBus clients can get information or control the recorder by calling these functions.
 
30
static const gchar g_introspection_xml[] =
 
31
    "<node>"
 
32
    "  <interface name='org.gnome.API.AudioRecorderInterface'>"
 
33
    "    <method name='get_identity'>"
 
34
    "      <arg type='s' name='response' direction='out'/>"  // Returns program name + version, eg. "Audio Recorder 1.0"
 
35
    "    </method>"
 
36
    "    <method name='get_state'>"
 
37
    "      <arg type='s' name='response' direction='out'/>"  // Returns current recording state: "not running"|"on"|off"|"paused"
 
38
    "    </method>"
 
39
    "    <method name='set_state'>"
 
40
    "      <arg type='s' name='state' direction='in'/>"      // Set new state. Input argument:"start"|"stop"|"pause"|"hide"|"show"|"quit".
 
41
    "      <arg type='s' name='response' direction='out'/>"  // Output: "OK" or NULL if error.
 
42
    "    </method>"
 
43
    "  </interface>"
 
44
    "</node>";
 
45
 
 
46
static gboolean dbus_service_start();
 
47
static void dbus_service_set_state(gchar *new_state);
 
48
 
 
49
// -----------------------------------------------------------------------------------
 
50
 
 
51
void dbus_service_module_init() {
 
52
    LOG_DEBUG("Init dbus_service.c\n");
 
53
 
 
54
    g_dbus_server = NULL;
 
55
 
 
56
    // Start service
 
57
    dbus_service_start();
 
58
}
 
59
 
 
60
void dbus_service_module_exit() {
 
61
    LOG_DEBUG("Clean up dbus_service.c.\n");
 
62
 
 
63
    if (g_introspection_data) {
 
64
        g_dbus_node_info_unref(g_introspection_data);
 
65
    }
 
66
    g_introspection_data = NULL;
 
67
 
 
68
    if (g_dbus_server) {
 
69
        g_object_unref(g_dbus_server);
 
70
    }
 
71
    g_dbus_server = NULL;
 
72
}
 
73
 
 
74
static void handle_method_call(GDBusConnection *connection,
 
75
                               const gchar           *sender,
 
76
                               const gchar           *object_path,
 
77
                               const gchar           *interface_name,
 
78
                               const gchar           *method_name,
 
79
                               GVariant              *parameters,
 
80
                               GDBusMethodInvocation *invocation,
 
81
                               gpointer               user_data) {
 
82
 
 
83
    // DBus method call: get_identity.
 
84
    // Returns program name + version.
 
85
    if (g_strcmp0(method_name, "get_identity") == 0) {
 
86
 
 
87
        // Eg. "Audio Recorder 2.x"
 
88
        gchar *response = about_program_name();
 
89
 
 
90
        g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", response));
 
91
        g_free(response);
 
92
        LOG_DEBUG("Audio recorder (DBus-server) executed method get_identity().\n");
 
93
    }
 
94
 
 
95
    // DBus method call: get_state.
 
96
    // Returns "not running" | "on" | "off" | "paused"
 
97
    else if (g_strcmp0(method_name, "get_state") == 0) {
 
98
 
 
99
        // Get recording state
 
100
        gint state = -1;
 
101
        gint pending = -1;
 
102
        rec_manager_get_state(&state, &pending);
 
103
 
 
104
        const gchar *state_str = NULL;
 
105
 
 
106
        switch (state) {
 
107
        case GST_STATE_PAUSED:
 
108
            state_str = "paused";
 
109
            break;
 
110
 
 
111
        case GST_STATE_PLAYING:
 
112
            state_str = "on";
 
113
            break;
 
114
 
 
115
        default:
 
116
            state_str = "off";
 
117
        }
 
118
 
 
119
        g_dbus_method_invocation_return_value(invocation, g_variant_new ("(s)", state_str));
 
120
        LOG_DEBUG("Audio recorder (DBus-server) executed method get_state().\n");
 
121
    }
 
122
 
 
123
    // DBus method call: set_state(new_state).
 
124
    // new_state can be: "start" | "stop" | "pause" | "show"  | "hide" | "quit".
 
125
    // Returns "OK" | NULL
 
126
    else if (g_strcmp0 (method_name, "set_state") == 0) {
 
127
        gchar *response = g_strdup("OK");
 
128
 
 
129
        gchar *new_state = NULL;
 
130
        g_variant_get(parameters, "(&s)", &new_state);
 
131
 
 
132
        g_dbus_method_invocation_return_value(invocation, g_variant_new ("(s)", response));
 
133
        g_free(response);
 
134
        LOG_DEBUG("Audio recorder (Dbus-server) executed method set_state(%s).\n", new_state);
 
135
 
 
136
        // Set recorder to new_state
 
137
        dbus_service_set_state(new_state);
 
138
    }
 
139
}
 
140
 
 
141
static void dbus_service_set_state(gchar *new_state) {
 
142
    // Set recorder to new_state
 
143
 
 
144
    // $ audio-recorder --command start
 
145
    if (!g_strcmp0(new_state, "start")) {
 
146
        rec_manager_start_recording();
 
147
    }
 
148
 
 
149
    // $ audio-recorder --command stop
 
150
    else if (!g_strcmp0(new_state, "stop")) {
 
151
        rec_manager_stop_recording();
 
152
    }
 
153
 
 
154
    // $ audio-recorder --command pause
 
155
    else if (!g_strcmp0(new_state, "pause")) {
 
156
        rec_manager_pause_recording();
 
157
    }
 
158
 
 
159
    // $ audio-recorder --command show
 
160
    else if (!g_strcmp0(new_state, "show")) {
 
161
        rec_manager_show_window(TRUE);
 
162
    }
 
163
 
 
164
    // $ audio-recorder --command hide
 
165
    else if (!g_strcmp0(new_state, "hide")) {
 
166
        rec_manager_show_window(FALSE);
 
167
    }
 
168
 
 
169
    // $ audio-recorder --command quit
 
170
    else if (!g_strcmp0(new_state, "quit")) {
 
171
        rec_manager_quit_application();
 
172
    }
 
173
}
 
174
 
 
175
static const GDBusInterfaceVTable interface_vtable = {
 
176
    handle_method_call,
 
177
    NULL,
 
178
    NULL,
 
179
};
 
180
 
 
181
// ---------------------------------------------------------------------------------
 
182
 
 
183
static gboolean on_new_connection(GDBusServer *server, GDBusConnection *connection, gpointer user_data) {
 
184
    /*
 
185
    GCredentials *credentials = NULL;
 
186
    credentials = g_dbus_connection_get_peer_credentials(connection);
 
187
 
 
188
    gchar *s = NULL;
 
189
    if (credentials == NULL)
 
190
        s = g_strdup ("(no credentials received)");
 
191
    else
 
192
        s = g_credentials_to_string(credentials);
 
193
 
 
194
 
 
195
    LOG_DEBUG("Client connected.\n"
 
196
           "Peer credentials: %s\n"
 
197
           "Negotiated capabilities: unix-fd-passing=%d\n",
 
198
           s,
 
199
           g_dbus_connection_get_capabilities(connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
 
200
    */
 
201
 
 
202
    g_object_ref(connection);
 
203
 
 
204
    gint registration_id = g_dbus_connection_register_object(connection,
 
205
                           R_DBUS_OBJECT_PATH,
 
206
                           g_introspection_data->interfaces[0],
 
207
                           &interface_vtable,
 
208
                           NULL,  /* user_data */
 
209
                           NULL,  /* user_data_free_func */
 
210
                           NULL); /* GError */
 
211
 
 
212
    return (registration_id > 0);
 
213
}
 
214
 
 
215
 
 
216
static gboolean dbus_service_start() {
 
217
    // Start DBus-server for this application.
 
218
    // This will receive method calls from external programs.
 
219
 
 
220
    // Build introspection data from XML
 
221
    g_introspection_data = g_dbus_node_info_new_for_xml(g_introspection_xml, NULL);
 
222
 
 
223
    // Server flags
 
224
    GDBusServerFlags server_flags = G_DBUS_SERVER_FLAGS_NONE;
 
225
    server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
 
226
 
 
227
    gchar *guid = g_dbus_generate_guid();
 
228
 
 
229
    // Create a new D-Bus server that listens on R_DBUS_SERVER_ADDRESS
 
230
    GError *error = NULL;
 
231
    g_dbus_server = g_dbus_server_new_sync(R_DBUS_SERVER_ADDRESS,
 
232
                                           server_flags,
 
233
                                           guid,
 
234
                                           NULL, /* GDBusAuthObserver */
 
235
                                           NULL, /* GCancellable */
 
236
                                           &error);
 
237
 
 
238
    g_dbus_server_start(g_dbus_server);
 
239
    g_free(guid);
 
240
 
 
241
    if (g_dbus_server == NULL) {
 
242
        LOG_ERROR("Cannot create server address %s for DBus. %s\n", R_DBUS_SERVER_ADDRESS, error->message);
 
243
        g_error_free(error);
 
244
        return FALSE;
 
245
    }
 
246
 
 
247
    LOG_DEBUG("This Audio Recorder is listening on DBus at: %s\n", g_dbus_server_get_client_address(g_dbus_server));
 
248
 
 
249
    // Set up callback method (for client calls)
 
250
    g_signal_connect(g_dbus_server, "new-connection", G_CALLBACK (on_new_connection), NULL);
 
251
 
 
252
    return (g_dbus_server != NULL);
 
253
}
 
254
 
 
255
gchar *dbus_service_client_request(gchar *method_name, gchar *arg) {
 
256
    // Execute method call on DBus-server.
 
257
    // Audio-recorder itself can call methods on the server.
 
258
    // DBus-server will most likely return a value. Pass it to the calling function.
 
259
        
 
260
    GError *error = NULL;
 
261
 
 
262
    GDBusConnection *connection = g_dbus_connection_new_for_address_sync(R_DBUS_SERVER_ADDRESS,
 
263
                                  G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 
264
                                  NULL, // GDBusAuthObserver
 
265
                                  NULL, // GCancellable
 
266
                                  &error);
 
267
 
 
268
    if (!connection) {
 
269
        LOG_DEBUG("Cannot connect to DBus address %s. %s\n", R_DBUS_SERVER_ADDRESS, error->message);
 
270
        g_error_free(error);
 
271
        return NULL;
 
272
    }
 
273
 
 
274
    // Optional argument
 
275
    GVariant *argument = NULL;
 
276
    if (arg) {
 
277
        argument = g_variant_new("(s)", arg);
 
278
    }
 
279
 
 
280
    GVariant *value = NULL;
 
281
    value = g_dbus_connection_call_sync(connection,
 
282
                                        NULL, // bus_name
 
283
                                        R_DBUS_OBJECT_PATH,
 
284
                                        R_DBUS_INTERFACE_NAME,
 
285
                                        method_name, // method_name
 
286
                                        argument, // input parm
 
287
                                        G_VARIANT_TYPE ("(s)"), // return value (one string)
 
288
                                        G_DBUS_CALL_FLAGS_NONE,
 
289
                                        -1,
 
290
                                        NULL,
 
291
                                        &error);
 
292
 
 
293
    if (!value) {
 
294
        LOG_ERROR("Error invoking %s(%s). %s\n", method_name, arg, error->message);
 
295
        g_error_free(error);
 
296
        return NULL;
 
297
    }
 
298
 
 
299
    gchar *server_response = NULL;
 
300
    g_variant_get(value, "(&s)", &server_response);
 
301
 
 
302
    // Take copy of the value
 
303
    gchar *ret = g_strdup(server_response);
 
304
 
 
305
    if (value) {
 
306
        g_variant_unref(value);
 
307
    }
 
308
 
 
309
    if (connection) {
 
310
        g_object_unref(connection);
 
311
    }
 
312
 
 
313
    // Return ret
 
314
    return ret;
 
315
}
 
316
 
 
317