diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2007-04-10 21:37:24 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2007-04-10 21:37:24 +0000 |
commit | b8a407aa8470ad8d92d9142edb41c17548b0cb2c (patch) | |
tree | 1510d97fe928944432a7fea1ac56b6f24760c5e2 /audio/pcm_bluetooth.c | |
parent | f895f6df807b623b2cdd041e9666b01b7f266eb7 (diff) |
Add first step of ALSA plugin integration
Diffstat (limited to 'audio/pcm_bluetooth.c')
-rw-r--r-- | audio/pcm_bluetooth.c | 227 |
1 files changed, 225 insertions, 2 deletions
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index b9f4f02c..d3e457ae 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -25,14 +25,237 @@ #include <config.h> #endif +#include <sys/socket.h> +#include <sys/un.h> + #include <alsa/asoundlib.h> #include <alsa/pcm_external.h> +#include "ipc.h" + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg) + +#define SOCKET_NAME "/org/bluez/audio" + +struct bluetooth_data { + snd_pcm_ioplug_t io; + snd_pcm_sframes_t hw_ptr; + int sock; +}; + +static int bluetooth_start(snd_pcm_ioplug_t *io) +{ + DBG("io %p", io); + + return 0; +} + +static int bluetooth_stop(snd_pcm_ioplug_t *io) +{ + DBG("io %p", io); + + return 0; +} + +static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io) +{ + struct bluetooth_data *data = io->private_data; + + //DBG("io %p", io); + + //DBG("hw_ptr=%lu", data->hw_ptr); + + return data->hw_ptr; +} + +static int bluetooth_close(snd_pcm_ioplug_t *io) +{ + struct bluetooth_data *data = io->private_data; + + DBG("io %p", io); + + free(data); + + return 0; +} + +static snd_pcm_ioplug_callback_t bluetooth_playback_callback = { + .start = bluetooth_start, + .stop = bluetooth_stop, + .pointer = bluetooth_pointer, + .close = bluetooth_close, +#if 0 + .hw_params = bluetooth_hw_params, + .prepare = bluetooth_prepare, + .transfer = bluetooth_write, +#endif +}; + +static snd_pcm_ioplug_callback_t bluetooth_capture_callback = { + .start = bluetooth_start, + .stop = bluetooth_stop, + .pointer = bluetooth_pointer, + .close = bluetooth_close, +#if 0 + .hw_params = bluetooth_hw_params, + .prepare = bluetooth_prepare, + .transfer = bluetooth_read, +#endif +}; + +#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0])) + +static int bluetooth_hw_constraint(snd_pcm_ioplug_t *io) +{ + 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; + + err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, + ARRAY_NELEMS(access_list), access_list); + if (err < 0) + return err; + + err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, + ARRAY_NELEMS(format_list), format_list); + if (err < 0) + return err; + + err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1); + if (err < 0) + return err; + + err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000); + if (err < 0) + return err; + + err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 48, 48); + 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; +} + SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth) { - printf("Bluetooth PCM plugin\n"); + snd_config_iterator_t iter, next; + struct bluetooth_data *data; + struct sockaddr_un addr; + unsigned int id; + int sk, err; + + DBG("Bluetooth PCM plugin (%s)", + stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture"); + + snd_config_for_each(iter, next, conf) { + snd_config_t *n = snd_config_iterator_entry(iter); + const char *id; + + if (snd_config_get_id(n, &id) < 0) + continue; + + if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) + continue; + + if (strcmp(id, "bdaddr") == 0) { + const char *str; + if (snd_config_get_string(n, &str) < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + printf("bdaddr %s\n", str); + continue; + } + + SNDERR("Unknown field %s", id); + + return -EINVAL; + } + + id = abs(getpid() * rand()); + + sk = socket(PF_LOCAL, SOCK_DGRAM, 0); + if (sk < 0) { + SNDERR("Can't open socket"); + return -errno; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", SOCKET_NAME, id); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + SNDERR("Can't bind socket"); + close(sk); + return -errno; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + SNDERR("Can't connect socket"); + close(sk); + return -errno; + } + + data = malloc(sizeof(*data)); + if (!data) { + close(sk); + return -ENOMEM; + } + + memset(data, 0, sizeof(*data)); + + data->sock = sk; + + data->io.version = SND_PCM_IOPLUG_VERSION; + data->io.name = "Bluetooth Audio"; + data->io.mmap_rw = 0; /* No direct mmap communication */ + + data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? + &bluetooth_playback_callback : &bluetooth_capture_callback; + data->io.poll_fd = sk; + data->io.poll_events = POLLIN; + data->io.private_data = data; + + err = snd_pcm_ioplug_create(&data->io, name, stream, mode); + if (err < 0) + goto error; + + err = bluetooth_hw_constraint(&data->io); + if (err < 0) { + snd_pcm_ioplug_delete(&data->io); + goto error; + } + + *pcmp = data->io.pcm; + + return 0; + +error: + close(sk); + + free(data); - return -EIO; + return err; } SND_PCM_PLUGIN_SYMBOL(bluetooth); |