root/branches/libffado-2.0/support/dbus/ffado-dbus-server.cpp

Revision 1297, 9.7 kB (checked in by ppalmers, 12 years ago)

improve signals

Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  * Copyright (C) 2005-2008 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 /*
26  * This version uses the CPP API
27  */
28
29 #include <config.h>
30 #include <semaphore.h>
31
32 #include "libffado/ffado.h"
33
34 #include "debugmodule/debugmodule.h"
35 #include "fbtypes.h"
36 #include "devicemanager.h"
37 #include "ffadodevice.h"
38
39 #include <dbus-c++/dbus.h>
40 #include "controlserver.h"
41 #include "libcontrol/BasicElements.h"
42
43 #include "libutil/Functors.h"
44
45 #include <signal.h>
46
47 #include <argp.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 #include <vector>
53 #include <string>
54 #include <iostream>
55 #include <sstream>
56
57 using namespace std;
58
59 DECLARE_GLOBAL_DEBUG_MODULE;
60
61 // DBUS stuff
62 DBus::BusDispatcher dispatcher;
63 DBusControl::Container *container = NULL;
64 DBus::Connection * global_conn;
65 DeviceManager *m_deviceManager = NULL;
66
67 // signal handler
68 int run=1;
69 sem_t run_sem;
70
71 static void sighandler (int sig)
72 {
73     run = 0;
74     dispatcher.leave();
75     sem_post(&run_sem);
76 }
77
78 // global's
79 const char *argp_program_version = PACKAGE_STRING;
80 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
81
82 // Program documentation.
83 static char doc[] = "ffado-dbus-server -- expose the mixer features of connected FFADO devices through DBus\n\n"
84                     ;
85
86 // A description of the arguments we accept.
87 static char args_doc[] = "";
88
89 struct arguments
90 {
91     short silent;
92     short verbose;
93     int   use_cache;
94     int   port;
95     int   node_id;
96     int   node_id_set;
97     const char* args[2];
98 };
99
100 // The options we understand.
101 static struct argp_option options[] = {
102     {"quiet",    'q',       0,    0,  "Don't produce any output" },
103     {"silent",   's',       0,    OPTION_ALIAS },
104
105     {"verbose",  'v', "level",    0,  "Produce verbose output" },
106 #if ENABLE_DISCOVERY_CACHE
107     {"cache",    'c', "enable",   0,  "Use AVC model cache" },
108 #endif
109
110     {"node",     'n',    "id",    0,  "Only expose mixer of a device on a specific node" },
111     {"port",     'p',    "nr",    0,  "IEEE1394 Port to use" },
112     { 0 }
113 };
114
115 //-------------------------------------------------------------
116
117 // Parse a single option.
118 static error_t
119 parse_opt( int key, char* arg, struct argp_state* state )
120 {
121     // Get the input argument from `argp_parse', which we
122     // know is a pointer to our arguments structure.
123     struct arguments* arguments = ( struct arguments* ) state->input;
124     char* tail;
125
126     errno = 0;
127     switch (key) {
128     case 'q': case 's':
129         arguments->silent = 1;
130         break;
131     case 'v':
132         if (arg) {
133             arguments->verbose = strtol( arg, &tail, 0 );
134             if ( errno ) {
135                 debugError( "Could not parse 'verbose' argument\n" );
136                 return ARGP_ERR_UNKNOWN;
137             }
138         }
139         break;
140     case 'c':
141         if (arg) {
142             arguments->use_cache = strtol( arg, &tail, 0 );
143             if ( errno ) {
144                 fprintf( stderr,  "Could not parse 'cache' argument\n" );
145                 return ARGP_ERR_UNKNOWN;
146             }
147         }
148         break;
149     case 'p':
150         if (arg) {
151             arguments->port = strtol( arg, &tail, 0 );
152             if ( errno ) {
153                 debugError( "Could not parse 'port' argument\n" );
154                 return ARGP_ERR_UNKNOWN;
155             }
156         } else {
157             if ( errno ) {
158                 debugError("Could not parse 'port' argumen\n" );
159                 return ARGP_ERR_UNKNOWN;
160             }
161         }
162         break;
163     case 'n':
164         if (arg) {
165             arguments->node_id = strtol( arg, &tail, 0 );
166             if ( errno ) {
167                 debugError( "Could not parse 'node' argument\n" );
168                 return ARGP_ERR_UNKNOWN;
169             }
170             arguments->node_id_set=1;
171         } else {
172             if ( errno ) {
173                 debugError("Could not parse 'node' argumen\n" );
174                 return ARGP_ERR_UNKNOWN;
175             }
176         }
177         break;
178     case ARGP_KEY_ARG:
179         if (state->arg_num >= 1) {
180             // Too many arguments.
181             argp_usage( state );
182         }
183         arguments->args[state->arg_num] = arg;
184         break;
185     case ARGP_KEY_END:
186         if (state->arg_num < 0) {
187         // Not enough arguments.
188         argp_usage( state );
189         }
190         break;
191     default:
192         return ARGP_ERR_UNKNOWN;
193     }
194     return 0;
195 }
196
197 // Our argp parser.
198 static struct argp argp = { options, parse_opt, args_doc, doc };
199
200 int exitfunction( int retval ) {
201     debugOutput( DEBUG_LEVEL_NORMAL, "Debug output flushed...\n" );
202     flushDebugOutput();
203     return retval;
204 }
205
206 void
207 preUpdateHandler()
208 {
209     debugOutput( DEBUG_LEVEL_NORMAL, "got pre-update notification...\n" );
210     // stop receiving dbus events since the control structure is going to
211     // be changed
212     dispatcher.leave();
213 }
214
215 void
216 postUpdateHandler()
217 {
218     debugOutput( DEBUG_LEVEL_NORMAL, "got post-update notification...\n" );
219     // the signal handlers registered by the elements should have taken
220     // care of updating the control tree
221
222     // signal that we can start receiving dbus events again
223     sem_post(&run_sem);
224 }
225
226 int
227 main( int argc, char **argv )
228 {
229     struct arguments arguments;
230
231     // Default values.
232     arguments.silent      = 0;
233     arguments.verbose     = DEBUG_LEVEL_NORMAL;
234     arguments.use_cache   = 1;
235     arguments.port        = 0;
236     arguments.node_id     = 0;
237     arguments.node_id_set = 0; // if we don't specify a node, discover all
238     arguments.args[0]     = "";
239     arguments.args[1]     = "";
240
241     setDebugLevel(arguments.verbose);
242
243     // Parse our arguments; every option seen by `parse_opt' will
244     // be reflected in `arguments'.
245     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
246         debugError("Could not parse command line\n" );
247         return exitfunction(-1);
248     }
249     printMessage("FFADO Control DBUS service\n");
250
251     debugOutput( DEBUG_LEVEL_NORMAL, "verbose level = %d\n", arguments.verbose);
252     debugOutput( DEBUG_LEVEL_NORMAL, "Using ffado library version: %s\n\n", ffado_get_version() );
253
254
255     printMessage(" Discovering devices...\n");
256     m_deviceManager = new DeviceManager();
257     if ( !m_deviceManager ) {
258         debugError("Could not allocate device manager\n" );
259         return exitfunction(-1);
260     }
261     if ( !m_deviceManager->initialize() ) {
262         debugError("Could not initialize device manager\n" );
263         delete m_deviceManager;
264         return exitfunction(-1);
265     }
266     if ( arguments.verbose ) {
267         m_deviceManager->setVerboseLevel(arguments.verbose);
268     }
269     if ( !m_deviceManager->discover(arguments.use_cache) ) {
270         debugError("Could not discover devices\n" );
271         delete m_deviceManager;
272         return exitfunction(-1);
273     }
274
275     // add pre-update handler
276     Util::Functor* preupdate_functor = new Util::CallbackFunctor0< void (*)() >
277                 ( &preUpdateHandler, false );
278     if ( !preupdate_functor ) {
279         debugFatal( "Could not create pre-update handler\n" );
280         return false;
281     }
282     if(!m_deviceManager->registerPreUpdateNotification(preupdate_functor)) {
283         debugError("could not register pre-update notifier");
284     }
285     // add post-update handler
286     Util::Functor* postupdate_functor = new Util::CallbackFunctor0< void (*)() >
287                 ( &postUpdateHandler, false );
288     if ( !postupdate_functor ) {
289         debugFatal( "Could not create post-update handler\n" );
290         return false;
291     }
292     if(!m_deviceManager->registerPostUpdateNotification(postupdate_functor)) {
293         debugError("could not register post-update notifier");
294     }
295
296     signal (SIGINT, sighandler);
297
298     printMessage(" Starting DBUS service...\n");
299     DBus::_init_threading();
300
301     // test DBUS stuff
302     DBus::default_dispatcher = &dispatcher;
303     DBus::Connection conn = DBus::Connection::SessionBus();
304     global_conn = &conn;
305     conn.request_name("org.ffado.Control");
306
307     // lock the control tree such that it does not get modified while we build our view
308     m_deviceManager->lockControl();
309     container = new DBusControl::Container(conn, "/org/ffado/Control/DeviceManager",
310                                             NULL, *m_deviceManager);
311     // unlock the control tree since the tree is built
312     m_deviceManager->unlockControl();
313
314     printMessage(" Running... (press ctrl-c to stop & exit)\n");
315    
316     while(run) {
317         debugOutput( DEBUG_LEVEL_NORMAL, "dispatching...\n");
318         dispatcher.enter();
319
320         debugOutput( DEBUG_LEVEL_NORMAL, " dispatcher exited...\n");
321         sem_wait(&run_sem);
322         debugOutput( DEBUG_LEVEL_NORMAL, " activity handled...\n");
323     }
324
325     printMessage(" Stopping...\n");
326     if(!m_deviceManager->unregisterPreUpdateNotification(preupdate_functor)) {
327         debugError("could not unregister pre update notifier");
328     }
329     delete preupdate_functor;
330     if(!m_deviceManager->unregisterPostUpdateNotification(postupdate_functor)) {
331         debugError("could not unregister post update notifier");
332     }
333     delete postupdate_functor;
334     delete container;
335     delete m_deviceManager;
336
337     signal (SIGINT, SIG_DFL);
338
339     printMessage(" Bye.\n");
340     return exitfunction(0);
341 }
Note: See TracBrowser for help on using the browser.