Exemplo n.º 1
0
static int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io,
					snd_pcm_hw_params_t *params)
{
	struct bluetooth_data *data = io->private_data;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_open_req *open_req = (void *) buf;
	struct bt_open_rsp *open_rsp = (void *) buf;
	struct bt_set_configuration_req *req = (void *) buf;
	struct bt_set_configuration_rsp *rsp = (void *) buf;
	int err;

	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
					io->period_size, io->buffer_size);

	memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
	open_req->h.type = BT_REQUEST;
	open_req->h.name = BT_OPEN;
	open_req->h.length = sizeof(*open_req);

	strncpy(open_req->destination, data->alsa_config.device, 18);
	open_req->seid = BT_A2DP_SEID_RANGE + 1;
	open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ?
			BT_WRITE_LOCK : BT_READ_LOCK);

	err = audioservice_send(data->server.fd, &open_req->h);
	if (err < 0)
		return err;

	open_rsp->h.length = sizeof(*open_rsp);
	err = audioservice_expect(data->server.fd, &open_rsp->h,
					BT_OPEN);
	if (err < 0)
		return err;

	memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
	req->h.type = BT_REQUEST;
	req->h.name = BT_SET_CONFIGURATION;
	req->h.length = sizeof(*req);

	req->codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
	req->codec.seid = BT_A2DP_SEID_RANGE + 1;
	req->codec.length = sizeof(pcm_capabilities_t);

	req->h.length += req->codec.length - sizeof(req->codec);
	err = audioservice_send(data->server.fd, &req->h);
	if (err < 0)
		return err;

	rsp->h.length = sizeof(*rsp);
	err = audioservice_expect(data->server.fd, &rsp->h,
					BT_SET_CONFIGURATION);
	if (err < 0)
		return err;

	data->transport = BT_CAPABILITIES_TRANSPORT_SCO;
	data->link_mtu = rsp->link_mtu;

	return 0;
}
Exemplo n.º 2
0
static int bluetooth_configure(struct bluetooth_data *data)
{
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_get_capabilities_req *getcaps_req = (void*) buf;
	struct bt_get_capabilities_rsp *getcaps_rsp = (void*) buf;
	int err;

	DBG("bluetooth_configure");

	data->state = A2DP_STATE_CONFIGURING;
	memset(getcaps_req, 0, BT_SUGGESTED_BUFFER_SIZE);
	getcaps_req->h.type = BT_REQUEST;
	getcaps_req->h.name = BT_GET_CAPABILITIES;

	getcaps_req->flags = 0;
	getcaps_req->flags |= BT_FLAG_AUTOCONNECT;
	strncpy(getcaps_req->destination, data->address, 18);
	getcaps_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
	getcaps_req->h.length = sizeof(*getcaps_req);

	err = audioservice_send(data, &getcaps_req->h);
	if (err < 0) {
		ERR("audioservice_send failed for BT_GETCAPABILITIES_REQ\n");
		goto error;
	}

	getcaps_rsp->h.length = 0;
	err = audioservice_expect(data, &getcaps_rsp->h, BT_GET_CAPABILITIES);
	if (err < 0) {
		ERR("audioservice_expect failed for BT_GETCAPABILITIES_RSP\n");
		goto error;
	}

	err = bluetooth_parse_capabilities(data, getcaps_rsp);
	if (err < 0) {
		ERR("bluetooth_parse_capabilities failed err: %d", err);
		goto error;
	}

	err = bluetooth_a2dp_hw_params(data);
	if (err < 0) {
		ERR("bluetooth_a2dp_hw_params failed err: %d", err);
		goto error;
	}


	set_state(data, A2DP_STATE_CONFIGURED);
	return 0;

error:

	if (data->state == A2DP_STATE_CONFIGURING) {
		bluetooth_close(data);
		/* notify client that thread is ready for next command */
		pthread_cond_signal(&data->client_wait);
        }
	return err;
}
Exemplo n.º 3
0
static int bluetooth_stop(struct bluetooth_data *data)
{
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_stop_stream_req *stop_req = (void*) buf;
	struct bt_stop_stream_rsp *stop_rsp = (void*) buf;
	int err;

	DBG("bluetooth_stop");

	data->state = A2DP_STATE_STOPPING;
	l2cap_set_flushable(data->stream.fd, 0);
	if (data->stream.fd >= 0) {
		close(data->stream.fd);
		data->stream.fd = -1;
	}

	/* send stop request */
	memset(stop_req, 0, BT_SUGGESTED_BUFFER_SIZE);
	stop_req->h.type = BT_REQUEST;
	stop_req->h.name = BT_STOP_STREAM;
	stop_req->h.length = sizeof(*stop_req);

	err = audioservice_send(data, &stop_req->h);
	if (err < 0)
		goto error;

	stop_rsp->h.length = sizeof(*stop_rsp);
	err = audioservice_expect(data, &stop_rsp->h, BT_STOP_STREAM);
	if (err < 0)
		goto error;

error:
	if (data->state == A2DP_STATE_STOPPING)
		set_state(data, A2DP_STATE_CONFIGURED);
	return err;
}
Exemplo n.º 4
0
static void bluetooth_close(struct bluetooth_data *data)
{
	DBG("bluetooth_close");
	if (data->server.fd >= 0) {
		// sending BT_CLOSE to cleanup unix socket.
		char buf[BT_SUGGESTED_BUFFER_SIZE];
		struct bt_close_req *close_req = (void*) buf;
		struct bt_close_rsp *close_rsp = (void*) buf;
		int err;
		memset(close_req, 0, BT_SUGGESTED_BUFFER_SIZE);
		close_req->h.type = BT_REQUEST;
		close_req->h.name = BT_CLOSE;

		close_req->h.length = sizeof(*close_req);

		err = audioservice_send(data, &close_req->h);
		if (err < 0) {
			ERR("audioservice_send failed for BT_CLOSE_REQ\n");
		} else {
			close_rsp->h.length = 0;
			err = audioservice_expect(data, &close_rsp->h, BT_CLOSE);
			if (err < 0) {
				ERR("audioservice_expect failed for BT_CLOSE_RSP\n");
			}
		}
		bt_audio_service_close(data->server.fd);
		data->server.fd = -1;
	}

	if (data->stream.fd >= 0) {
		close(data->stream.fd);
		data->stream.fd = -1;
	}

	data->state = A2DP_STATE_NONE;
}
Exemplo n.º 5
0
static int bluetooth_a2dp_hw_params(struct bluetooth_data *data)
{
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_open_req *open_req = (void *) buf;
	struct bt_open_rsp *open_rsp = (void *) buf;
	struct bt_set_configuration_req *setconf_req = (void*) buf;
	struct bt_set_configuration_rsp *setconf_rsp = (void*) buf;
	int err;

	memset(open_req, 0, BT_SUGGESTED_BUFFER_SIZE);
	open_req->h.type = BT_REQUEST;
	open_req->h.name = BT_OPEN;
	open_req->h.length = sizeof(*open_req);
	strncpy(open_req->destination, data->address, 18);
	open_req->seid = data->sbc_capabilities.capability.seid;
	open_req->lock = BT_WRITE_LOCK;

	err = audioservice_send(data, &open_req->h);
	if (err < 0)
		return err;

	open_rsp->h.length = sizeof(*open_rsp);
	err = audioservice_expect(data, &open_rsp->h, BT_OPEN);
	if (err < 0)
		return err;

	err = bluetooth_a2dp_init(data);
	if (err < 0)
		return err;


	memset(setconf_req, 0, BT_SUGGESTED_BUFFER_SIZE);
	setconf_req->h.type = BT_REQUEST;
	setconf_req->h.name = BT_SET_CONFIGURATION;
	setconf_req->h.length = sizeof(*setconf_req);
	memcpy(&setconf_req->codec, &data->sbc_capabilities,
						sizeof(data->sbc_capabilities));

	setconf_req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
	setconf_req->codec.length = sizeof(data->sbc_capabilities);
	setconf_req->h.length += setconf_req->codec.length - sizeof(setconf_req->codec);

	DBG("bluetooth_a2dp_hw_params sending configuration:\n");
	switch (data->sbc_capabilities.channel_mode) {
		case BT_A2DP_CHANNEL_MODE_MONO:
			DBG("\tchannel_mode: MONO\n");
			break;
		case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
			DBG("\tchannel_mode: DUAL CHANNEL\n");
			break;
		case BT_A2DP_CHANNEL_MODE_STEREO:
			DBG("\tchannel_mode: STEREO\n");
			break;
		case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
			DBG("\tchannel_mode: JOINT STEREO\n");
			break;
		default:
			DBG("\tchannel_mode: UNKNOWN (%d)\n",
				data->sbc_capabilities.channel_mode);
	}
	switch (data->sbc_capabilities.frequency) {
		case BT_SBC_SAMPLING_FREQ_16000:
			DBG("\tfrequency: 16000\n");
			break;
		case BT_SBC_SAMPLING_FREQ_32000:
			DBG("\tfrequency: 32000\n");
			break;
		case BT_SBC_SAMPLING_FREQ_44100:
			DBG("\tfrequency: 44100\n");
			break;
		case BT_SBC_SAMPLING_FREQ_48000:
			DBG("\tfrequency: 48000\n");
			break;
		default:
			DBG("\tfrequency: UNKNOWN (%d)\n",
				data->sbc_capabilities.frequency);
	}
	switch (data->sbc_capabilities.allocation_method) {
		case BT_A2DP_ALLOCATION_SNR:
			DBG("\tallocation_method: SNR\n");
			break;
		case BT_A2DP_ALLOCATION_LOUDNESS:
			DBG("\tallocation_method: LOUDNESS\n");
			break;
		default:
			DBG("\tallocation_method: UNKNOWN (%d)\n",
				data->sbc_capabilities.allocation_method);
	}
	switch (data->sbc_capabilities.subbands) {
		case BT_A2DP_SUBBANDS_4:
			DBG("\tsubbands: 4\n");
			break;
		case BT_A2DP_SUBBANDS_8:
			DBG("\tsubbands: 8\n");
			break;
		default:
			DBG("\tsubbands: UNKNOWN (%d)\n",
				data->sbc_capabilities.subbands);
	}
	switch (data->sbc_capabilities.block_length) {
		case BT_A2DP_BLOCK_LENGTH_4:
			DBG("\tblock_length: 4\n");
			break;
		case BT_A2DP_BLOCK_LENGTH_8:
			DBG("\tblock_length: 8\n");
			break;
		case BT_A2DP_BLOCK_LENGTH_12:
			DBG("\tblock_length: 12\n");
			break;
		case BT_A2DP_BLOCK_LENGTH_16:
			DBG("\tblock_length: 16\n");
			break;
		default:
			DBG("\tblock_length: UNKNOWN (%d)\n",
				data->sbc_capabilities.block_length);
	}
	DBG("\tmin_bitpool: %d\n", data->sbc_capabilities.min_bitpool);
	DBG("\tmax_bitpool: %d\n", data->sbc_capabilities.max_bitpool);

	err = audioservice_send(data, &setconf_req->h);
	if (err < 0)
		return err;

	err = audioservice_expect(data, &setconf_rsp->h, BT_SET_CONFIGURATION);
	if (err < 0)
		return err;

	data->link_mtu = setconf_rsp->link_mtu;
#ifdef TN_JPN_NTT_BT_SCMS-T
	if (setconf_rsp->content_protection == CP_TYPE_SCMS_T) {
		data->sizeof_scms_t = 1;
		data->scms_t_cp_header = SCMS_T_COPY_NOT_ALLOWED;
	} else {
		data->sizeof_scms_t = 0;
		data->scms_t_cp_header = SCMS_T_COPY_ALLOWED;
	}
	DBG("MTU: %d -- SCMS-T Enabled: %d", data->link_mtu, setconf_rsp->content_protection);
#else
       DBG("MTU: %d", data->link_mtu);
#endif
	/* Setup SBC encoder now we agree on parameters */
	bluetooth_a2dp_setup(data);

	DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
		data->sbc.allocation, data->sbc.subbands, data->sbc.blocks,
		data->sbc.bitpool);

	return 0;
}
Exemplo n.º 6
0
static int bluetooth_start(struct bluetooth_data *data)
{
	char c = 'w';
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_start_stream_req *start_req = (void*) buf;
	struct bt_start_stream_rsp *start_rsp = (void*) buf;
	struct bt_new_stream_ind *streamfd_ind = (void*) buf;
	int opt_name, err, bytes;

	DBG("bluetooth_start");
	data->state = A2DP_STATE_STARTING;
	/* send start */
	memset(start_req, 0, BT_SUGGESTED_BUFFER_SIZE);
	start_req->h.type = BT_REQUEST;
	start_req->h.name = BT_START_STREAM;
	start_req->h.length = sizeof(*start_req);


	err = audioservice_send(data, &start_req->h);
	if (err < 0)
		goto error;

	start_rsp->h.length = sizeof(*start_rsp);
	err = audioservice_expect(data, &start_rsp->h, BT_START_STREAM);
	if (err < 0)
		goto error;

	streamfd_ind->h.length = sizeof(*streamfd_ind);
	err = audioservice_expect(data, &streamfd_ind->h, BT_NEW_STREAM);
	if (err < 0)
		goto error;

	data->stream.fd = bt_audio_service_get_data_fd(data->server.fd);
	if (data->stream.fd < 0) {
		ERR("bt_audio_service_get_data_fd failed, errno: %d", errno);
		err = -errno;
		goto error;
	}
	l2cap_set_flushable(data->stream.fd, 1);
	data->stream.events = POLLOUT;

	/* set our socket buffer to the size of PACKET_BUFFER_COUNT packets */
	bytes = data->link_mtu * PACKET_BUFFER_COUNT;
	setsockopt(data->stream.fd, SOL_SOCKET, SO_SNDBUF, &bytes,
			sizeof(bytes));

#ifdef TN_JPN_NTT_BT_SCMS-T
	data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload) + data->sizeof_scms_t;
#else
	data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
#endif
	data->frame_count = 0;
	data->samples = 0;
	data->nsamples = 0;
	data->seq_num = 0;
	data->frame_count = 0;
	data->next_write = 0;

	set_state(data, A2DP_STATE_STARTED);
	return 0;

error:
	/* close bluetooth connection to force reinit and reconfiguration */
	if (data->state == A2DP_STATE_STARTING) {
		bluetooth_close(data);
		/* notify client that thread is ready for next command */
		pthread_cond_signal(&data->client_wait);
        }
	return err;
}
Exemplo n.º 7
0
static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,
					snd_pcm_hw_params_t *params)
{
	struct bluetooth_data *data = io->private_data;
	struct bluetooth_a2dp *a2dp = &data->a2dp;
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_open_req *open_req = (void *) buf;
	struct bt_open_rsp *open_rsp = (void *) buf;
	struct bt_set_configuration_req *req = (void *) buf;
	struct bt_set_configuration_rsp *rsp = (void *) buf;
	int err;

	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
					io->period_size, io->buffer_size);

	memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
	open_req->h.type = BT_REQUEST;
	open_req->h.name = BT_OPEN;
	open_req->h.length = sizeof(*open_req);

	strncpy(open_req->destination, data->alsa_config.device, 18);
	open_req->seid = a2dp->sbc_capabilities.capability.seid;
	open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ?
			BT_WRITE_LOCK : BT_READ_LOCK);

	err = audioservice_send(data->server.fd, &open_req->h);
	if (err < 0)
		return err;

	open_rsp->h.length = sizeof(*open_rsp);
	err = audioservice_expect(data->server.fd, &open_rsp->h,
					BT_OPEN);
	if (err < 0)
		return err;

	err = bluetooth_a2dp_init(data, params);
	if (err < 0)
		return err;

	memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
	req->h.type = BT_REQUEST;
	req->h.name = BT_SET_CONFIGURATION;
	req->h.length = sizeof(*req);

	memcpy(&req->codec, &a2dp->sbc_capabilities,
			sizeof(a2dp->sbc_capabilities));

	req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
	req->codec.length = sizeof(a2dp->sbc_capabilities);
	req->h.length += req->codec.length - sizeof(req->codec);

	err = audioservice_send(data->server.fd, &req->h);
	if (err < 0)
		return err;

	rsp->h.length = sizeof(*rsp);
	err = audioservice_expect(data->server.fd, &rsp->h,
					BT_SET_CONFIGURATION);
	if (err < 0)
		return err;

	data->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
	data->link_mtu = rsp->link_mtu;

	/* Setup SBC encoder now we agree on parameters */
	bluetooth_a2dp_setup(a2dp);

	DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
		a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks,
		a2dp->sbc.bitpool);

	return 0;
}
Exemplo n.º 8
0
static int bluetooth_prepare(snd_pcm_ioplug_t *io)
{
	struct bluetooth_data *data = io->private_data;
	char c = 'w';
	char buf[BT_SUGGESTED_BUFFER_SIZE];
	struct bt_start_stream_req *req = (void *) buf;
	struct bt_start_stream_rsp *rsp = (void *) buf;
	struct bt_new_stream_ind *ind = (void *) buf;
	uint32_t period_count = io->buffer_size / io->period_size;
	int opt_name, err;
	struct timeval t = { 0, period_count };

	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
					io->period_size, io->buffer_size);

	data->reset = 0;

	/* As we're gonna receive messages on the server socket, we have to stop the
	   hw thread that is polling on it, if any */
	if (data->hw_thread) {
		pthread_cancel(data->hw_thread);
		pthread_join(data->hw_thread, 0);
		data->hw_thread = 0;
	}

	if (io->stream == SND_PCM_STREAM_PLAYBACK)
		/* If not null for playback, xmms doesn't display time
		 * correctly */
		data->hw_ptr = 0;
	else
		/* ALSA library is really picky on the fact hw_ptr is not null.
		 * If it is, capture won't start */
		data->hw_ptr = io->period_size;

	/* send start */
	memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
	req->h.type = BT_REQUEST;
	req->h.name = BT_START_STREAM;
	req->h.length = sizeof(*req);

	err = audioservice_send(data->server.fd, &req->h);
	if (err < 0)
		return err;

	rsp->h.length = sizeof(*rsp);
	err = audioservice_expect(data->server.fd, &rsp->h,
					BT_START_STREAM);
	if (err < 0)
		return err;

	ind->h.length = sizeof(*ind);
	err = audioservice_expect(data->server.fd, &ind->h,
					BT_NEW_STREAM);
	if (err < 0)
		return err;

	if (data->stream.fd >= 0)
		close(data->stream.fd);

	data->stream.fd = bt_audio_service_get_data_fd(data->server.fd);
	if (data->stream.fd < 0) {
		return -errno;
	}

	if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
		opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
						SO_SNDTIMEO : SO_RCVTIMEO;

		if (setsockopt(data->stream.fd, SOL_SOCKET, opt_name, &t,
							sizeof(t)) < 0)
			return -errno;
	} else {
		opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
						SCO_TXBUFS : SCO_RXBUFS;

		if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,
						sizeof(period_count)) == 0)
			return 0;

		opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
						SO_SNDBUF : SO_RCVBUF;

		if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,
						sizeof(period_count)) == 0)
			return 0;

		/* FIXME : handle error codes */
	}

	/* wake up any client polling at us */
	if (write(data->pipefd[1], &c, 1) < 0) {
		err = -errno;
		return err;
	}

	return 0;
}