Update audio_plugin

This commit is contained in:
brunodev85 2024-02-01 17:17:42 -03:00
parent 1a2d360ef6
commit 8fecfc95ae
2 changed files with 270 additions and 270 deletions

View File

@ -1,9 +1,9 @@
@hooks [ @hooks [
{ {
func load func load
files [ files [
"/etc/alsa/conf.d/android_aserver.conf" "/etc/alsa/conf.d/android_aserver.conf"
] ]
errors false errors false
} }
] ]

View File

@ -24,229 +24,229 @@
#define DATA_TYPE_FLOATLE 3 #define DATA_TYPE_FLOATLE 3
#define DATA_TYPE_FLOATBE 4 #define DATA_TYPE_FLOATBE 4
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
typedef struct snd_pcm_android_aserver { typedef struct snd_pcm_android_aserver {
snd_pcm_ioplug_t io; snd_pcm_ioplug_t io;
int fd; int fd;
int frame_bytes; int frame_bytes;
unsigned int position; unsigned int position;
void* buffer; void* buffer;
int buffer_size; int buffer_size;
bool use_shm; bool use_shm;
} snd_pcm_android_aserver_t; } snd_pcm_android_aserver_t;
static int android_aserver_recv_fd(int fd) { static int android_aserver_recv_fd(int fd) {
char zero = 0; char zero = 0;
struct iovec iovmsg = {.iov_base = &zero, .iov_len = 1}; struct iovec iovmsg = {.iov_base = &zero, .iov_len = 1};
struct { struct {
struct cmsghdr align; struct cmsghdr align;
int fds[1]; int fds[1];
} ctrlmsg; } ctrlmsg;
struct msghdr msg = { struct msghdr msg = {
.msg_name = NULL, .msg_name = NULL,
.msg_namelen = 0, .msg_namelen = 0,
.msg_iov = &iovmsg, .msg_iov = &iovmsg,
.msg_iovlen = 1, .msg_iovlen = 1,
.msg_flags = 0, .msg_flags = 0,
.msg_control = &ctrlmsg, .msg_control = &ctrlmsg,
.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) .msg_controllen = sizeof(struct cmsghdr) + sizeof(int)
}; };
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = msg.msg_controllen; cmsg->cmsg_len = msg.msg_controllen;
((int*)CMSG_DATA(cmsg))[0] = -1; ((int*)CMSG_DATA(cmsg))[0] = -1;
recvmsg(fd, &msg, 0); recvmsg(fd, &msg, 0);
return ((int*)CMSG_DATA(cmsg))[0]; return ((int*)CMSG_DATA(cmsg))[0];
} }
static int android_aserver_close(snd_pcm_ioplug_t* io) { static int android_aserver_close(snd_pcm_ioplug_t* io) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
if (!android_aserver) return 0; if (!android_aserver) return 0;
if (android_aserver->fd >= 0) { if (android_aserver->fd >= 0) {
int request_length = 0; int request_length = 0;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_CLOSE; request_data[0] = REQUEST_CODE_CLOSE;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
close(android_aserver->fd); close(android_aserver->fd);
} }
if (android_aserver->buffer_size > 0) { if (android_aserver->buffer_size > 0) {
munmap(android_aserver->buffer, android_aserver->buffer_size); munmap(android_aserver->buffer, android_aserver->buffer_size);
android_aserver->buffer_size = 0; android_aserver->buffer_size = 0;
} }
free(android_aserver); free(android_aserver);
return 0; return 0;
} }
static int android_aserver_start(snd_pcm_ioplug_t* io) { static int android_aserver_start(snd_pcm_ioplug_t* io) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
int request_length = 0; int request_length = 0;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_START; request_data[0] = REQUEST_CODE_START;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
if (res < 0) return -EINVAL; if (res < 0) return -EINVAL;
return 0; return 0;
} }
static int android_aserver_stop(snd_pcm_ioplug_t* io) { static int android_aserver_stop(snd_pcm_ioplug_t* io) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
int request_length = 0; int request_length = 0;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_STOP; request_data[0] = REQUEST_CODE_STOP;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
if (res < 0) return -EINVAL; if (res < 0) return -EINVAL;
return 0; return 0;
} }
static int android_aserver_pause(snd_pcm_ioplug_t* io, int enable) { static int android_aserver_pause(snd_pcm_ioplug_t* io, int enable) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
int request_length = 0; int request_length = 0;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_PAUSE; request_data[0] = REQUEST_CODE_PAUSE;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
if (res < 0) return -EINVAL; if (res < 0) return -EINVAL;
return 0; return 0;
} }
static int android_aserver_prepare(snd_pcm_ioplug_t* io) { static int android_aserver_prepare(snd_pcm_ioplug_t* io) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
android_aserver->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8; android_aserver->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
android_aserver->position = 0; android_aserver->position = 0;
char channels = (char)io->channels; char channels = (char)io->channels;
char data_type; char data_type;
switch (io->format) { switch (io->format) {
case SND_PCM_FORMAT_U8: case SND_PCM_FORMAT_U8:
data_type = DATA_TYPE_U8; data_type = DATA_TYPE_U8;
break; break;
case SND_PCM_FORMAT_S16_LE: case SND_PCM_FORMAT_S16_LE:
data_type = DATA_TYPE_S16LE; data_type = DATA_TYPE_S16LE;
break; break;
case SND_PCM_FORMAT_S16_BE: case SND_PCM_FORMAT_S16_BE:
data_type = DATA_TYPE_S16BE; data_type = DATA_TYPE_S16BE;
break; break;
case SND_PCM_FORMAT_FLOAT_LE: case SND_PCM_FORMAT_FLOAT_LE:
data_type = DATA_TYPE_FLOATLE; data_type = DATA_TYPE_FLOATLE;
break; break;
case SND_PCM_FORMAT_FLOAT_BE: case SND_PCM_FORMAT_FLOAT_BE:
data_type = DATA_TYPE_FLOATBE; data_type = DATA_TYPE_FLOATBE;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
int request_length = 10; int request_length = 10;
char request_data[request_length + MIN_REQUEST_LENGTH]; char request_data[request_length + MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_PREPARE; request_data[0] = REQUEST_CODE_PREPARE;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
memcpy(request_data + 5, &channels, 1); memcpy(request_data + 5, &channels, 1);
memcpy(request_data + 6, &data_type, 1); memcpy(request_data + 6, &data_type, 1);
memcpy(request_data + 7, &io->rate, 4); memcpy(request_data + 7, &io->rate, 4);
memcpy(request_data + 11, &io->buffer_size, 4); memcpy(request_data + 11, &io->buffer_size, 4);
int res = write(android_aserver->fd, &request_data, request_length + MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, request_length + MIN_REQUEST_LENGTH);
if (res < 0) return -EINVAL; if (res < 0) return -EINVAL;
if (android_aserver->use_shm) { if (android_aserver->use_shm) {
if (android_aserver->buffer_size > 0) { if (android_aserver->buffer_size > 0) {
munmap(android_aserver->buffer, android_aserver->buffer_size); munmap(android_aserver->buffer, android_aserver->buffer_size);
android_aserver->buffer_size = 0; android_aserver->buffer_size = 0;
} }
int fd = android_aserver_recv_fd(android_aserver->fd); int fd = android_aserver_recv_fd(android_aserver->fd);
if (fd >= 0) { if (fd >= 0) {
android_aserver->buffer_size = io->buffer_size * android_aserver->frame_bytes; android_aserver->buffer_size = io->buffer_size * android_aserver->frame_bytes;
android_aserver->buffer = mmap(NULL, android_aserver->buffer_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); android_aserver->buffer = mmap(NULL, android_aserver->buffer_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
if (android_aserver->buffer == MAP_FAILED) { if (android_aserver->buffer == MAP_FAILED) {
android_aserver->buffer_size = 0; android_aserver->buffer_size = 0;
android_aserver->use_shm = false; android_aserver->use_shm = false;
} }
close(fd); close(fd);
} }
} }
return 0; return 0;
} }
static snd_pcm_sframes_t android_aserver_pointer(snd_pcm_ioplug_t* io) { static snd_pcm_sframes_t android_aserver_pointer(snd_pcm_ioplug_t* io) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
int request_length = 0; int request_length = 0;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_POINTER; request_data[0] = REQUEST_CODE_POINTER;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
if (res < 0) return android_aserver->position; if (res < 0) return android_aserver->position;
int position; int position;
res = read(android_aserver->fd, &position, 4); res = read(android_aserver->fd, &position, 4);
if (res != 4) return android_aserver->position; if (res != 4) return android_aserver->position;
android_aserver->position = position; android_aserver->position = position;
return android_aserver->position; return android_aserver->position;
} }
static snd_pcm_sframes_t android_aserver_transfer(snd_pcm_ioplug_t* io, const snd_pcm_channel_area_t* areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) { static snd_pcm_sframes_t android_aserver_transfer(snd_pcm_ioplug_t* io, const snd_pcm_channel_area_t* areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
char* data = (char*)areas->addr + (areas->first + areas->step * offset) / 8; char* data = (char*)areas->addr + (areas->first + areas->step * offset) / 8;
int request_length = size * android_aserver->frame_bytes; int request_length = size * android_aserver->frame_bytes;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_WRITE; request_data[0] = REQUEST_CODE_WRITE;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
if (android_aserver->use_shm) memcpy(android_aserver->buffer, data, request_length); if (android_aserver->use_shm) memcpy(android_aserver->buffer, data, request_length);
int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
if (res < 0) return 0; if (res < 0) return 0;
if (!android_aserver->use_shm) { if (!android_aserver->use_shm) {
res = write(android_aserver->fd, data, request_length); res = write(android_aserver->fd, data, request_length);
if (res < 0) return 0; if (res < 0) return 0;
} }
return size; return size;
} }
static int android_aserver_drain(snd_pcm_ioplug_t* io) { static int android_aserver_drain(snd_pcm_ioplug_t* io) {
snd_pcm_android_aserver_t* android_aserver = io->private_data; snd_pcm_android_aserver_t* android_aserver = io->private_data;
int request_length = 0; int request_length = 0;
char request_data[MIN_REQUEST_LENGTH]; char request_data[MIN_REQUEST_LENGTH];
request_data[0] = REQUEST_CODE_DRAIN; request_data[0] = REQUEST_CODE_DRAIN;
memcpy(request_data + 1, &request_length, 4); memcpy(request_data + 1, &request_length, 4);
int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH); int res = write(android_aserver->fd, &request_data, MIN_REQUEST_LENGTH);
if (res < 0) return -EINVAL; if (res < 0) return -EINVAL;
return 0; return 0;
} }
static int android_aserver_set_hw_constraint(snd_pcm_ioplug_t* io) { static int android_aserver_set_hw_constraint(snd_pcm_ioplug_t* io) {
static const unsigned int access_list[] = {SND_PCM_ACCESS_RW_INTERLEAVED}; static const unsigned int access_list[] = {SND_PCM_ACCESS_RW_INTERLEAVED};
static const unsigned int format_list[] = {SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE, SND_PCM_FORMAT_FLOAT_LE, SND_PCM_FORMAT_FLOAT_BE}; static const unsigned int format_list[] = {SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE, SND_PCM_FORMAT_FLOAT_LE, SND_PCM_FORMAT_FLOAT_BE};
int err; int err;
@ -262,109 +262,109 @@ static int android_aserver_set_hw_constraint(snd_pcm_ioplug_t* io) {
err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 48000); err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 48000);
if (err < 0) return err; if (err < 0) return err;
err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 64, 64 * 1024); err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 64, 64 * 1024);
if (err < 0) return err; if (err < 0) return err;
err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 64); err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 64);
if (err < 0) return err; if (err < 0) return err;
return 0; return 0;
} }
static snd_pcm_ioplug_callback_t android_aserver_callback = { static snd_pcm_ioplug_callback_t android_aserver_callback = {
.close = android_aserver_close, .close = android_aserver_close,
.start = android_aserver_start, .start = android_aserver_start,
.stop = android_aserver_stop, .stop = android_aserver_stop,
.pause = android_aserver_pause, .pause = android_aserver_pause,
.resume = android_aserver_start, .resume = android_aserver_start,
.prepare = android_aserver_prepare, .prepare = android_aserver_prepare,
.transfer = android_aserver_transfer, .transfer = android_aserver_transfer,
.drain = android_aserver_drain, .drain = android_aserver_drain,
.pointer = android_aserver_pointer, .pointer = android_aserver_pointer,
}; };
static int android_aserver_connect() { static int android_aserver_connect() {
char* path = getenv("ANDROID_ALSA_SERVER"); char* path = getenv("ANDROID_ALSA_SERVER");
int fd = socket(AF_UNIX, SOCK_STREAM, 0); int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) return -1; if (fd < 0) return -1;
struct sockaddr_un server_addr; struct sockaddr_un server_addr;
memset(&server_addr, 0, sizeof(server_addr)); memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_LOCAL; server_addr.sun_family = AF_LOCAL;
strncpy(server_addr.sun_path, path, sizeof(server_addr.sun_path) - 1); strncpy(server_addr.sun_path, path, sizeof(server_addr.sun_path) - 1);
int res; int res;
do { do {
res = 0; res = 0;
if (connect(fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_un)) < 0) res = -errno; if (connect(fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_un)) < 0) res = -errno;
} }
while (res == -EINTR); while (res == -EINTR);
if (res < 0) { if (res < 0) {
close(fd); close(fd);
return -1; return -1;
} }
return fd; return fd;
} }
static int android_aserver_create(snd_pcm_t** pcmp, const char* name, snd_pcm_stream_t stream, int mode) { static int android_aserver_create(snd_pcm_t** pcmp, const char* name, snd_pcm_stream_t stream, int mode) {
snd_pcm_android_aserver_t* android_aserver; snd_pcm_android_aserver_t* android_aserver;
if (stream != SND_PCM_STREAM_PLAYBACK) return -ENOTSUP; if (stream != SND_PCM_STREAM_PLAYBACK) return -ENOTSUP;
android_aserver = calloc(1, sizeof(snd_pcm_android_aserver_t)); android_aserver = calloc(1, sizeof(snd_pcm_android_aserver_t));
if (!android_aserver) return -ENOMEM; if (!android_aserver) return -ENOMEM;
android_aserver->buffer_size = 0; android_aserver->buffer_size = 0;
android_aserver->io.version = SND_PCM_IOPLUG_VERSION; android_aserver->io.version = SND_PCM_IOPLUG_VERSION;
android_aserver->io.name = "ALSA <-> Android AServer PCM Plugin"; android_aserver->io.name = "ALSA <-> Android AServer PCM Plugin";
android_aserver->io.callback = &android_aserver_callback; android_aserver->io.callback = &android_aserver_callback;
android_aserver->io.mmap_rw = 0; android_aserver->io.mmap_rw = 0;
android_aserver->io.private_data = android_aserver; android_aserver->io.private_data = android_aserver;
int res = -EINVAL; int res = -EINVAL;
android_aserver->fd = android_aserver_connect(); android_aserver->fd = android_aserver_connect();
if (android_aserver->fd < 0) goto error; if (android_aserver->fd < 0) goto error;
char* use_shm_value = getenv("ANDROID_ASERVER_USE_SHM"); char* use_shm_value = getenv("ANDROID_ASERVER_USE_SHM");
android_aserver->use_shm = use_shm_value && (strcmp(use_shm_value, "true") == 0 || strcmp(use_shm_value, "1") == 0); android_aserver->use_shm = use_shm_value && (strcmp(use_shm_value, "true") == 0 || strcmp(use_shm_value, "1") == 0);
res = snd_pcm_ioplug_create(&android_aserver->io, name, stream, mode); res = snd_pcm_ioplug_create(&android_aserver->io, name, stream, mode);
if (res < 0) goto error; if (res < 0) goto error;
res = android_aserver_set_hw_constraint(&android_aserver->io); res = android_aserver_set_hw_constraint(&android_aserver->io);
if (res < 0) { if (res < 0) {
snd_pcm_ioplug_delete(&android_aserver->io); snd_pcm_ioplug_delete(&android_aserver->io);
goto error; goto error;
} }
*pcmp = android_aserver->io.pcm; *pcmp = android_aserver->io.pcm;
return 0; return 0;
error: error:
if (android_aserver->fd >= 0) close(android_aserver->fd); if (android_aserver->fd >= 0) close(android_aserver->fd);
free(android_aserver); free(android_aserver);
return res; return res;
} }
SND_PCM_PLUGIN_DEFINE_FUNC(android_aserver) { SND_PCM_PLUGIN_DEFINE_FUNC(android_aserver) {
snd_config_iterator_t i, next; snd_config_iterator_t i, next;
snd_config_for_each(i, next, conf) { snd_config_for_each(i, next, conf) {
snd_config_t* n = snd_config_iterator_entry(i); snd_config_t* n = snd_config_iterator_entry(i);
const char* id; const char* id;
if (snd_config_get_id(n, &id) < 0) continue; if (snd_config_get_id(n, &id) < 0) continue;
if (strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) continue; if (strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) continue;
return -EINVAL; return -EINVAL;
} }
int err = android_aserver_create(pcmp, name, stream, mode); int err = android_aserver_create(pcmp, name, stream, mode);
return err; return err;
} }
SND_PCM_PLUGIN_SYMBOL(android_aserver); SND_PCM_PLUGIN_SYMBOL(android_aserver);