📄 a2dpd_dbus.c
字号:
/*** A2DPD - Bluetooth A2DP daemon for Linux** Copyright (C) 2006 Frédéric DALLEAU <frederic.dalleau@palmsource.com>** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <pthread.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include "a2dpd_dbus.h"#include "a2dpd_protocol.h"#define DBUS_API_SUBJECT_TO_CHANGE#include <dbus/dbus-glib.h>#include <dbus/dbus-glib-lowlevel.h>// D-Bus constants#define A2DPD_SERVICE_NAME "com.access.a2dpd"#define A2DPD_SERVICE_PATH "/com/access/a2dpd"#define A2DPD_SERVER_INTERFACE_NAME A2DPD_SERVICE_NAME ".server"#define A2DPD_SERVER_FAILED_ERROR "com.access.Error.Failed"#define A2DPD_SERVER_PARAM_ERROR "com.access.Error.ParamError"#define A2DPD_SERVER_BUSY_ERROR "com.access.Error.Busy"#define A2DPD_SERVER_NOT_SUPPORTED_ERROR "com.access.Error.NotSupported"#define A2DPD_SERVER_ALREADY_EXISTS_ERROR "com.access.Error.AlreadyExists"#define A2DPD_SERVER_NOT_EXIST_ERROR "com.access.Error.DoesNotExist"static DBusGConnection *gconnection = NULL;static pthread_t a2dpd_dbus_thread;static GMainLoop *loop = NULL;static int ctl_socket = 0;int write_config_string(char *filename, char *section, char *key, char *value){ GError *error = NULL; GKeyFile *key_file = g_key_file_new(); gchar *key_file_data = NULL; unsigned int key_file_len = 0; int result = EINVAL; if (key_file) { g_key_file_load_from_file(key_file, filename, G_KEY_FILE_KEEP_COMMENTS, &error); if (error) { DBG("Failed to load key file %s: %s", filename, error->message); g_error_free(error); error = NULL; } g_key_file_set_value(key_file, section, key, value); key_file_data = g_key_file_to_data(key_file, &key_file_len, &error); if (error) { DBG("Failed to convert keyfile %s to data: %s", filename, error->message); g_error_free(error); error = NULL; } g_key_file_free(key_file); if (key_file_data) { /* Why do this fail on UML?? Is it because we use busybox and not a real unix with all compatible commands... result = g_file_set_contents(filename, key_file_data, key_file_len, &error); if(error) { g_print("3) %d bytes: %s", key_file_len, error->message); g_error_free(error); error = NULL; */ FILE *hFile = fopen(filename, "wt"); if (hFile) { if ((int) (fwrite((void *) key_file_data, key_file_len, 1, hFile)) != 1) { DBG("Write failed (errno=%d:%s)", errno, strerror(errno)); result = errno; } else { DBG("Write %s successful", filename); result = 0; } fclose(hFile); } else { DBG("fopen %s failed", filename); result = errno; } } } return result;}static DBusHandlerResult a2dpd_dbus_Connect(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char c = 'c'; DBG("Begin"); write(ctl_socket, &c, sizeof(c)); DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_Disconnect(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char c = 'd'; DBG("Begin"); write(ctl_socket, &c, sizeof(c)); DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_StreamStart(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char c = 's'; DBG("Begin"); write(ctl_socket, &c, sizeof(c)); DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_StreamSuspend(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char c = 'p'; DBG("Begin"); write(ctl_socket, &c, sizeof(c)); DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_Startup(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ // This dummy method is intended to be used with activation // Calling startup should startup the daemon thanks to dbus activation return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_Exit(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ kill(getpid(), SIGTERM); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_Save(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char c = 'w'; DBG("Begin"); write(ctl_socket, &c, sizeof(c)); DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_SetAddress(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char addr[32]; char* lpszParam = NULL; char c = 't'; DBG("Begin"); if(dbus_message_get_args(message, error, DBUS_TYPE_STRING, &lpszParam, DBUS_TYPE_INVALID)) { memset(addr, 0, sizeof(addr)); strncpy(addr, lpszParam, sizeof(addr)); write(ctl_socket, &c, sizeof(c)); write(ctl_socket, &addr, sizeof(addr)); } DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_AutoConnect(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char* lpszParam = NULL; char c0 = 'a'; char c1 = 'a'; DBG("Begin"); if(dbus_message_get_args(message, error, DBUS_TYPE_STRING, &lpszParam, DBUS_TYPE_INVALID)) { DBG("Param %s", lpszParam); write(ctl_socket, &c0, sizeof(c0)); if(!strcasecmp(lpszParam, "swap")) { c1 = 'a'; } else if(!strcasecmp(lpszParam, "0")) { c1 = '0'; } else { c1 = '1'; } write(ctl_socket, &c1, sizeof(c1)); } DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_SetDebug(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char* lpszParam = NULL; DBG("Begin"); if(dbus_message_get_args(message, error, DBUS_TYPE_STRING, &lpszParam, DBUS_TYPE_INVALID)) { DBG("Param %s", lpszParam); if(!strcasecmp(lpszParam, "0")) { g_bdebug = 0; } else { g_bdebug = 1; } } DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_SetVolume(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char* lpszParam = NULL; char c = 'v'; int param = 0; DBG("Begin"); if(dbus_message_get_args(message, error, DBUS_TYPE_STRING, &lpszParam, DBUS_TYPE_INVALID)) { param = atoi(lpszParam); DBG("Param %s => %d", lpszParam, param); write(ctl_socket, &c, sizeof(c)); write(ctl_socket, ¶m, sizeof(param)); } DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_SetFlags(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char* lpszParam = NULL; char c = 'f'; int param = 0; DBG("Begin"); if(dbus_message_get_args(message, error, DBUS_TYPE_STRING, &lpszParam, DBUS_TYPE_INVALID)) { param = atoi(lpszParam); DBG("Param %s => %d", lpszParam, param); write(ctl_socket, &c, sizeof(c)); write(ctl_socket, ¶m, sizeof(param)); } DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult a2dpd_dbus_SetReReadConfig(DBusMessage * message, DBusMessage * reply, DBusError* error, void *user_data){ char* lpszParam = NULL; char c = 'r'; int param = 0; DBG("Begin"); if(dbus_message_get_args(message, error, DBUS_TYPE_STRING, &lpszParam, DBUS_TYPE_INVALID)) { param = atoi(lpszParam); DBG("Param %s => %d", lpszParam, param); write(ctl_socket, &c, sizeof(c)); write(ctl_socket, ¶m, sizeof(param)); } DBG("OK"); return DBUS_HANDLER_RESULT_HANDLED;}void a2dpd_signal_command(char* dir, char* cmd){ // Print a trace DBG("%s", cmd); // Send signal if connected if (gconnection != NULL) { DBusMessage *signal = dbus_message_new_signal (A2DPD_SERVICE_PATH, A2DPD_SERVER_INTERFACE_NAME, "A2Command"); if(signal) { if (dbus_message_append_args (signal, DBUS_TYPE_STRING, &dir, DBUS_TYPE_STRING, &cmd, DBUS_TYPE_INVALID)) { // In case this gets fired off after we've disconnected. if (dbus_connection_get_is_connected (dbus_g_connection_get_connection(gconnection))) { dbus_connection_send (dbus_g_connection_get_connection(gconnection), signal, NULL); } } dbus_message_unref(signal); } }}void a2dpd_signal_state(int state, char* bdaddr){ static int s_state = -1; if(state != s_state) { char* signal_name = (state==DISCONNECTED)?"Disconnected":(state==CONNECTING)?"Connecting":"Connected"; DBG("%s %s", signal_name, bdaddr); // Send signal if connected if (gconnection != NULL) { DBusMessage *signal = dbus_message_new_signal (A2DPD_SERVICE_PATH, A2DPD_SERVER_INTERFACE_NAME, "A2StateChange"); if(signal) { if (dbus_message_append_args (signal, DBUS_TYPE_STRING, &signal_name, DBUS_TYPE_STRING, &bdaddr, DBUS_TYPE_INVALID)) { // In case this gets fired off after we've disconnected. if (dbus_connection_get_is_connected (dbus_g_connection_get_connection(gconnection))) { dbus_connection_send (dbus_g_connection_get_connection(gconnection), signal, NULL); } } dbus_message_unref(signal); } } // Print a trace s_state = state; }}static DBusHandlerResult a2dpd_handler_func(DBusConnection * connection, DBusMessage * message, void *user_data){ DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; DBusError dbusError; DBusMessage *reply = dbus_message_new_method_return(message); if (reply) { dbus_error_init(&dbusError); DBG(""); // Methods if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "Connect")) result = a2dpd_dbus_Connect(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "Disconnect")) result = a2dpd_dbus_Disconnect(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "StreamStart")) result = a2dpd_dbus_StreamStart(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "StreamSuspend")) result = a2dpd_dbus_StreamSuspend(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "SetAddress")) result = a2dpd_dbus_SetAddress(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "AutoConnect")) result = a2dpd_dbus_AutoConnect(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "SetDebug")) result = a2dpd_dbus_SetDebug(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "SetVolume")) result = a2dpd_dbus_SetVolume(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "SetFlags")) result = a2dpd_dbus_SetFlags(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "SetReReadConfig")) result = a2dpd_dbus_SetReReadConfig(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "Startup")) result = a2dpd_dbus_Startup(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "Exit")) result = a2dpd_dbus_Exit(message, reply, &dbusError, user_data); if (dbus_message_is_method_call(message, A2DPD_SERVER_INTERFACE_NAME, "Save")) result = a2dpd_dbus_Save(message, reply, &dbusError, user_data); // Signals if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { DBG("Disconnected from BUS"); //result = a2dpd_dbus_Exit(message, reply, &dbusError, user_data); result = DBUS_HANDLER_RESULT_HANDLED; } // Send answers if(!dbus_connection_send(connection, reply, NULL)) { DBG("Failed to send reply"); result = DBUS_HANDLER_RESULT_NEED_MEMORY; } dbus_message_unref(reply); dbus_error_free(&dbusError); } else { DBG("Failed to allocate reply"); result = DBUS_HANDLER_RESULT_NEED_MEMORY; } return result;}void *a2dpd_thread_handler(void *param){ DBusError dbusError; static DBusObjectPathVTable dbus_vtable_a2dpd_server = { NULL, a2dpd_handler_func, NULL, NULL, NULL, NULL }; dbus_error_init(&dbusError); if (gconnection != NULL) { DBG("Registering object path: "A2DPD_SERVICE_PATH); if (dbus_connection_register_object_path(dbus_g_connection_get_connection(gconnection), A2DPD_SERVICE_PATH, &dbus_vtable_a2dpd_server, NULL)) { DBG("Acquiring service: " A2DPD_SERVICE_NAME); if(dbus_bus_request_name(dbus_g_connection_get_connection(gconnection), A2DPD_SERVICE_NAME, 0, &dbusError)) { if (!dbus_error_is_set(&dbusError)) { // Run main loop DBG("Running ..."); g_main_loop_run(loop); DBG("Closing ..."); } else { DBG("Failed to acquire service[2]: %s", dbusError.message); } } else { DBG("Failed to acquire service: %s", dbusError.message); } } else { DBG("Failed to register object path"); } } dbus_error_free(&dbusError); return NULL;}void a2dpd_signal_init(int session_bus){ GError *gError = NULL; pthread_attr_t tattr; size_t size = PTHREAD_STACK_MIN; DBG(""); if (!g_thread_supported ()) g_thread_init (NULL); g_type_init(); loop = g_main_loop_new(NULL, FALSE); DBG("Getting on DBUS"); gconnection = dbus_g_bus_get((session_bus)?DBUS_BUS_SESSION:DBUS_BUS_SYSTEM, &gError); if(gconnection != NULL) { // Start thread pthread_attr_init(&tattr); pthread_attr_setstacksize(&tattr, size); pthread_create(&a2dpd_dbus_thread, &tattr, a2dpd_thread_handler, NULL); pthread_attr_destroy(&tattr); } else { DBG("Failed to get on DBUS: %s", gError->message); } if(gError) g_error_free(gError); DBG("OK");}void a2dpd_signal_set_socket(int a2dpd_ctl_socket){ DBG("Signal socket set to %d", a2dpd_ctl_socket); ctl_socket = a2dpd_ctl_socket;}void a2dpd_signal_kill(){ DBG(""); if (loop) { g_main_quit(loop); } DBG("joining"); pthread_join(a2dpd_dbus_thread, NULL); DBG("OK");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -