~audio-recorder/audio-recorder/trunk

« back to all changes in this revision

Viewing changes to src/dbus-server.c

  • Committer: Osmo Antero
  • Date: 2012-04-18 19:22:01 UTC
  • Revision ID: osmoma@gmail.com-20120418192201-ejjs6ikv7o4aznbi
New media-player interface that's based on the MediaPlayer2 standard. See src/dbus-mpris2.c.

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