📄 headset.c
字号:
dbus_message_unref(msg); return 0;}static int rfcomm_connect(struct device *dev, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id){ struct headset *hs = dev->headset; struct sockaddr_rc addr; GIOChannel *io; char address[18]; int sk, err; if (hs->rfcomm_ch < 0) return get_handles(dev, cb, user_data, cb_id); ba2str(&dev->dst, address); debug("%s: Connecting to %s channel %d", dev->path, address, hs->rfcomm_ch); sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sk < 0) { err = errno; error("socket(BTPROTO_RFCOMM): %s (%d)", strerror(err), err); return -err; } io = g_io_channel_unix_new(sk); if (!io) { close(sk); return -ENOMEM; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, BDADDR_ANY); addr.rc_channel = 0; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = errno; error("bind: %s (%d)", strerror(errno), errno); goto failed; } if (set_nonblocking(sk) < 0) { err = errno; goto failed; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, &dev->dst); addr.rc_channel = hs->rfcomm_ch; err = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) { err = errno; error("connect() failed: %s (%d)", strerror(err), err); goto failed; } headset_set_state(dev, HEADSET_STATE_CONNECT_IN_PROGRESS); pending_connect_init(hs, HEADSET_STATE_CONNECTED); if (cb) { unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data); if (cb_id) *cb_id = id; } g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_connect_cb, dev); hs->pending->io = io; return 0;failed: g_io_channel_close(io); g_io_channel_unref(io); return -err;}static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS) return error_not_connected(conn, msg); headset_set_state(device, HEADSET_STATE_CONNECTED); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; dbus_bool_t playing; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; playing = (hs->state == HEADSET_STATE_PLAYING); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; char hs_address[18]; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->state == HEADSET_STATE_DISCONNECTED) return error_not_connected(conn, msg); headset_set_state(device, HEADSET_STATE_DISCONNECTED); ba2str(&device->dst, hs_address); info("Disconnected from %s, %s", hs_address, device->path); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_is_connected(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; DBusMessage *reply; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; connected = (device->headset->state >= HEADSET_STATE_CONNECTED); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; int err; if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS) return error_in_progress(conn, msg, "Connect in progress"); else if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS) return error_already_connected(conn, msg); err = rfcomm_connect(device, NULL, NULL, NULL); if (err < 0) return error_connection_attempt_failed(conn, msg, -err); hs->auto_dc = FALSE; hs->pending->msg = dbus_message_ref(msg); return DBUS_HANDLER_RESULT_HANDLED;}static gboolean ring_timer_cb(gpointer data){ struct device *device = data; struct headset *hs = device->headset; int err; err = headset_send(hs, "\r\nRING\r\n"); if (err < 0) error("Error while sending RING: %s (%d)", strerror(-err), -err); if (hs->cli_active && hs->ph_number) { err = headset_send(hs, "\r\n+CLIP:\"%s\",%d\r\n", hs->ph_number, hs->type); if (err < 0) error("Error while sending CLIP: %s (%d)", strerror(-err), -err); } return TRUE;}static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; int err; if (hs->state < HEADSET_STATE_CONNECTED) return error_not_connected(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->ring_timer) { debug("IndicateCall received when already indicating"); goto done; } err = headset_send(hs, "\r\nRING\r\n"); if (err < 0) { dbus_message_unref(reply); return error_failed_errno(conn, msg, -err); } if (hs->cli_active && hs->ph_number) { err = headset_send(hs, "\r\n+CLIP:\"%s\",%d\r\n", hs->ph_number, hs->type); if (err < 0) { dbus_message_unref(reply); return error_failed_errno(conn, msg, -err); } } hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);done: send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; if (hs->state < HEADSET_STATE_CONNECTED) return error_not_connected(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (!hs->ring_timer) { debug("Got CancelRinging method call but ringing is not in progress"); goto done; } g_source_remove(hs->ring_timer); hs->ring_timer = 0;done: if (hs->hfp_active) { int err; /*+CIEV: (callsetup = 0)*/ err = headset_send(hs, "\r\n+CIEV:3,0\r\n"); if (err < 0) { dbus_message_unref(reply); return error_failed_errno(conn, msg, -err); } } send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; int err; if (sco_hci) { error("Refusing Headset.Play() because SCO HCI routing " "is enabled"); return error_not_available(conn, msg); } switch (hs->state) { case HEADSET_STATE_DISCONNECTED: case HEADSET_STATE_CONNECT_IN_PROGRESS: return error_not_connected(conn, msg); case HEADSET_STATE_PLAY_IN_PROGRESS: return error_in_progress(conn, msg, "Play in progress"); case HEADSET_STATE_PLAYING: return error_already_connected(conn, msg); case HEADSET_STATE_CONNECTED: default: break; } err = sco_connect(device, NULL, NULL, NULL); if (err < 0) return error_failed(conn, msg, strerror(-err)); hs->pending->msg = dbus_message_ref(msg); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_get_speaker_gain(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; dbus_uint16_t gain; if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0) return error_not_available(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; gain = (dbus_uint16_t) hs->sp_gain; dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_get_mic_gain(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; dbus_uint16_t gain; if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0) return error_not_available(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; gain = (dbus_uint16_t) hs->mic_gain; dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_set_gain(DBusConnection *conn, DBusMessage *msg, void *data, char type){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; DBusError derr; dbus_uint16_t gain; int err; if (hs->state < HEADSET_STATE_CONNECTED) return error_not_connected(conn, msg); dbus_error_init(&derr); dbus_message_get_args(msg, &derr, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); if (dbus_error_is_set(&derr)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } if (gain > 15) return error_invalid_arguments(conn, msg, "Must be less than or equal to 15"); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (hs->state != HEADSET_STATE_PLAYING) goto done; err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain); if (err < 0) { dbus_message_unref(reply); return error_failed(conn, msg, "Unable to send to headset"); }done: if (type == HEADSET_GAIN_SPEAKER) { hs->sp_gain = gain; dbus_connection_emit_signal(conn, device->path, AUDIO_HEADSET_INTERFACE, "SpeakerGainChanged", DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); } else { hs->mic_gain = gain; dbus_connection_emit_signal(conn, device->path, AUDIO_HEADSET_INTERFACE, "MicrophoneGainChanged", DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); } send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_set_speaker_gain(DBusConnection *conn, DBusMessage *msg, void *data){ return hs_set_gain(conn, msg, data, HEADSET_GAIN_SPEAKER);}static DBusHandlerResult hs_set_mic_gain(DBusConnection *conn, DBusMessage *msg, void *data){ return hs_set_gain(conn, msg, data, HEADSET_GAIN_MICROPHONE);}static DBusHandlerResult hf_setup_call(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; DBusError derr; const char *value; int err; if (!hs->hfp_active) return error_not_supported(device->conn, msg); if (hs->state < HEADSET_STATE_CONNECTED) return error_not_connected(conn, msg); dbus_error_init(&derr); dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID); if (dbus_error_is_set(&derr)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; } reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; if (!strncmp(value, "incoming", 8)) err = headset_send(hs, "\r\n+CIEV:3,1\r\n"); else if (!strncmp(value, "outgoing", 8)) err = headset_send(hs, "\r\n+CIEV:3,2\r\n"); else if (!strncmp(value, "remote", 6)) err = headset_send(hs, "\r\n+CIEV:3,3\r\n"); else err = -EINVAL; if (err < 0) { dbus_message_unref(reply); return error_failed_errno(conn, msg, -err); } send_message_and_unref(conn, reply); return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hf_identify_call(DBusConnection *conn, DBusMessage *msg, void *data){ struct device *device = data; struct headset *hs = device->headset; DBusMessage *reply; DBusError derr; const char *number; dbus_int32_t type; if (!hs->hfp_active && !hs->cli_active) return error_not_supported(device->conn, msg); if (hs->state < HEADSET_STATE_CONNECTED) return error_not_connected(conn, msg); dbus_error_init(&derr); dbus_message_get_args(msg, &derr, DBUS_TYPE_STRING, &number, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID); if (dbus_error_is_set(&derr)) { error_invalid_arguments(conn, msg, derr.message); dbus_error_free(&derr); return DBUS_HANDLER_RESULT_HANDLED; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -