📄 unix.c
字号:
a2dp->stream = NULL;}static void create_stream(struct device *dev, struct unix_client *client){ struct a2dp_data *a2dp; unsigned int id; client->type = select_service(dev, client->interface); switch (client->type) { case TYPE_SINK: a2dp = &client->d.a2dp; if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); if (!a2dp->session) { error("Unable to get a session"); goto failed; } /* FIXME: The provided media_codec breaks bitpool selection. So disable it. This needs fixing */ id = a2dp_source_request_stream(a2dp->session, TRUE, a2dp_setup_complete, client, NULL/*client->media_codec*/); client->cancel_stream = a2dp_source_cancel_stream; break; case TYPE_HEADSET: id = headset_request_stream(dev, headset_setup_complete, client); client->cancel_stream = headset_cancel_stream; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("request_stream failed"); goto failed; } client->req_id = id; client->dev = dev; return;failed: unix_send_cfg(client->sock, NULL, -1);}static void create_cb(struct device *dev, void *user_data){ struct unix_client *client = user_data; if (!dev) unix_send_cfg(client->sock, NULL, -1); else create_stream(dev, client);}static int cfg_to_caps(struct ipc_data_cfg *cfg, struct sbc_codec_cap *sbc_cap){ struct ipc_codec_sbc *sbc = (void *) cfg->data; memset(sbc_cap, 0, sizeof(struct sbc_codec_cap)); sbc_cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; sbc_cap->cap.media_codec_type = A2DP_CODEC_SBC; switch (cfg->rate) { case 48000: sbc_cap->frequency = A2DP_SAMPLING_FREQ_48000; break; case 44100: sbc_cap->frequency = A2DP_SAMPLING_FREQ_44100; break; case 32000: sbc_cap->frequency = A2DP_SAMPLING_FREQ_32000; break; case 16000: sbc_cap->frequency = A2DP_SAMPLING_FREQ_16000; break; default: sbc_cap->frequency = A2DP_SAMPLING_FREQ_44100; break; } switch (cfg->mode) { case CFG_MODE_MONO: sbc_cap->channel_mode = A2DP_CHANNEL_MODE_MONO; break; case CFG_MODE_DUAL_CHANNEL: sbc_cap->channel_mode = A2DP_CHANNEL_MODE_DUAL_CHANNEL; break; case CFG_MODE_STEREO: sbc_cap->channel_mode = A2DP_CHANNEL_MODE_STEREO; break; case CFG_MODE_JOINT_STEREO: sbc_cap->channel_mode = A2DP_CHANNEL_MODE_JOINT_STEREO; break; default: sbc_cap->channel_mode = A2DP_CHANNEL_MODE_JOINT_STEREO; break; } switch (sbc->allocation) { case CFG_ALLOCATION_LOUDNESS: sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS; break; case CFG_ALLOCATION_SNR: sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS; break; default: sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS; break; } switch (sbc->subbands) { case 8: sbc_cap->subbands = A2DP_SUBBANDS_8; break; case 4: sbc_cap->subbands = A2DP_SUBBANDS_4; break; default: sbc_cap->subbands = A2DP_SUBBANDS_8; break; } switch (sbc->blocks) { case 16: sbc_cap->block_length = A2DP_BLOCK_LENGTH_16; break; case 12: sbc_cap->block_length = A2DP_BLOCK_LENGTH_12; break; case 8: sbc_cap->block_length = A2DP_BLOCK_LENGTH_8; break; case 4: sbc_cap->block_length = A2DP_BLOCK_LENGTH_4; break; default: sbc_cap->block_length = A2DP_BLOCK_LENGTH_16; break; } if (sbc->bitpool != 0) { if (sbc->bitpool > 250) return -EINVAL; sbc_cap->min_bitpool = sbc->bitpool; sbc_cap->max_bitpool = sbc->bitpool; } return 0;}static void cfg_event(struct unix_client *client, struct ipc_packet *pkt, int len){ struct device *dev; bdaddr_t bdaddr; struct ipc_data_cfg *cfg = (void *) pkt->data; struct sbc_codec_cap sbc_cap; str2ba(pkt->device, &bdaddr); client->fd_opt = cfg->fd_opt; if (client->interface) { g_free(client->interface); client->interface = NULL; } if (pkt->role == PKT_ROLE_VOICE) client->interface = g_strdup(AUDIO_HEADSET_INTERFACE); else if (pkt->role == PKT_ROLE_HIFI) client->interface = g_strdup(AUDIO_SINK_INTERFACE); if (cfg_to_caps(cfg, &sbc_cap) < 0) goto failed; client->media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap, sizeof(sbc_cap)); if (!manager_find_device(&bdaddr, NULL, FALSE)) { if (!bacmp(&bdaddr, BDADDR_ANY)) goto failed; if (!manager_create_device(&bdaddr, create_cb, client)) goto failed; return; } dev = manager_find_device(&bdaddr, client->interface, TRUE); if (!dev) dev = manager_find_device(&bdaddr, client->interface, FALSE); if (!dev) goto failed; create_stream(dev, client); return;failed: unix_send_cfg(client->sock, NULL, -1);}static void ctl_event(struct unix_client *client, struct ipc_packet *pkt, int len){}static int reply_state(int sock, struct ipc_packet *pkt){ struct ipc_data_state *state = (struct ipc_data_state *) pkt->data; int len; info("status=%u", state->state); pkt->type = PKT_TYPE_STATE_RSP; pkt->length = sizeof(struct ipc_data_state); pkt->error = PKT_ERROR_NONE; len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_state); len = send(sock, pkt, len, 0); if (len < 0) error("Error %s(%d)", strerror(errno), errno); debug("%d bytes sent", len); return 0;}static void state_event(struct unix_client *client, struct ipc_packet *pkt, int len){#if 0 struct ipc_data_state *state = (struct ipc_data_state *) pkt->data; struct device *dev = client->dev; if (len > sizeof(struct ipc_packet)) device_set_state(dev, state->state); else state->state = device_get_state(dev);#endif reply_state(client->sock, pkt);}static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data){ char buf[IPC_MTU]; struct ipc_packet *pkt = (void *) buf; struct unix_client *client = data; int len, len_check; struct a2dp_data *a2dp = &client->d.a2dp; struct headset_data *hs = &client->d.hs; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { debug("Unix client disconnected (fd=%d)", client->sock); switch (client->type) { case TYPE_HEADSET: if (client->dev) headset_unlock(client->dev, hs->lock); break; case TYPE_SOURCE: case TYPE_SINK: if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } break; default: break; } if (client->cancel_stream && client->req_id > 0) client->cancel_stream(client->dev, client->req_id); goto failed; } memset(buf, 0, sizeof(buf)); len = recv(client->sock, buf, sizeof(buf), 0); if (len < 0) { error("recv: %s (%d)", strerror(errno), errno); goto failed; } len_check = pkt->length + sizeof(struct ipc_packet); if (len != len_check) { error("Packet lenght doesn't match"); goto failed; } switch (pkt->type) { case PKT_TYPE_CFG_REQ: info("Package PKT_TYPE_CFG_REQ:%u", pkt->role); cfg_event(client, pkt, len); break; case PKT_TYPE_STATE_REQ: info("Package PKT_TYPE_STATE_REQ"); state_event(client, pkt, len); break; case PKT_TYPE_CTL_REQ: info("Package PKT_TYPE_CTL_REQ"); ctl_event(client, pkt, len); break; } return TRUE;failed: clients = g_slist_remove(clients, client); client_free(client); return FALSE;}static gboolean server_cb(GIOChannel *chan, GIOCondition cond, gpointer data){ struct sockaddr_un addr; socklen_t addrlen; int sk, cli_sk; struct unix_client *client; GIOChannel *io; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { g_io_channel_close(chan); return FALSE; } sk = g_io_channel_unix_get_fd(chan); memset(&addr, 0, sizeof(addr)); addrlen = sizeof(addr); cli_sk = accept(sk, (struct sockaddr *) &addr, &addrlen); if (cli_sk < 0) { error("accept: %s (%d)", strerror(errno), errno); return TRUE; } debug("Accepted new client connection on unix socket (fd=%d)", cli_sk); client = g_new0(struct unix_client, 1); client->sock = cli_sk; clients = g_slist_append(clients, client); io = g_io_channel_unix_new(cli_sk); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, client_cb, client); g_io_channel_unref(io); return TRUE;}int unix_init(void){ GIOChannel *io; struct sockaddr_un addr = { AF_UNIX, IPC_SOCKET_NAME }; int sk, err; sk = socket(PF_LOCAL, SOCK_STREAM, 0); if (sk < 0) { err = errno; error("Can't create unix socket: %s (%d)", strerror(err), err); return -err; } if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { error("Can't bind unix socket: %s (%d)", strerror(errno), errno); close(sk); return -1; } set_nonblocking(sk); unix_sock = sk; listen(sk, 1); io = g_io_channel_unix_new(sk); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, server_cb, NULL); g_io_channel_unref(io); info("Unix socket created: %d", sk); return 0;}void unix_exit(void){ g_slist_foreach(clients, (GFunc) client_free, NULL); g_slist_free(clients); close(unix_sock); unix_sock = -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -