#include #include #include #include #include #include #include #include #include #include #include #include #include #include "gdbus/gdbus.h" #include "avrcpctrl.h" #include "a2dp_source/a2dp_masterctrl.h" #include "DeviceIo.h" //#include "Rk_shell.h" #include "slog.h" #define COLOR_OFF "\x1B[0m" #define COLOR_RED "\x1B[0;91m" #define COLOR_GREEN "\x1B[0;92m" #define COLOR_YELLOW "\x1B[0;93m" #define COLOR_BLUE "\x1B[0;94m" #define COLOR_BOLDGRAY "\x1B[1;30m" #define COLOR_BOLDWHITE "\x1B[1;37m" /* String display constants */ #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF #define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF #define COLORED_DEL COLOR_RED "DEL" COLOR_OFF #define PROMPT_ON COLOR_BLUE "[bluetooth]" COLOR_OFF "# " #define PROMPT_OFF "[bluetooth]# " static GList *proxy_list; static const char *last_device_path = NULL; static char last_obj_path[] = "/org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx"; static GDBusProxy *last_connected_device_proxy = NULL; static GDBusProxy *last_temp_connected_device_proxy = NULL; static GList *device_list; static guint reconnect_timer; #define STORAGE_PATH "/data/cfg/lib/bluetooth" static void device_connected_post(GDBusProxy *proxy); #define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1" #define BLUEZ_MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1" #define BLUEZ_MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1" #define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1" extern DBusConnection *dbus_conn; static GDBusProxy *default_player; static GSList *players = NULL; static GSList *folders = NULL; static GSList *items = NULL; static int first_ctrl = 1; extern GDBusClient *btsrc_client; static int g_btsrc_connect_status = RK_BT_SINK_STATE_IDLE; extern void print_iter(const char *label, const char *name, DBusMessageIter *iter); typedef struct { RK_BT_SINK_CALLBACK avrcp_sink_cb; RK_BT_AVRCP_TRACK_CHANGE_CB avrcp_track_cb; RK_BT_AVRCP_PLAY_POSITION_CB avrcp_position_cb; RK_BT_SINK_VOLUME_CALLBACK avrcp_volume_cb; } avrcp_callback_t; static avrcp_callback_t g_avrcp_cb = { NULL, NULL, NULL, NULL, }; static char track_key[256]; static int current_song_len = 0; void bt_sink_state_send(RK_BT_SINK_STATE state) { if (g_avrcp_cb.avrcp_sink_cb) (g_avrcp_cb.avrcp_sink_cb)(state); } void report_avrcp_event(enum BtEvent event, void *data, int len) { pr_info("[AVRCP DEBUG]: event: %d \n", event); switch(event) { case BT_SINK_ENV_CONNECT: g_btsrc_connect_status = RK_BT_SINK_STATE_CONNECT; bt_sink_state_send(RK_BT_SINK_STATE_CONNECT); break; case BT_SINK_ENV_DISCONNECT: g_btsrc_connect_status = RK_BT_SINK_STATE_DISCONNECT; bt_sink_state_send(RK_BT_SINK_STATE_DISCONNECT); break; case BT_EVENT_START_PLAY: bt_sink_state_send(RK_BT_SINK_STATE_PLAY); break; case BT_EVENT_PAUSE_PLAY: bt_sink_state_send(RK_BT_SINK_STATE_PAUSE); break; case BT_EVENT_STOP_PLAY: bt_sink_state_send(RK_BT_SINK_STATE_STOP); break; default: break; } } bool system_command(const char* cmd) { pid_t status = 0; bool ret_value = false; status = system(cmd); if (-1 == status) { } else { if (WIFEXITED(status)) { if (0 == WEXITSTATUS(status)) { ret_value = true; } else { } } else { } } return ret_value; } void rkbt_inquiry_scan(bool scan) { if (scan) system_command("hciconfig hci0 piscan"); else system_command("hciconfig hci0 noscan"); } struct adapter { GDBusProxy *proxy; GDBusProxy *ad_proxy; GList *devices; }; extern struct adapter *default_ctrl; extern GList *ctrl_list; static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master) { DBusMessageIter iter; const char *adapter, *path; if (!master) return FALSE; if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE) return FALSE; dbus_message_iter_get_basic(&iter, &adapter); path = g_dbus_proxy_get_path(master); if (!strcmp(path, adapter)) return TRUE; return FALSE; } static struct adapter *find_parent(GDBusProxy *device) { GList *list; for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) { struct adapter *parent_adapter = (struct adapter*)(list->data); if (device_is_child(device, parent_adapter->proxy) == TRUE) return parent_adapter; } return NULL; } void connect_handler(DBusConnection *connection, void *user_data) { pr_info("%s \n", __func__); } void disconnect_handler(DBusConnection *connection, void *user_data) { pr_info("%s \n", __func__); } void print_folder(GDBusProxy *proxy, const char *description) { const char *path; path = g_dbus_proxy_get_path(proxy); } void folder_removed(GDBusProxy *proxy) { folders = g_slist_remove(folders, proxy); print_folder(proxy, COLORED_DEL); } char *proxy_description(GDBusProxy *proxy, const char *title, const char *description) { const char *path; path = g_dbus_proxy_get_path(proxy); return g_strdup_printf("%s%s%s%s %s ", description ? "[" : "", description ? : "", description ? "] " : "", title, path); } void print_player(GDBusProxy *proxy, const char *description) { char *str; char strplay[256]; str = proxy_description(proxy, "Player", description); memset(strplay, 0x00, 256); sprintf(strplay,"%s%s\n", str, (default_player == proxy ? "[default]" : "")); pr_info(strplay); g_free(str); } void player_added(GDBusProxy *proxy) { pr_info("player_added \n"); if (g_slist_length(players) == 0) { pr_info("=== add set last_connected_device_proxy 0x%p \n", proxy); last_connected_device_proxy = last_temp_connected_device_proxy; device_connected_post(last_connected_device_proxy); report_avrcp_event(BT_SINK_ENV_CONNECT, NULL, 0); pr_info("[D: %s]: BT_SNK_DEVICE CONNECTED\n", __func__); system("hciconfig hci0 noscan"); system("hciconfig hci0 noscan"); } players = g_slist_append(players, proxy); if (default_player == NULL) { pr_info("set default player: %s\n", g_dbus_proxy_get_path(proxy)); default_player = proxy; } print_player(proxy, COLORED_NEW); } void print_item(GDBusProxy *proxy, const char *description) { const char *path, *name; DBusMessageIter iter; path = g_dbus_proxy_get_path(proxy); if (g_dbus_proxy_get_property(proxy, "Name", &iter)) dbus_message_iter_get_basic(&iter, &name); else name = ""; } void item_added(GDBusProxy *proxy) { items = g_slist_append(items, proxy); print_item(proxy, COLORED_NEW); } void folder_added(GDBusProxy *proxy) { folders = g_slist_append(folders, proxy); print_folder(proxy, COLORED_NEW); } static GDBusProxy *proxy_lookup(GList *list, int *index, const char *path, const char *interface) { GList *l; if (!interface) return NULL; for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) { GDBusProxy *proxy = (GDBusProxy *)(l->data); const char *proxy_iface = g_dbus_proxy_get_interface(proxy); const char *proxy_path = g_dbus_proxy_get_path(proxy); if (index) (*index)++; /* Proxy info mybe error. */ if (!proxy_iface || !proxy_path) { pr_info("ERROR: %s proxy info error! proxy_iface:%s, proxy_path:%s\n", __func__, proxy_iface, proxy_path); return NULL; } if (g_str_equal(proxy_iface, interface) == TRUE && g_str_equal(proxy_path, path) == TRUE) return proxy; } return NULL; } static GDBusProxy *proxy_lookup_client(GDBusClient *client, int *index, const char* path, const char *interface) { return proxy_lookup(proxy_list, index, path, interface); } static const char *load_connected_device(const char *str) { int fd; int result; char path[64]; sprintf(path, "%s/%s/reconnect", STORAGE_PATH, str); pr_info("Load path %s", path); result = access(path, F_OK); if (result == -1) { pr_info("%s doesnot exist", path); return NULL; } fd = open(path, O_RDONLY); if (fd == -1) { pr_info("Open %s error: %s", path, strerror(errno)); return NULL; } result = read(fd, last_obj_path, sizeof(last_obj_path) - 1); close(fd); if (result > 0) { pr_info("Previous device path: %s", last_obj_path); return last_obj_path; } else { pr_info("Read %s error: %s", path, strerror(errno)); return NULL; } } static void store_connected_device(GDBusProxy *proxy) { int fd; int result; const char *object_path; struct adapter *adapter = find_parent(proxy); char path[64]; DBusMessageIter iter; const char *str; if (!adapter) return; if (g_dbus_proxy_get_property(adapter->proxy, "Address", &iter) == FALSE) { pr_err("Get adapter address error"); return; } dbus_message_iter_get_basic(&iter, &str); sprintf(path, "%s/%s/reconnect", STORAGE_PATH, str); pr_info("Store path: %s", path); object_path = g_dbus_proxy_get_path(proxy); pr_info("Connected device object path: %s", object_path); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644); if (fd == -1) { pr_info("Open %s error: %s", path, strerror(errno)); return; } result = write(fd, object_path, strlen(object_path) + 1); close(fd); if (result > 0) memcpy(last_obj_path, object_path, sizeof(last_obj_path) - 1); else pr_info("Write %s error: %s", path, strerror(errno)); } static void device_connected_post(GDBusProxy *proxy) { int device_num = g_list_length(device_list); pr_info("Connected device number %d", device_num); if (!device_num) return; store_connected_device(proxy); } static void disconn_device_reply(DBusMessage * message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { if (strstr(error.name, "Failed")) pr_info("disconn_device_reply failed\n"); dbus_error_free(&error); } } #define RECONN_INTERVAL 2 static void reconn_last_device_reply(DBusMessage * message, void *user_data) { DBusError error; static int count = 1; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { if (strstr(error.name, "Failed") && (count > 0)) { pr_info("Retry to reconn_last connect, count %d", count); count--; reconnect_timer = g_timeout_add_seconds(RECONN_INTERVAL, reconn_last, NULL); dbus_error_free(&error); return; } report_avrcp_event(BT_SINK_ENV_CONNECT_FAIL, NULL, 0); dbus_error_free(&error); } count = 1; } bool disconn_device(void) { GDBusProxy *proxy = last_connected_device_proxy; DBusMessageIter iter, addr_iter; dbus_bool_t connected; if (!proxy) { pr_info("Invalid proxy, stop disconnecting\n"); return FALSE; } pr_info("disconnect g_dbus_proxy_get_path [0x%p]: %s\n", proxy, g_dbus_proxy_get_path(proxy)); if (g_dbus_proxy_get_property(proxy, "Address", &addr_iter) == TRUE) { const char *address; dbus_message_iter_get_basic(&addr_iter, &address); pr_info("disconn_device addrs %s ", address); } if (g_dbus_proxy_get_property(proxy, "Connected", &iter)) { dbus_message_iter_get_basic(&iter, &connected); if (!connected) return FALSE; } if (g_list_length(device_list) <= 0) { pr_info("Device already disconnected"); return FALSE; } pr_info("disconnect target device: %s", g_dbus_proxy_get_path(proxy)); if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_device_reply, last_connected_device_proxy, NULL) == FALSE) { pr_info("Failed to call org.bluez.Device1.Disonnect"); } return TRUE; } bool reconn_last(void) { GDBusProxy *proxy = last_connected_device_proxy; DBusMessageIter addr_iter, addrType_iter; int fd, ret, reconnect = 1; char buff[100] = {0}; fd = open("/userdata/cfg/bt_reconnect", O_RDONLY); if (fd > 0) { ret = read(fd, buff, sizeof(buff)); if (ret > 0) { if (strstr(buff, "bluez-reconnect:disable")) reconnect = 0; } close(fd); } if (reconnect == 0) { pr_info("%s: automatic reconnection is disabled!", __func__); return 0; } if (bt_is_connected()) { pr_info("%s: The device is connected and does not need to be reconnected!", __func__); return 0; } if (reconnect_timer) { g_source_remove(reconnect_timer); reconnect_timer = 0; } pr_info("%s: lcdp: 0x%p, last_device_path: %s.\n", __func__, last_connected_device_proxy, last_device_path); if ((!last_connected_device_proxy) && last_device_path) { /* Check if the device exists */ last_connected_device_proxy = proxy_lookup_client( btsrc_client, NULL, last_device_path, "org.bluez.Device1"); proxy = last_connected_device_proxy; } if (!proxy) { pr_info("Invalid proxy, stop reconnecting\n"); return FALSE; } if (g_list_length(device_list) > 0) { pr_info("Device device_list: %d.\n", g_list_length(device_list)); //return FALSE; } pr_info("reconn_last target device: %s", g_dbus_proxy_get_path(proxy)); if (g_dbus_proxy_get_property(proxy, "Address", &addr_iter) == TRUE) { const char *address; dbus_message_iter_get_basic(&addr_iter, &address); pr_info("disconn_device addrs %s ", address); } if (g_dbus_proxy_get_property(proxy, "AddressType", &addrType_iter) == TRUE) { const char *addrType; dbus_message_iter_get_basic(&addrType_iter, &addrType); pr_info("addrType %s ", addrType); if (strcmp(addrType, "random") == 0) return 0; } if (g_dbus_proxy_method_call(proxy, "Connect", NULL, reconn_last_device_reply, last_connected_device_proxy, NULL) == FALSE) { pr_info("Failed to call org.bluez.Device1.Connect"); } return FALSE; } static int adapter_is_powered(GDBusProxy *proxy) { DBusMessageIter iter; dbus_bool_t powered; if (g_dbus_proxy_get_property(proxy, "Powered", &iter)) { dbus_message_iter_get_basic(&iter, &powered); if (powered) return 1; } return 0; } void a2dp_sink_device_added(GDBusProxy *proxy) { const char *path = g_dbus_proxy_get_path(proxy); dbus_bool_t connected = 0; static int first = 1; DBusMessageIter iter; proxy_list = g_list_append(proxy_list, proxy); if (g_dbus_proxy_get_property(proxy, "Connected", &iter)) { dbus_message_iter_get_basic(&iter, &connected); if (connected) { device_list = g_list_append(device_list, proxy); pr_info("=== BT SINK set last_temp_connected_device_proxy %p \n", proxy); last_temp_connected_device_proxy = proxy; return; } } } void a2dp_sink_proxy_added(GDBusProxy *proxy, void *user_data) { pr_info("BT SINK proxy_added\n"); const char *interface; interface = g_dbus_proxy_get_interface(proxy); pr_info("BT SINK proxy_added interface:%s \n", interface); if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) player_added(proxy); else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE)) folder_added(proxy); else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE)) item_added(proxy); if (!strcmp(interface, "org.bluez.Device1")) { //a2dp_sink_device_added(proxy); } else if (!strcmp(interface, "org.bluez.Adapter1")) { DBusMessageIter iter; const char *str; if (!g_dbus_proxy_get_property(proxy, "Address", &iter)) { pr_err("Failed to get adapter address"); return; } dbus_message_iter_get_basic(&iter, &str); if (!first_ctrl) return; first_ctrl = 0; /* Load previous connected device */ last_device_path = load_connected_device(str); } } void player_removed(GDBusProxy *proxy) { print_player(proxy, COLORED_DEL); if (default_player == proxy) { default_player = NULL; } players = g_slist_remove(players, proxy); if (g_slist_length(players) == 0) { pr_info("[D: %s]: BT_SNK_DEVICE DISCONNECTED\n", __func__); report_avrcp_event(BT_SINK_ENV_DISCONNECT, NULL, 0); system("hciconfig hci0 piscan"); system("hciconfig hci0 piscan"); } } void item_removed(GDBusProxy *proxy) { items = g_slist_remove(items, proxy); print_item(proxy, COLORED_DEL); } void a2dp_sink_proxy_removed(GDBusProxy *proxy, void *user_data) { const char *interface; pr_info("BT SINK proxy_removed\n"); interface = g_dbus_proxy_get_interface(proxy); if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) player_removed(proxy); if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE)) folder_removed(proxy); if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE)) item_removed(proxy); } static void save_track_info(BtTrackInfo *track, const char *valstr, unsigned int valu32) { if(!strcmp(track_key, "Title") && valstr != NULL) memcpy(track->title, valstr, strlen(valstr)); else if(!strcmp(track_key, "Album") && valstr != NULL) memcpy(track->album, valstr, strlen(valstr)); else if(!strcmp(track_key, "Artist") && valstr != NULL) memcpy(track->artist, valstr, strlen(valstr)); else if(!strcmp(track_key, "Genre") && valstr != NULL) memcpy(track->genre, valstr, strlen(valstr)); else if(!strcmp(track_key, "TrackNumber")) sprintf(track->track_num, "%d", valu32); else if(!strcmp(track_key, "NumberOfTracks")) sprintf(track->num_tracks, "%d", valu32); else if(!strcmp(track_key, "Duration")) { sprintf(track->playing_time, "%d", valu32); current_song_len = valu32; } memset(track_key, 0, 256); } static void avrcp_get_track_info(BtTrackInfo *track, const char *name, DBusMessageIter *iter) { dbus_uint32_t valu32; const char *valstr; DBusMessageIter subiter; char *entry; switch (dbus_message_iter_get_arg_type(iter)) { case DBUS_TYPE_STRING: dbus_message_iter_get_basic(iter, &valstr); if(!strncmp(name, "Track Key", 9)) memcpy(track_key, valstr, strlen(valstr)); else if(!strncmp(name, "Track Value", 11)) save_track_info(track, valstr, 0); break; case DBUS_TYPE_UINT32: dbus_message_iter_get_basic(iter, &valu32); if(!strncmp(name, "Track Value", 11)) save_track_info(track, NULL, (unsigned int)valu32); break; case DBUS_TYPE_VARIANT: dbus_message_iter_recurse(iter, &subiter); avrcp_get_track_info(track, name, &subiter); break; case DBUS_TYPE_ARRAY: dbus_message_iter_recurse(iter, &subiter); while (dbus_message_iter_get_arg_type(&subiter) != DBUS_TYPE_INVALID) { avrcp_get_track_info(track, name, &subiter); dbus_message_iter_next(&subiter); } break; case DBUS_TYPE_DICT_ENTRY: dbus_message_iter_recurse(iter, &subiter); entry = g_strconcat(name, " Key", NULL); avrcp_get_track_info(track, entry, &subiter); g_free(entry); entry = g_strconcat(name, " Value", NULL); dbus_message_iter_next(&subiter); avrcp_get_track_info(track, entry, &subiter); g_free(entry); break; } } static void avrcp_track_info_send(const char *name, DBusMessageIter *iter) { char addr[18]; DBusMessageIter addr_iter; BtTrackInfo track; if(strncmp(name, "Track", 5)) return; memset(addr, 0, 18); bt_get_default_dev_addr(addr, 18); memset(track_key, 0, 256); memset(&track, 0, sizeof(BtTrackInfo)); avrcp_get_track_info(&track, name, iter); if(g_avrcp_cb.avrcp_track_cb) { g_avrcp_cb.avrcp_track_cb(addr, track); } } static void avrcp_position_send(const char *name, DBusMessageIter *iter) { dbus_uint32_t valu32; char addr[18]; if(strncmp(name, "Position", 8)) return; memset(addr, 0, 18); bt_get_default_dev_addr(addr, 18); dbus_message_iter_get_basic(iter, &valu32); if(g_avrcp_cb.avrcp_position_cb) g_avrcp_cb.avrcp_position_cb(addr, current_song_len, valu32); } static void avrcp_volume_send(const char *name, DBusMessageIter *iter) { dbus_uint16_t valu16; if(strncmp(name, "Volume", 6)) return; dbus_message_iter_get_basic(iter, &valu16); pr_info("Volume: 0x%2x\n", valu16); if(g_avrcp_cb.avrcp_volume_cb) g_avrcp_cb.avrcp_volume_cb(valu16); } void player_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter) { char *str; str = proxy_description(proxy, "Player", COLORED_CHG); pr_info("player_property_changed: str: %s, name: %s\n", str, name); avrcp_track_info_send(name, iter); avrcp_position_send(name, iter); print_iter(str, name, iter); g_free(str); } void folder_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter) { char *str; str = proxy_description(proxy, "Folder", COLORED_CHG); print_iter(str, name, iter); g_free(str); } void item_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter) { char *str; str = proxy_description(proxy, "Item", COLORED_CHG); print_iter(str, name, iter); g_free(str); } void transport_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter) { char *str; const char *valstr; str = proxy_description(proxy, "MediaTransport1", COLORED_CHG); if (!strncmp(name, "State", 5)) { dbus_message_iter_get_basic(iter, &valstr); if (strstr(valstr, "active")) bt_sink_state_send(RK_BT_A2DP_SINK_STARTED); else if (strstr(valstr, "idle")) bt_sink_state_send(RK_BT_A2DP_SINK_SUSPENDED); } avrcp_volume_send(name, iter); print_iter(str, name, iter); g_free(str); } void device_changed(GDBusProxy *proxy, DBusMessageIter *iter, void *user_data) { dbus_bool_t val; const char *object_path = g_dbus_proxy_get_path(proxy); dbus_message_iter_get_basic(iter, &val); pr_info("%s connect status changed to %s", object_path, val ? "TRUE" : "FALSE"); if (val) { device_list = g_list_append(device_list, proxy); last_temp_connected_device_proxy = proxy; } else { /* Device has been stored when being connected */ device_list = g_list_remove(device_list, proxy); } } void adapter_changed(GDBusProxy *proxy, DBusMessageIter *iter, void *user_data) { dbus_bool_t val; dbus_message_iter_get_basic(iter, &val); pr_info("Adapter powered changed to %s", val ? "TRUE" : "FALSE"); } void a2dp_sink_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter, void *user_data) { const char *interface; interface = g_dbus_proxy_get_interface(proxy); pr_info("BT SINK: property_changed %s\n", interface); if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) player_property_changed(proxy, name, iter); else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE)) folder_property_changed(proxy, name, iter); else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE)) item_property_changed(proxy, name, iter); else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) transport_property_changed(proxy, name, iter); } bool check_default_player(void) { if (!default_player) { if (NULL != players) { GSList *l; l = players; GDBusProxy *proxy = (GDBusProxy *)l->data; default_player = proxy; pr_info("set default player\n"); return TRUE; } pr_info("No default player available\n"); return FALSE; } pr_info(" player ok\n"); return TRUE; } gboolean option_version = FALSE; GOptionEntry options[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, "Show version information and exit" }, { NULL }, }; int init_avrcp_ctrl(void) { proxy_list = NULL; last_device_path = NULL; last_connected_device_proxy = NULL; device_list = NULL; reconnect_timer = 0; return 1; } void a2dp_sink_open(void) { pr_info("call avrcp_thread init_avrcp\n"); g_btsrc_connect_status = RK_BT_SINK_STATE_IDLE; system("hciconfig hci0 piscan"); system("hciconfig hci0 piscan"); } int release_avrcp_ctrl(void) { pr_info("=== release_avrcp_ctrl ===\n"); g_btsrc_connect_status = RK_BT_SINK_STATE_IDLE; system("hciconfig hci0 noscan"); system("hciconfig hci0 noscan"); return 0; } int release_avrcp_ctrl2(void) { pr_info("=== release_avrcp_ctrl2 ===\n"); g_btsrc_connect_status = RK_BT_SINK_STATE_IDLE; return 0; } void play_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to play\n"); dbus_error_free(&error); return; } pr_info("Play successful\n"); } int play_avrcp(void) { if (!check_default_player()) return -1; if (g_dbus_proxy_method_call(default_player, "Play", NULL, play_reply, NULL, NULL) == FALSE) { pr_info("Failed to play\n"); return -1; } pr_info("Attempting to play\n"); return 0; } void pause_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to pause: %s\n", __func__); dbus_error_free(&error); return; } pr_info("Pause successful\n"); } int pause_avrcp(void) { if (!check_default_player()) return -1; if (g_dbus_proxy_method_call(default_player, "Pause", NULL, pause_reply, NULL, NULL) == FALSE) { pr_info("Failed to pause\n"); return -1; } pr_info("Attempting to pause\n"); return 0; } void volumedown_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to volume down\n"); dbus_error_free(&error); return; } pr_info("volumedown successful\n"); } void volumedown_avrcp(void) { if (!check_default_player()) return; if (g_dbus_proxy_method_call(default_player, "VolumeDown", NULL, volumedown_reply, NULL, NULL) == FALSE) { pr_info("Failed to volumeup\n"); return; } pr_info("Attempting to volumeup\n"); } void volumeup_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to volumeup\n"); dbus_error_free(&error); return; } pr_info("volumeup successful\n"); } void volumeup_avrcp() { if (!check_default_player()) return; if (g_dbus_proxy_method_call(default_player, "VolumeUp", NULL, volumeup_reply, NULL, NULL) == FALSE) { pr_info("Failed to volumeup\n"); return; } pr_info("Attempting to volumeup\n"); } void stop_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { //rl_printf("Failed to stop: %s\n", error.name); dbus_error_free(&error); return; } pr_info("Stop successful\n"); } int stop_avrcp() { if (!check_default_player()) return -1; if (g_dbus_proxy_method_call(default_player, "Stop", NULL, stop_reply, NULL, NULL) == FALSE) { pr_info("Failed to stop\n"); return -1; } pr_info("Attempting to stop\n"); return 0; } void next_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to jump to next\n"); dbus_error_free(&error); return; } pr_info("Next successful\n"); } int next_avrcp(void) { { if (!check_default_player()) return -1; if (g_dbus_proxy_method_call(default_player, "Next", NULL, next_reply, NULL, NULL) == FALSE) { pr_info("Failed to jump to next\n"); return -1; } pr_info("Attempting to jump to next\n"); } return 0; } void previous_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to jump to previous\n"); dbus_error_free(&error); return; } pr_info("Previous successful\n"); } int previous_avrcp(void) { if (!check_default_player()) return -1; if (g_dbus_proxy_method_call(default_player, "Previous", NULL, previous_reply, NULL, NULL) == FALSE) { pr_info("Failed to jump to previous\n"); return -1; } pr_info("Attempting to jump to previous\n"); return 0; } void fast_forward_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to fast forward\n"); dbus_error_free(&error); return; } pr_info("FastForward successful\n"); } void fast_forward_avrcp() { { if (!check_default_player()) return; if (g_dbus_proxy_method_call(default_player, "FastForward", NULL, fast_forward_reply, NULL, NULL) == FALSE) { pr_info("Failed to jump to previous\n"); return; } pr_info("Fast forward playback\n"); } } void rewind_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to rewind\n"); dbus_error_free(&error); return; } pr_info("Rewind successful\n"); } void rewind_avrcp(){ { if (!check_default_player()) return; if (g_dbus_proxy_method_call(default_player, "Rewind", NULL, rewind_reply, NULL, NULL) == FALSE) { pr_info("Failed to rewind\n"); return; } pr_info("Rewind playback\n"); } } int getstatus_avrcp(void) { GDBusProxy *proxy; DBusMessageIter iter; const char *valstr; if (check_default_player() == FALSE) return AVRCP_PLAY_STATUS_ERROR; //default player no find proxy = default_player; if (g_dbus_proxy_get_property(proxy, "Status", &iter) == FALSE) return AVRCP_PLAY_STATUS_ERROR; //unkonw status dbus_message_iter_get_basic(&iter, &valstr); //pr_info("----getstatus_avrcp,rtl wifi,return %s--\n",valstr); if (!strcasecmp(valstr, "stopped")) return AVRCP_PLAY_STATUS_STOPPED; else if (!strcasecmp(valstr, "playing")) return AVRCP_PLAY_STATUS_PLAYING; else if (!strcasecmp(valstr, "paused")) return AVRCP_PLAY_STATUS_PAUSED; else if (!strcasecmp(valstr, "forward-seek")) return AVRCP_PLAY_STATUS_FWD_SEEK; else if (!strcasecmp(valstr, "reverse-seek")) return AVRCP_PLAY_STATUS_REV_SEEK; else if (!strcasecmp(valstr, "error")) return AVRCP_PLAY_STATUS_ERROR; return AVRCP_PLAY_STATUS_ERROR; } void get_play_status_reply(DBusMessage *message, void *user_data) { DBusError error; dbus_error_init(&error); if (dbus_set_error_from_message(&error, message) == TRUE) { pr_info("Failed to GetPlayStatus\n"); dbus_error_free(&error); return; } pr_info("GetPlayStatus successful\n"); } int get_play_status_avrcp() { if (!check_default_player()) return -1; if (g_dbus_proxy_method_call(default_player, "GetPlayStatus", NULL, get_play_status_reply, NULL, NULL) == FALSE) { pr_info("Failed to GetPlayStatus\n"); return -1; } pr_info("GetPlayStatus playback\n"); return 0; } bool get_poschange_avrcp() { DBusMessageIter iter; dbus_bool_t pos_change = FALSE; if (check_default_player() == FALSE) return FALSE; if (g_dbus_proxy_get_property(default_player, "PosChange", &iter) == FALSE) { pr_info("Failed to get PosChange\n"); return FALSE; } dbus_message_iter_get_basic(&iter, &pos_change); return pos_change; } void a2dp_sink_register_cb(RK_BT_SINK_CALLBACK cb) { g_avrcp_cb.avrcp_sink_cb = cb; } void a2dp_sink_register_track_cb(RK_BT_AVRCP_TRACK_CHANGE_CB cb) { g_avrcp_cb.avrcp_track_cb = cb; } void a2dp_sink_register_position_cb(RK_BT_AVRCP_PLAY_POSITION_CB cb) { g_avrcp_cb.avrcp_position_cb = cb; } void a2dp_sink_register_volume_cb(RK_BT_SINK_VOLUME_CALLBACK cb) { g_avrcp_cb.avrcp_volume_cb = cb; } void a2dp_sink_clear_cb() { g_avrcp_cb.avrcp_sink_cb = NULL; g_avrcp_cb.avrcp_track_cb = NULL; g_avrcp_cb.avrcp_position_cb = NULL; g_avrcp_cb.avrcp_volume_cb = NULL; } int a2dp_sink_status(RK_BT_SINK_STATE *pState) { int avrcp_status; if (!pState) return -1; avrcp_status = getstatus_avrcp(); switch (avrcp_status) { case AVRCP_PLAY_STATUS_STOPPED: *pState = RK_BT_SINK_STATE_STOP; break; case AVRCP_PLAY_STATUS_REV_SEEK: case AVRCP_PLAY_STATUS_FWD_SEEK: case AVRCP_PLAY_STATUS_PLAYING: *pState = RK_BT_SINK_STATE_PLAY; break; case AVRCP_PLAY_STATUS_PAUSED: *pState = RK_BT_SINK_STATE_PAUSE; break; default: if (g_btsrc_connect_status == RK_BT_SINK_STATE_CONNECT) *pState = RK_BT_SINK_STATE_CONNECT; else *pState = RK_BT_SINK_STATE_IDLE; break; } return 0; }