starting btsco-in-libalsa
Guys,
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.
anyway, this is my next project. it depends on a couple of things in other parts of the project:
it would be nice if 'make install' inside sbc/ would install the sbc
includes and library (static libs would be ok)
the avdtp library is just a skeleton right now... should I just ignore
it for now and hardcode what is currently in a2play?
brad
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. http://productguide.itmanagersjournal.com/
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
Marcel Holtmann
maintainerHi Brad,
Quoted 10 lines
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.
Quoted 2 lines
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.
Quoted 2 lines
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.
Quoted 2 lines
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
/*
*
* Bluetooth Advanced Audio Distribution Profile (A2DP) plugin *
* Copyright (C) 2004 Marcel Holtmann <[email protected]> *
*
* 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 ¶ms->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 ¶ms->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);
Marcel Holtmann wrote: 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.
Marcel Holtmann
maintainerHi Thomas,
Quoted 19 lines
Quoted 9 lines
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 thatSND_PCM_TYPE_BLUETOOTHis 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 ~/.asoundrcQuoted 9 lines
pcm.aiptek { type a2dp bdaddr "00:0B:xx:xx:xx:xx" }Assuming that
/usr/lib/alsa-lib/libasound_module_pcm_a2dp.soexists 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.
Quoted 5 lines
i think this goes to the wrong direction.
1. Even if there exist alsa library for many programms it is sufficent to use/dev/dspand/dev/audio.
This mean that the soundcard driver should work independent of the alsa library.
this is too short thinking. There are parts that don't belong inside the kernel. And SBC encoding and decoding is one of them.
Quoted 3 lines
For me looks this very similar to the old pwc driver problem.
a) An kernel module that create an hook for interact with an non kernel module
No it is not. We don't design crappy binary interfaces to the kernel. Everything is open and the socket interface is a well known "hook" into the kernel side of a network stack.
Quoted 5 lines
b) There is an gerneral interface dsp/audio/mixer wich become crippled without the alsa lib
So why not be conesquent and put btsco int the snd-bt-sco module ? Like other hardware the module is tooled via command line or IOCTL wich bt-device it should handle.
Bluetooth is not only hardware. What you see is a dongle, but on top there is a complete stack. We interface with L2CAP and this is a software layer.
Quoted 2 lines
Than the we have and "single" module wich is responsable for handling bluetooth sound.
See the point above. There will never be a "single" module solution.
Quoted 2 lines
Currently it look more like an skeleton for me that grab data from SCO and tell BTSCO how to configure the hardware.
It is this way actually, because the sound volume (mixer settings) are done via AT commands over RFCOMM. There is no way to do this inside the kernel.
Quoted 2 lines
So what are the grounds for moving btsco to the lib inseat of moving it to the module ?
The support for a Bluetooth protocol can be implemented as a kernel module or in userspace depending on its needs. A Bluetooth profile is like an application is this is userspace. So decide by yourself what is the protocol and what is the profile.
Regards
Marcel
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
[Bluez-devel] Re2: starting btsco-in-libalsa
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. =20 i think this goes to the wrong direction. 1. Even if there exist alsa library for many programms it is sufficent to use /dev/dsp and /dev/audio. This mean that the soundcard driver should work independent of the alsa library.
Marcel Holtmann
maintainerHi Thomas,
Quoted 10 lines
Quoted 3 lines
this is too short thinking. There are parts that don't belong inside the kernel. And SBC encoding and decoding is one of them.
OK that is an point that i can understand. But the btsco daemon does not handly any conversion.
He is only responsible for managing the "hardware" Meaning 2 points:
- handle the hardware connection rfcomm / sco
- pipe the volume information betwen the mixer and the headset. He does not do any conversion and also he only interact between kernel modules as an linking glue.
the SCO is PCM and so there is no problem to have this inside the kernel, but headset profile means AT commands over RFCOMM. I am not going to put an AT parser inside the kernel.
Quoted 7 lines
Quoted 4 lines
Bluetooth is not only hardware. What you see is a dongle, but on top there is a complete stack. We interface with L2CAP and this is a software layer.
Hm here came L2CAP in ? Currently i see that there is an rfcomm connection for controll
and an SCO connection there the audio data is transmitted.
And RFCOMM is on top of L2CAP. Even if you don't have to worry about L2CAP, it is there.
Quoted 11 lines
btsco connect to rfcomm and connect/disconnect sco with sound module and send mixer infos.
there i do not se the point there whe deamon handle L2CAP. And i think the discussion is there to
move this part.
I think an good comparision would be the Network to Bluetooth sound
Mozilla --- HTTP --- tcp --- ip --- arp --- 802.3
--- kable
KPhone --- dsp/audio --- sco/rfcomm --- bluethooth
--- on air
Quoted 4 lines
btsco is in the level of sco/rfcomm.
This could be compared with the routing engine that decide on wich device an packet went.
There sco is the tcp/udp channel and rfcomm the icmp.
This is not compareable. TCP/IP is more protocol specific and the Bluetooth stack is more profile/application specific.
Quoted 4 lines
The situation is similiar in antoher point the basic routing is done in the kernel so that tcp stack is usable.
And external routing deamon is used for higher layer routing wich interact with the internal routing.
I don't get the point what static routing versus dynamic routing has to do with it.
Quoted 3 lines
For bluetooth headset this would mean basic function is done in the kernel (connection handling, volume controll).
data conversion and spezial sound protocol in userspace.
If we talk about the headset/handsfree support and if it would only be SCO specific I would agree, but the volume control is realized using AT commands. You don't want an AT parser inside the kernel.
Regards
Marcel
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
Thomas,
Quoted 3 lines
i think this goes to the wrong direction.
1. Even if there exist alsa library for many programms it is sufficent to use/dev/dspand/dev/audio. This mean that the soundcard driver should work independent of the alsa library.
...
Quoted 1 line
So what are the grounds for moving btsco to the lib inseat of moving it to the module ?
I think Marcel explained sufficiently that this is how we can get handsfree and a2dp profiles working properly in the audio driver.
When we get the libalsa stuff going, there will be overlap in function with the current kernel module and daemon, but we can keep the kernel module in our project. As with everything open source, it'll be maintained by people who care about it.
Brad
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. http://productguide.itmanagersjournal.com/
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel