root/trunk/libffado/support/dbus/ffado-dbus-server.cpp

Revision 1498, 10.4 kB (checked in by ppalmers, 12 years ago)

Merge all changes from 2.0 branch into trunk (since r1361). This _should_ contain all forward merges done in the mean time. At this moment in time both branches should be in sync.

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