root/daemon/control.c @ 847536504b95307eadfdb31d17902c85569e2e21

Revision 847536504b95307eadfdb31d17902c85569e2e21, 15.7 KB (checked in by Nedko Arnaudov <nedko@…>, 6 months ago)

Basic control of studio rooms

  • Property mode set to 100644
Line 
1/* -*- Mode: C ; c-basic-offset: 2 -*- */
2/*
3 * LADI Session Handler (ladish)
4 *
5 * Copyright (C) 2008, 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
7 *
8 **************************************************************************
9 * This file contains code of the D-Bus control interface helpers
10 **************************************************************************
11 *
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 */
27
28#include "common.h"
29
30#include "../dbus/error.h"
31#include "control.h"
32#include "../dbus_constants.h"
33#include "studio_internal.h"
34#include "room.h"
35#include "../lib/wkports.h"
36
37#define INTERFACE_NAME IFACE_CONTROL
38
39/* 805e485f-65e4-4c37-a959-2a3b60b3c270 */
40UUID_DEFINE(empty_room,0x80,0x5E,0x48,0x5F,0x65,0xE4,0x4C,0x37,0xA9,0x59,0x2A,0x3B,0x60,0xB3,0xC2,0x70);
41
42/* c603f2a0-d96a-493e-a8cf-55581d950aa9 */
43UUID_DEFINE(basic_room,0xC6,0x03,0xF2,0xA0,0xD9,0x6A,0x49,0x3E,0xA8,0xCF,0x55,0x58,0x1D,0x95,0x0A,0xA9);
44
45static struct list_head g_rooms;
46
47bool create_builtin_rooms(void)
48{
49  ladish_room_handle room;
50
51  if (!ladish_room_create(empty_room, "Empty", NULL, &room))
52  {
53    log_error("ladish_room_create() failed.");
54    return false;
55  }
56
57  list_add_tail(ladish_room_get_list_node(room), &g_rooms);
58
59  if (!ladish_room_create(basic_room, "Basic", NULL, &room))
60  {
61    log_error("ladish_room_create() failed.");
62    return false;
63  }
64
65  list_add_tail(ladish_room_get_list_node(room), &g_rooms);
66
67  return true;
68}
69
70bool create_rooms(void)
71{
72  if (!create_builtin_rooms())
73  {
74    return false;
75  }
76
77  return true;
78}
79
80void maybe_create_rooms(void)
81{
82  if (list_empty(&g_rooms))
83  {
84    create_rooms();
85  }
86}
87
88bool rooms_init(void)
89{
90  INIT_LIST_HEAD(&g_rooms);
91
92  return true;
93}
94
95void rooms_uninit(void)
96{
97  struct list_head * node_ptr;
98  ladish_room_handle room;
99
100  while (!list_empty(&g_rooms))
101  {
102    node_ptr = g_rooms.next;
103    list_del(node_ptr);
104    room = ladish_room_from_list_node(node_ptr);
105    ladish_room_destroy(room);
106  }
107}
108
109bool rooms_enum(void * context, bool (* callback)(void * context, ladish_room_handle room))
110{
111  struct list_head * node_ptr;
112
113  maybe_create_rooms();
114
115  list_for_each(node_ptr, &g_rooms)
116  {
117    if (!callback(context, ladish_room_from_list_node(node_ptr)))
118    {
119      return false;
120    }
121  }
122
123  return true;
124}
125
126ladish_room_handle find_room_template_by_name(const char * name)
127{
128  ladish_room_handle room;
129  struct list_head * node_ptr;
130
131  maybe_create_rooms();
132
133  list_for_each(node_ptr, &g_rooms)
134  {
135    room = ladish_room_from_list_node(node_ptr);
136    if (strcmp(ladish_room_get_name(room), name) == 0)
137    {
138      return room;
139    }
140  }
141
142  return NULL;
143}
144
145ladish_room_handle find_room_template_by_uuid(const uuid_t uuid_ptr)
146{
147  ladish_room_handle room;
148  struct list_head * node_ptr;
149  uuid_t uuid;
150
151  maybe_create_rooms();
152
153  list_for_each(node_ptr, &g_rooms)
154  {
155    room = ladish_room_from_list_node(node_ptr);
156    ladish_room_get_uuid(room, uuid);
157    if (uuid_compare(uuid, uuid_ptr) == 0)
158    {
159      return room;
160    }
161  }
162
163  return NULL;
164}
165
166static void ladish_is_studio_loaded(struct dbus_method_call * call_ptr)
167{
168  DBusMessageIter iter;
169  dbus_bool_t is_loaded;
170
171  is_loaded = studio_is_loaded();
172
173  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
174  if (call_ptr->reply == NULL)
175  {
176    goto fail;
177  }
178
179  dbus_message_iter_init_append(call_ptr->reply, &iter);
180
181  if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &is_loaded))
182  {
183    goto fail_unref;
184  }
185
186  return;
187
188fail_unref:
189  dbus_message_unref(call_ptr->reply);
190  call_ptr->reply = NULL;
191
192fail:
193  log_error("Ran out of memory trying to construct method return");
194}
195
196#define array_iter_ptr ((DBusMessageIter *)context)
197
198static bool get_studio_list_callback(void * call_ptr, void * context, const char * studio, uint32_t modtime)
199{
200  DBusMessageIter struct_iter;
201  DBusMessageIter dict_iter;
202  bool ret;
203
204  ret = false;
205
206  if (!dbus_message_iter_open_container(array_iter_ptr, DBUS_TYPE_STRUCT, NULL, &struct_iter))
207    goto exit;
208
209  if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &studio))
210    goto close_struct;
211
212  if (!dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter))
213    goto close_struct;
214
215/*   if (!maybe_add_dict_entry_string(&dict_iter, "Description", xxx)) */
216/*     goto close_dict; */
217
218  if (!dbus_add_dict_entry_uint32(&dict_iter, "Modification Time", modtime))
219    goto close_dict;
220
221  ret = true;
222
223close_dict:
224  if (!dbus_message_iter_close_container(&struct_iter, &dict_iter))
225    ret = false;
226
227close_struct:
228  if (!dbus_message_iter_close_container(array_iter_ptr, &struct_iter))
229    ret = false;
230
231exit:
232  return ret;
233}
234
235static void ladish_get_studio_list(struct dbus_method_call * call_ptr)
236{
237  DBusMessageIter iter, array_iter;
238
239  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
240  if (call_ptr->reply == NULL)
241  {
242    goto fail;
243  }
244
245  dbus_message_iter_init_append(call_ptr->reply, &iter);
246
247  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sa{sv})", &array_iter))
248  {
249    goto fail_unref;
250  }
251
252  if (!studios_iterate(call_ptr, &array_iter, get_studio_list_callback))
253  {
254    dbus_message_iter_close_container(&iter, &array_iter);
255    if (call_ptr->reply == NULL)
256      goto fail_unref;
257
258    /* studios_iterate or get_studio_list_callback() composed error reply */
259    return;
260  }
261
262  if (!dbus_message_iter_close_container(&iter, &array_iter))
263  {
264    goto fail_unref;
265  }
266
267  return;
268
269fail_unref:
270  dbus_message_unref(call_ptr->reply);
271  call_ptr->reply = NULL;
272
273fail:
274  log_error("Ran out of memory trying to construct method return");
275}
276
277static void ladish_load_studio(struct dbus_method_call * call_ptr)
278{
279  const char * name;
280
281  dbus_error_init(&g_dbus_error);
282
283  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
284  {
285    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, g_dbus_error.message);
286    dbus_error_free(&g_dbus_error);
287    return;
288  }
289
290  log_info("Load studio request (%s)", name);
291
292  if (ladish_command_load_studio(call_ptr, &g_studio.cmd_queue, name))
293  {
294    method_return_new_void(call_ptr);
295  }
296}
297
298static void ladish_delete_studio(struct dbus_method_call * call_ptr)
299{
300  const char * name;
301
302  dbus_error_init(&g_dbus_error);
303
304  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
305  {
306    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, g_dbus_error.message);
307    dbus_error_free(&g_dbus_error);
308    return;
309  }
310
311  if (studio_delete(call_ptr, name))
312  {
313    method_return_new_void(call_ptr);
314  }
315}
316
317static void ladish_new_studio(struct dbus_method_call * call_ptr)
318{
319  const char * name;
320
321  dbus_error_init(&g_dbus_error);
322
323  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
324  {
325    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, g_dbus_error.message);
326    dbus_error_free(&g_dbus_error);
327    return;
328  }
329
330  log_info("New studio request (%s)", name);
331
332  if (ladish_command_new_studio(call_ptr, &g_studio.cmd_queue, name))
333  {
334    method_return_new_void(call_ptr);
335  }
336}
337
338static void ladish_get_application_list(struct dbus_method_call * call_ptr)
339{
340  DBusMessageIter iter;
341  DBusMessageIter array_iter;
342#if 0
343  DBusMessageIter struct_iter;
344  DBusMessageIter dict_iter;
345  struct list_head * node_ptr;
346  struct lash_appdb_entry * entry_ptr;
347#endif
348
349  log_info("Getting applications list");
350
351  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
352  if (call_ptr->reply == NULL)
353  {
354    goto fail;
355  }
356
357  dbus_message_iter_init_append(call_ptr->reply, &iter);
358
359  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sa{sv})", &array_iter))
360  {
361    goto fail_unref;
362  }
363
364#if 0
365  list_for_each(node_ptr, &g_server->appdb)
366  {
367    entry_ptr = list_entry(node_ptr, struct lash_appdb_entry, siblings);
368
369    if (!dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
370      goto fail_unref;
371
372    if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, (const void *) &entry_ptr->name))
373    {
374      dbus_message_iter_close_container(&iter, &array_iter);
375      goto fail_unref;
376    }
377
378    if (!dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter))
379      goto fail_unref;
380
381    if (!maybe_add_dict_entry_string(&dict_iter, "GenericName", entry_ptr->generic_name))
382      goto fail_unref;
383
384    if (!maybe_add_dict_entry_string(&dict_iter, "Comment", entry_ptr->comment))
385      goto fail_unref;
386
387    if (!maybe_add_dict_entry_string(&dict_iter, "Icon", entry_ptr->icon))
388      goto fail_unref;
389
390    if (!dbus_message_iter_close_container(&struct_iter, &dict_iter))
391      goto fail_unref;
392
393    if (!dbus_message_iter_close_container(&array_iter, &struct_iter))
394      goto fail_unref;
395  }
396#endif
397
398  if (!dbus_message_iter_close_container(&iter, &array_iter))
399  {
400    goto fail_unref;
401  }
402
403  return;
404
405fail_unref:
406  dbus_message_unref(call_ptr->reply);
407  call_ptr->reply = NULL;
408fail:
409  return;
410}
411
412#define array_iter_ptr ((DBusMessageIter *)context)
413
414bool room_list_filler(void * context, ladish_room_handle room)
415{
416  DBusMessageIter struct_iter;
417  DBusMessageIter dict_iter;
418  const char * name;
419
420  name = ladish_room_get_name(room);
421
422  if (!dbus_message_iter_open_container(array_iter_ptr, DBUS_TYPE_STRUCT, NULL, &struct_iter))
423    return false;
424
425  if (!dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_STRING, &name))
426    return false;
427
428  if (!dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter))
429    return false;
430
431  if (!dbus_message_iter_close_container(&struct_iter, &dict_iter))
432    return false;
433
434  if (!dbus_message_iter_close_container(array_iter_ptr, &struct_iter))
435    return false;
436
437  return true;
438}
439
440#undef array_iter_ptr
441
442static void ladish_get_room_list(struct dbus_method_call * call_ptr)
443{
444  DBusMessageIter iter, array_iter;
445
446  call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
447  if (call_ptr->reply == NULL)
448  {
449    goto fail;
450  }
451
452  dbus_message_iter_init_append(call_ptr->reply, &iter);
453
454  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sa{sv})", &array_iter))
455  {
456    goto fail_unref;
457  }
458
459  if (!rooms_enum(&array_iter, room_list_filler))
460  {
461    goto fail_unref;
462  }
463
464  if (!dbus_message_iter_close_container(&iter, &array_iter))
465  {
466    goto fail_unref;
467  }
468
469  return;
470
471fail_unref:
472  dbus_message_unref(call_ptr->reply);
473  call_ptr->reply = NULL;
474
475fail:
476  log_error("Ran out of memory trying to construct method return");
477}
478
479static void ladish_delete_room(struct dbus_method_call * call_ptr)
480{
481  const char * name;
482
483  dbus_error_init(&g_dbus_error);
484
485  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
486  {
487    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, g_dbus_error.message);
488    dbus_error_free(&g_dbus_error);
489    return;
490  }
491
492  log_info("Delete room request (%s)", name);
493
494  {
495    method_return_new_void(call_ptr);
496  }
497}
498
499static void ladish_new_room(struct dbus_method_call * call_ptr)
500{
501  const char * name;
502
503  dbus_error_init(&g_dbus_error);
504
505  if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
506  {
507    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, g_dbus_error.message);
508    dbus_error_free(&g_dbus_error);
509    return;
510  }
511
512  log_info("New room request (%s)", name);
513
514  {
515    method_return_new_void(call_ptr);
516  }
517}
518
519static void ladish_exit(struct dbus_method_call * call_ptr)
520{
521  log_info("Exit command received through D-Bus");
522
523  if (!ladish_command_exit(NULL, &g_studio.cmd_queue))
524  { /* if queuing of command failed, force exit anyway,
525       JACK server will be left started,
526       but refusing exit command is worse */
527    g_quit = true;
528  }
529
530  method_return_new_void(call_ptr);
531}
532
533void emit_studio_appeared(void)
534{
535  dbus_signal_emit(g_dbus_connection, CONTROL_OBJECT_PATH, INTERFACE_NAME, "StudioAppeared", "");
536}
537
538void emit_studio_disappeared(void)
539{
540  dbus_signal_emit(g_dbus_connection, CONTROL_OBJECT_PATH, INTERFACE_NAME, "StudioDisappeared", "");
541}
542
543void emit_clean_exit(void)
544{
545  dbus_signal_emit(g_dbus_connection, CONTROL_OBJECT_PATH, INTERFACE_NAME, "CleanExit", "");
546}
547
548METHOD_ARGS_BEGIN(IsStudioLoaded, "Check whether studio D-Bus object is present")
549  METHOD_ARG_DESCRIBE_OUT("present", "b", "Whether studio D-Bus object is present")
550METHOD_ARGS_END
551
552METHOD_ARGS_BEGIN(GetStudioList, "Get list of studios")
553  METHOD_ARG_DESCRIBE_OUT("studio_list", "a(sa{sv})", "List of studios, name and properties")
554METHOD_ARGS_END
555
556METHOD_ARGS_BEGIN(NewStudio, "New studio")
557  METHOD_ARG_DESCRIBE_IN("studio_name", "s", "Name of studio, if empty name will be generated")
558METHOD_ARGS_END
559
560METHOD_ARGS_BEGIN(LoadStudio, "Load studio")
561  METHOD_ARG_DESCRIBE_IN("studio_name", "s", "Name of studio to load")
562  METHOD_ARG_DESCRIBE_IN("options", "a{sv}", "Load options")
563METHOD_ARGS_END
564
565METHOD_ARGS_BEGIN(DeleteStudio, "Delete studio")
566  METHOD_ARG_DESCRIBE_IN("studio_name", "s", "Name of studio to delete")
567METHOD_ARGS_END
568
569METHOD_ARGS_BEGIN(GetApplicationList, "Get list of applications that can be launched")
570  METHOD_ARG_DESCRIBE_OUT("applications", "a(sa{sv})", "List of applications, name and properties")
571METHOD_ARGS_END
572
573METHOD_ARGS_BEGIN(GetRoomList, "Get list of rooms")
574  METHOD_ARG_DESCRIBE_OUT("room_list", "a(sa{sv})", "List of rooms, name and properties")
575METHOD_ARGS_END
576
577METHOD_ARGS_BEGIN(NewRoom, "New room")
578  METHOD_ARG_DESCRIBE_IN("room_name", "s", "Name of the room")
579METHOD_ARGS_END
580
581METHOD_ARGS_BEGIN(DeleteRoom, "Delete room")
582  METHOD_ARG_DESCRIBE_IN("room_name", "s", "Name of room to delete")
583METHOD_ARGS_END
584
585METHOD_ARGS_BEGIN(Exit, "Tell ladish D-Bus service to exit")
586METHOD_ARGS_END
587
588METHODS_BEGIN
589  METHOD_DESCRIBE(IsStudioLoaded, ladish_is_studio_loaded)
590  METHOD_DESCRIBE(GetStudioList, ladish_get_studio_list)
591  METHOD_DESCRIBE(NewStudio, ladish_new_studio)
592  METHOD_DESCRIBE(LoadStudio, ladish_load_studio)
593  METHOD_DESCRIBE(DeleteStudio, ladish_delete_studio)
594  METHOD_DESCRIBE(GetApplicationList, ladish_get_application_list)
595  METHOD_DESCRIBE(GetRoomList, ladish_get_room_list)
596  METHOD_DESCRIBE(NewRoom, ladish_new_room)
597  METHOD_DESCRIBE(DeleteRoom, ladish_delete_room)
598  METHOD_DESCRIBE(Exit, ladish_exit)
599METHODS_END
600
601SIGNAL_ARGS_BEGIN(StudioAppeared, "Studio D-Bus object appeared")
602SIGNAL_ARGS_END
603
604SIGNAL_ARGS_BEGIN(StudioDisappeared, "Studio D-Bus object disappeared")
605SIGNAL_ARGS_END
606
607SIGNAL_ARGS_BEGIN(CleanExit, "Exit was requested")
608SIGNAL_ARGS_END
609
610SIGNALS_BEGIN
611  SIGNAL_DESCRIBE(StudioAppeared)
612  SIGNAL_DESCRIBE(StudioDisappeared)
613  SIGNAL_DESCRIBE(CleanExit)
614SIGNALS_END
615
616/*
617 * Interface description.
618 */
619
620INTERFACE_BEGIN(g_lashd_interface_control, INTERFACE_NAME)
621  INTERFACE_DEFAULT_HANDLER
622  INTERFACE_EXPOSE_METHODS
623  INTERFACE_EXPOSE_SIGNALS
624INTERFACE_END
Note: See TracBrowser for help on using the browser.