public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
From: Marcel Holtmann <marcel@holtmann.org>
To: BlueZ Mailing List <bluez-devel@lists.sourceforge.net>
Subject: Re: [Bluez-devel] starting btsco-in-libalsa
Date: Thu, 09 Dec 2004 11:57:15 +0100	[thread overview]
Message-ID: <1102589835.9988.114.camel@pegasus> (raw)
In-Reply-To: <41B81ACB.1080807@xmission.com>

[-- Attachment #1: Type: text/plain, Size: 2059 bytes --]

Hi Brad,

> I put some junk in the btsco cvs:
> 
> alsa-lib.patch
> bt/
> 
> if you apply alsa-lib.patch and put bt inside alsa-lib/src/pcm then the 
> idea is that you can build a userspace alsa driver.
> 
> currently it doesn't even compile... it's just based on the jack plugin 
> and not yet reworked for bluetooth.

nice start. Actually I tried this by myself some time ago, but haven't
got any further than a skeleton. The main problem I see at the moment is
that we have to develop this inside the ALSA lib source and that is bad.
The reason for this is "pcm_local.h" and its definitions that are not
installed system wide. I don't think that SND_PCM_TYPE_BLUETOOTH is
needed, but I can be wrong of course. The other thing is that this stuff
should belong to the pcm/ext/ directory. My skeleton is attached and I
used these extra lines in ~/.asoundrc

	pcm.aiptek {
		type a2dp
		bdaddr "00:0B:xx:xx:xx:xx"
	}

Assuming that /usr/lib/alsa-lib/libasound_module_pcm_a2dp.so exists this
works as it should. So we have PCM at the input side of this plugin and
we send SBC over AVDTP to our headphone.

> anyway, this is my next project. it depends on a couple of things in 
> other parts of the project:

Actually I think this is the way we should go. Using a2play is great,
but this will open it up to any tool that can play music using the ALSA
library.

>   it would be nice if 'make install' inside sbc/ would install the sbc 
> includes and library (static libs would be ok)

This is the whole goal, but for now I think we should copy the source
and simply link it. My plan is to combine sbclib.c and sbc.c and include
sbc_internal.h into sbc.c then. Also sbc_tables.h is not really useful
as a separate include.

>   the avdtp library is just a skeleton right now... should I just ignore 
> it for now and hardcode what is currently in a2play?

It is more than a skeleton, but I haven't committed the other code and I
don't think that I will have much time to work on it. Ignore it for now,
because we can catch up with that later.

Regards

Marcel


[-- Attachment #2: pcm_a2dp.c --]
[-- Type: text/x-csrc, Size: 10261 bytes --]

/*
 *
 *  Bluetooth Advanced Audio Distribution Profile (A2DP) plugin
 *
 *  Copyright (C) 2004  Marcel Holtmann <marcel@holtmann.org>
 *
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sys/types.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>

#include "sbc.h"

#include "pcm_local.h"

#define DBG(fmt, arg...)  printf("%s: " fmt "\n" , __FUNCTION__ , ## arg)

#ifndef PIC
/* entry for static linking */
const char *_snd_module_pcm_a2dp = "";
#endif

static int snd_pcm_a2dp_close(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_nonblock(snd_pcm_t *pcm, int nonblock)
{
	DBG("pcm %p nonblock %d", pcm, nonblock);

	return 0;
}

static int snd_pcm_a2dp_async(snd_pcm_t *pcm, int sig, pid_t pid)
{
	DBG("pcm %p sig %d pid %d", pcm, sig, pid);

	return -ENOSYS;
}

static int snd_pcm_a2dp_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
{
	DBG("pcm %p pfds %p nfds %d revents %p", pcm, pfds, nfds, revents);

	return 0;
}

static int snd_pcm_a2dp_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
	DBG("pcm %p info %p", pcm, info);

	memset(info, 0, sizeof(*info));
	info->stream = pcm->stream;
	info->card = -1;
	strncpy(info->id, pcm->name, sizeof(info->id));
	strncpy(info->name, pcm->name, sizeof(info->name));
	strncpy(info->subname, pcm->name, sizeof(info->subname));
	info->subdevices_count = 1;

	return 0;
}

static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
{
	return &params->masks[var - SND_PCM_HW_PARAM_FIRST_MASK];
}

static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
{
	return &params->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL];
}

static int snd_pcm_a2dp_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
	static snd_mask_t access = { .bits = { 
					(1<<SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) |
					(1<<SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) |
					(1<<SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
					(1<<SNDRV_PCM_ACCESS_RW_NONINTERLEAVED),
					0, 0, 0 } };
	static snd_pcm_format_mask_t format_mask = { { 1U<<SNDRV_PCM_FORMAT_S16_BE } };
	snd_interval_t t;
	int err;

	DBG("pcm %p params %p", pcm, params);

	err = snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS), &access);
	if (err < 0)
		return err;

	err = snd_mask_refine(hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT), &format_mask);
	if (err < 0)
		return err;

	err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_CHANNELS), 2);
	if (err < 0)
		return err;

	err = snd_interval_refine_set(hw_param_interval(params, SND_PCM_HW_PARAM_RATE), 44100);
	if (err < 0)
		return err;

	snd_interval_set_minmax(&t, 128, 1024*1024);
	err = snd_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE), &t);
	if (err < 0)
		return err;

	snd_interval_set_minmax(&t, 64, 1024*1024);
	err = snd_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE), &t);
	if (err < 0)
		return err;

	snd_interval_set_minmax(&t, 2, 64);
	err = snd_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS), &t);
	if (err < 0)
		return err;

	return 0;
}

static int snd_pcm_a2dp_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
	DBG("pcm %p params %p", pcm, params);

	return 0;
}

static int snd_pcm_a2dp_hw_free(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
	DBG("pcm %p params %p", pcm, params);

	return 0;
}

static int snd_pcm_a2dp_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
	DBG("pcm %p info %p", pcm, info);

	return snd_pcm_channel_info_shm(pcm, info, -1);
}

static void snd_pcm_a2dp_dump(snd_pcm_t *pcm, snd_output_t *out)
{
	DBG("pcm %p out %p", pcm, out);

	snd_output_printf(out, "Bluetooth A2DP PCM\n");
	if (pcm->setup) {
		snd_output_printf(out, "Its setup is:\n");
		snd_pcm_dump_setup(pcm, out);
	}
}

static int snd_pcm_a2dp_mmap(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_munmap(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static snd_pcm_ops_t snd_pcm_a2dp_ops = {
	.close		= snd_pcm_a2dp_close,
	.info		= snd_pcm_a2dp_info,
	.nonblock	= snd_pcm_a2dp_nonblock,
	.async		= snd_pcm_a2dp_async,
	.poll_revents	= snd_pcm_a2dp_poll_revents,
	.hw_refine	= snd_pcm_a2dp_hw_refine,
	.hw_params	= snd_pcm_a2dp_hw_params,
	.hw_free	= snd_pcm_a2dp_hw_free,
	.sw_params	= snd_pcm_a2dp_sw_params,
	.channel_info	= snd_pcm_a2dp_channel_info,
	.dump		= snd_pcm_a2dp_dump,
	.mmap		= snd_pcm_a2dp_mmap,
	.munmap		= snd_pcm_a2dp_munmap,
};

static int snd_pcm_a2dp_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
{
	DBG("pcm %p status %p", pcm, status);

	memset(status, 0, sizeof(*status));
	status->avail = pcm->buffer_size;

	return 0;
}

static int snd_pcm_a2dp_prepare(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_reset(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_start(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_drop(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_drain(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_pause(snd_pcm_t *pcm, int enable)
{
	DBG("pcm %p enable %d", pcm, enable);

	return 0;
}

static snd_pcm_state_t snd_pcm_a2dp_state(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return SND_PCM_STATE_RUNNING;
}

static int snd_pcm_a2dp_hwsync(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay)
{
	DBG("pcm %p delay %p", pcm, delay);

	return 0;
}

static int snd_pcm_a2dp_resume(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static int snd_pcm_a2dp_poll_ask(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
	DBG("pcm %p frames %d", pcm, frames);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
	DBG("pcm %p frames %d", pcm, frames);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
{
	DBG("pcm %p buffer %p size %d", pcm, buffer, size);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
{
	DBG("pcm %p bufs %p size %d", pcm, bufs, size);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
{
	DBG("pcm %p buffer %p size %d", pcm, buffer, size);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
{
	DBG("pcm %p bufs %p size %d", pcm, bufs, size);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_avail_update(snd_pcm_t *pcm)
{
	DBG("pcm %p", pcm);

	return 0;
}

static snd_pcm_sframes_t snd_pcm_a2dp_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
{
	DBG("pcm %p offset %d size %d", pcm, offset, size);

	return 0;
}

static snd_pcm_fast_ops_t snd_pcm_a2dp_fast_ops = {
	.status		= snd_pcm_a2dp_status,
	.prepare	= snd_pcm_a2dp_prepare,
	.reset		= snd_pcm_a2dp_reset,
	.start		= snd_pcm_a2dp_start,
	.drop		= snd_pcm_a2dp_drop,
	.drain		= snd_pcm_a2dp_drain,
	.pause		= snd_pcm_a2dp_pause,
	.state		= snd_pcm_a2dp_state,
	.hwsync		= snd_pcm_a2dp_hwsync,
	.delay		= snd_pcm_a2dp_delay,
	.resume		= snd_pcm_a2dp_resume,
	.poll_ask	= snd_pcm_a2dp_poll_ask,
	.rewind		= snd_pcm_a2dp_rewind,
	.forward	= snd_pcm_a2dp_forward,
	.writei		= snd_pcm_a2dp_writei,
	.writen		= snd_pcm_a2dp_writen,
	.readi		= snd_pcm_a2dp_readi,
	.readn		= snd_pcm_a2dp_readn,
	.avail_update	= snd_pcm_a2dp_avail_update,
	.mmap_commit	= snd_pcm_a2dp_mmap_commit,
};

static int snd_pcm_a2dp_open(snd_pcm_t **pcmp, const char *name,
		bdaddr_t *src, bdaddr_t *dst, snd_pcm_stream_t stream, int mode)
{
	snd_pcm_t *pcm;
	char addr[18];
	int err;

	DBG("name %s mode %d", name, mode);

	ba2str(dst, addr);
	printf("BD_ADDR %s\n", addr);

	err = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, stream, mode);
	if (err < 0)
		return err;

	pcm->ops = &snd_pcm_a2dp_ops;
	pcm->fast_ops = &snd_pcm_a2dp_fast_ops;

	*pcmp = pcm;

	return 0;
}

int _snd_pcm_a2dp_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root,
			snd_config_t *conf, snd_pcm_stream_t stream, int mode)
{
	snd_config_iterator_t i, next;
	bdaddr_t src, dst;
	const char *addr;
	int err;

	DBG("name %s mode %d", name, mode);

	bacpy(&src, BDADDR_ANY);
	bacpy(&dst, BDADDR_ANY);

	snd_config_for_each(i, next, conf) {
		snd_config_t *n = snd_config_iterator_entry(i);
		const char *id;

		if (snd_config_get_id(n, &id) < 0)
			continue;

		if (snd_pcm_conf_generic_id(id))
			continue;

		if (strcmp(id, "bdaddr") == 0 || strcmp(id, "dst") == 0) {
			if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
				SNDERR("Invalid type for %s", id);
				return -EINVAL;
			}
			snd_config_get_string(n, &addr);
			str2ba(addr, &dst);
			continue;
		}

		if (strcmp(id, "src") == 0) {
			if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
				SNDERR("Invalid type for %s", id);
				return -EINVAL;
			}
			snd_config_get_string(n, &addr);
			str2ba(addr, &src);
			continue;
		}

		SNDERR("Unknown field %s", id);
		return -EINVAL;
	}

	err = snd_pcm_a2dp_open(pcmp, name, &src, &dst, stream, mode);

	return err;
}

SND_DLSYM_BUILD_VERSION(_snd_pcm_a2dp_open, SND_PCM_DLSYM_VERSION);

  reply	other threads:[~2004-12-09 10:57 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-12-09  9:28 [Bluez-devel] starting btsco-in-libalsa Brad Midgley
2004-12-09 10:57 ` Marcel Holtmann [this message]
2004-12-09 11:48   ` [Bluez-devel] " suche.org
2004-12-09 12:07     ` Marcel Holtmann
2004-12-09 12:49       ` [Bluez-devel] Re2: " suche.org
2004-12-09 13:10         ` [Bluez-devel] " Marcel Holtmann
2004-12-09 17:31     ` Brad Midgley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1102589835.9988.114.camel@pegasus \
    --to=marcel@holtmann.org \
    --cc=bluez-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox