📄 pcm_bluetooth.c
字号:
struct pollfd *pfd, unsigned int space){ struct bluetooth_data *data = io->private_data; assert(io); if (space < 1) return 0; pfd[0].fd = data->stream.fd; pfd[0].events = POLLIN; pfd[0].revents = 0; return 1;}static int bluetooth_poll_revents(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED, struct pollfd *pfds, unsigned int nfds, unsigned short *revents){ assert(pfds && nfds == 1 && revents); *revents = pfds[0].revents; return 0;}static int bluetooth_playback_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space){ struct bluetooth_data *data = io->private_data; DBG(""); assert(data->pipefd[0] >= 0); if (space < 1) return 0; pfd[0].fd = data->pipefd[0]; pfd[0].events = POLLIN; pfd[0].revents = 0; return 1;}static int bluetooth_playback_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents){ static char buf[1]; int ret; DBG(""); assert(pfds); assert(nfds == 1); assert(revents); assert(pfds[0].fd >= 0); if (io->state != SND_PCM_STATE_PREPARED) ret = read(pfds[0].fd, buf, 1); *revents = (pfds[0].revents & ~POLLIN) | POLLOUT; return 0;}static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size){ struct bluetooth_data *data = io->private_data; struct ipc_data_cfg cfg = data->cfg; snd_pcm_uframes_t frames_to_write, ret; unsigned char *buff; int nrecv, frame_size = 0; DBG("areas->step=%u areas->first=%u offset=%lu size=%lu io->nonblock=%u", areas->step, areas->first, offset, size, io->nonblock); if (data->count > 0) goto proceed; frame_size = areas->step / 8; nrecv = recv(data->stream.fd, data->buffer, cfg.pkt_len, MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0)); if (nrecv < 0) { ret = (errno == EPIPE) ? -EIO : -errno; goto done; } if (nrecv != cfg.pkt_len) { ret = -EIO; SNDERR(strerror(-ret)); goto done; } /* Increment hardware transmition pointer */ data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;proceed: buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8; if ((data->count + size * frame_size) <= cfg.pkt_len) frames_to_write = size; else frames_to_write = (cfg.pkt_len - data->count) / frame_size; memcpy(buff, data->buffer + data->count, frame_size * frames_to_write); data->count += (frame_size * frames_to_write); data->count %= cfg.pkt_len; /* Return written frames count */ ret = frames_to_write;done: DBG("returning %lu", ret); return ret;}static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size){ struct bluetooth_data *data = io->private_data; struct ipc_data_cfg cfg = data->cfg; snd_pcm_sframes_t ret = 0; snd_pcm_uframes_t frames_to_read; uint8_t *buff; int rsend, frame_size; DBG("areas->step=%u areas->first=%u offset=%lu, size=%lu io->nonblock=%u", areas->step, areas->first, offset, size, io->nonblock); if (io->hw_ptr > io->appl_ptr) { ret = bluetooth_playback_stop(io); if (ret == 0) ret = -EPIPE; goto done; } frame_size = areas->step / 8; if ((data->count + size * frame_size) <= cfg.pkt_len) frames_to_read = size; else frames_to_read = (cfg.pkt_len - data->count) / frame_size; DBG("count=%d frames_to_read=%lu", data->count, frames_to_read); /* Ready for more data */ buff = (uint8_t *) areas->addr + (areas->first + areas->step * offset) / 8; memcpy(data->buffer + data->count, buff, frame_size * frames_to_read); /* Remember we have some frames in the pipe now */ data->count += frames_to_read * frame_size; if (data->count != cfg.pkt_len) { ret = frames_to_read; goto done; } rsend = send(data->stream.fd, data->buffer, cfg.pkt_len, io->nonblock ? MSG_DONTWAIT : 0); if (rsend > 0) { /* Reset count pointer */ data->count = 0; ret = frames_to_read; } else if (rsend < 0) ret = (errno == EPIPE) ? -EIO : -errno; else ret = -EIO;done: DBG("returning %ld", ret); return ret;}static snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size){ snd_pcm_uframes_t ret = 0; return ret;}static int avdtp_write(struct bluetooth_data *data){ int ret = 0; struct rtp_header *header; struct rtp_payload *payload; struct bluetooth_a2dp *a2dp = &data->a2dp; header = (void *) a2dp->buffer; payload = (void *) (a2dp->buffer + sizeof(*header)); memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload)); payload->frame_count = a2dp->frame_count; header->v = 2; header->pt = 1; header->sequence_number = htons(a2dp->seq_num); header->timestamp = htonl(a2dp->nsamples); header->ssrc = htonl(1); ret = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT); if (ret == -1) ret = -errno; /* Reset buffer of data to send */ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); a2dp->frame_count = 0; a2dp->samples = 0; a2dp->seq_num++; return ret;}static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size){ struct bluetooth_data *data = io->private_data; struct bluetooth_a2dp *a2dp = &data->a2dp; snd_pcm_sframes_t ret = 0; snd_pcm_uframes_t frames_to_read; int frame_size, encoded; uint8_t *buff; DBG("areas->step=%u areas->first=%u offset=%lu size=%lu", areas->step, areas->first, offset, size); DBG("hw_ptr=%lu appl_ptr=%lu", io->hw_ptr, io->appl_ptr); if (io->hw_ptr > io->appl_ptr) { ret = bluetooth_playback_stop(io); if (ret == 0) ret = -EPIPE; goto done; } /* Check if we should autostart */ if (io->state == SND_PCM_STATE_PREPARED) { snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t threshold; snd_pcm_sw_params_malloc(&swparams); if (!snd_pcm_sw_params_current(io->pcm, swparams) && !snd_pcm_sw_params_get_start_threshold(swparams, &threshold)) { if (io->appl_ptr >= threshold) { ret = snd_pcm_start(io->pcm); if (ret != 0) goto done; } } snd_pcm_sw_params_free(swparams); } frame_size = areas->step / 8; if ((data->count + size * frame_size) <= a2dp->codesize) frames_to_read = size; else frames_to_read = (a2dp->codesize - data->count) / frame_size; DBG("count=%d frames_to_read=%lu", data->count, frames_to_read); DBG("a2dp.count=%d cfg.pkt_len=%d", a2dp->count, data->cfg.pkt_len); /* FIXME: If state is not streaming then return */ /* Ready for more data */ buff = (uint8_t *) areas->addr + (areas->first + areas->step * offset) / 8; memcpy(data->buffer + data->count, buff, frame_size * frames_to_read); /* Remember we have some frames in the pipe now */ data->count += frames_to_read * frame_size; if (data->count != a2dp->codesize) { ret = frames_to_read; goto done; } /* Enough data to encode (sbc wants 1k blocks) */ encoded = sbc_encode(&(a2dp->sbc), data->buffer, a2dp->codesize); if (encoded <= 0) { DBG("Encoding error %d", encoded); goto done; } data->count -= encoded; DBG("encoded=%d a2dp.sbc.len=%d", encoded, a2dp->sbc.len); if (a2dp->count + a2dp->sbc.len >= data->cfg.pkt_len) { ret = avdtp_write(data); if (ret < 0) { if (-ret == EPIPE) ret = -EIO; goto done; } } memcpy(a2dp->buffer + a2dp->count, a2dp->sbc.data, a2dp->sbc.len); a2dp->count += a2dp->sbc.len; a2dp->frame_count++; a2dp->samples += encoded / frame_size; a2dp->nsamples += encoded / frame_size; ret = frames_to_read;done: DBG("returning %ld", ret); return ret;}static snd_pcm_ioplug_callback_t bluetooth_hsp_playback = { .start = bluetooth_playback_start, .stop = bluetooth_playback_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_hsp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_hsp_write, .poll_descriptors = bluetooth_playback_poll_descriptors, .poll_revents = bluetooth_playback_poll_revents,};static snd_pcm_ioplug_callback_t bluetooth_hsp_capture = { .start = bluetooth_start, .stop = bluetooth_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_hsp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_hsp_read, .poll_descriptors = bluetooth_poll_descriptors, .poll_revents = bluetooth_poll_revents,};static snd_pcm_ioplug_callback_t bluetooth_a2dp_playback = { .start = bluetooth_playback_start, .stop = bluetooth_playback_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_a2dp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_a2dp_write, .poll_descriptors = bluetooth_playback_poll_descriptors, .poll_revents = bluetooth_playback_poll_revents,};static snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = { .start = bluetooth_start, .stop = bluetooth_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_a2dp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_a2dp_read, .poll_descriptors = bluetooth_poll_descriptors, .poll_revents = bluetooth_poll_revents,};#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io){ struct bluetooth_data *data = io->private_data; struct ipc_data_cfg cfg = data->cfg; snd_pcm_access_t access_list[] = { SND_PCM_ACCESS_RW_INTERLEAVED, /* Mmap access is really useless fo this driver, but we * support it because some pieces of software out there * insist on using it */ SND_PCM_ACCESS_MMAP_INTERLEAVED }; unsigned int format_list[] = { SND_PCM_FORMAT_S16_LE }; int err, channels; /* access type */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, ARRAY_NELEMS(access_list), access_list); if (err < 0) return err; /* supported formats */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, ARRAY_NELEMS(format_list), format_list); if (err < 0) return err; /* supported channels */ channels = cfg.mode == CFG_MODE_MONO ? 1 : 2; err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, channels, channels); if (err < 0) return err; /* supported rate */ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, cfg.rate, cfg.rate); if (err < 0) return err; /* supported block size */ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, cfg.pkt_len, cfg.pkt_len); if (err < 0) return err; err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200); if (err < 0) return err; return 0;}static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io){ struct bluetooth_data *data = io->private_data; struct bluetooth_a2dp *a2dp = &data->a2dp; struct ipc_data_cfg cfg = data->cfg; snd_pcm_access_t access_list[] = { SND_PCM_ACCESS_RW_INTERLEAVED, /* Mmap access is really useless fo this driver, but we * support it because some pieces of software out there * insist on using it */ SND_PCM_ACCESS_MMAP_INTERLEAVED }; unsigned int format_list[] = { SND_PCM_FORMAT_S16_LE }; int err, channels; /* access type */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, ARRAY_NELEMS(access_list), access_list); if (err < 0) return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -