replace common qcom sources with samsung ones
This commit is contained in:
6
qcom/opensource/agm/plugins/Android.mk
Normal file
6
qcom/opensource/agm/plugins/Android.mk
Normal file
@@ -0,0 +1,6 @@
|
||||
MY_LOCAL_PATH := $(call my-dir)
|
||||
include $(MY_LOCAL_PATH)/tinyalsa/Android.mk
|
||||
include $(MY_LOCAL_PATH)/tinyalsa/test/Android.mk
|
||||
ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
|
||||
include $(MY_LOCAL_PATH)/tinyalsa/test/gtest/Android.mk
|
||||
endif
|
1359
qcom/opensource/agm/plugins/alsalib/src/agm_ctl_plugin.c
Normal file
1359
qcom/opensource/agm/plugins/alsalib/src/agm_ctl_plugin.c
Normal file
File diff suppressed because it is too large
Load Diff
554
qcom/opensource/agm/plugins/alsalib/src/agm_io_plugin.c
Normal file
554
qcom/opensource/agm/plugins/alsalib/src/agm_io_plugin.c
Normal file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
** Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
#define LOG_TAG "PLUGIN: AGMIO"
|
||||
#include <stdio.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/pcm_external.h>
|
||||
|
||||
#include <agm/agm_api.h>
|
||||
#include <agm/agm_list.h>
|
||||
#include <snd-card-def.h>
|
||||
#include "utils.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
enum {
|
||||
AGM_IO_STATE_OPEN = 1,
|
||||
AGM_IO_STATE_SETUP,
|
||||
AGM_IO_STATE_PREPARED,
|
||||
AGM_IO_STATE_RUNNING,
|
||||
};
|
||||
|
||||
struct agmio_priv {
|
||||
snd_pcm_ioplug_t io;
|
||||
|
||||
int card;
|
||||
int device;
|
||||
|
||||
void *card_node;
|
||||
void *pcm_node;
|
||||
uint64_t handle;
|
||||
struct agm_media_config *media_config;
|
||||
struct agm_buffer_config *buffer_config;
|
||||
struct agm_session_config *session_config;
|
||||
unsigned int period_size;
|
||||
size_t frame_size;
|
||||
unsigned int state;
|
||||
snd_pcm_uframes_t hw_pointer;
|
||||
snd_pcm_uframes_t boundary;
|
||||
int event_fd;
|
||||
/* add private variables here */
|
||||
};
|
||||
|
||||
static int agm_get_session_handle(struct agmio_priv *priv,
|
||||
uint64_t *handle)
|
||||
{
|
||||
if (!priv)
|
||||
return -EINVAL;
|
||||
|
||||
*handle = priv->handle;
|
||||
if (!*handle)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int agm_io_start(snd_pcm_ioplug_t * io)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
uint64_t handle;
|
||||
int ret;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->state < AGM_IO_STATE_PREPARED) {
|
||||
ret = agm_session_prepare(handle);
|
||||
errno = ret;
|
||||
if (ret)
|
||||
return ret;
|
||||
pcm->state = AGM_IO_STATE_PREPARED;
|
||||
}
|
||||
|
||||
if (pcm->state != AGM_IO_STATE_RUNNING) {
|
||||
ret = agm_session_start(handle);
|
||||
if (!ret)
|
||||
pcm->state = AGM_IO_STATE_RUNNING;
|
||||
}
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_stop(snd_pcm_ioplug_t * io)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
uint64_t handle;
|
||||
int ret;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = agm_session_stop(handle);
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_drain(snd_pcm_ioplug_t * io)
|
||||
{
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_sframes_t agm_io_pointer(snd_pcm_ioplug_t * io)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
snd_pcm_sframes_t new_hw_ptr;
|
||||
|
||||
new_hw_ptr = pcm->hw_pointer;
|
||||
if (io->stream == SND_PCM_STREAM_CAPTURE) {
|
||||
if (pcm->hw_pointer == 0)
|
||||
new_hw_ptr = io->period_size * pcm->frame_size;
|
||||
}
|
||||
|
||||
|
||||
AGM_LOGD("%s %d\n", __func__, io->state);
|
||||
return new_hw_ptr;
|
||||
}
|
||||
|
||||
static snd_pcm_sframes_t agm_io_transfer(snd_pcm_ioplug_t * io,
|
||||
const snd_pcm_channel_area_t * areas,
|
||||
snd_pcm_uframes_t offset,
|
||||
snd_pcm_uframes_t size)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
uint64_t handle;
|
||||
uint8_t *buf = (uint8_t *) areas->addr + (areas->first + areas->step * offset) / 8;
|
||||
size_t count;
|
||||
int ret = 0;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pcm->state != AGM_IO_STATE_RUNNING) {
|
||||
ret = agm_io_start(io);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
count = size * pcm->frame_size;
|
||||
|
||||
if (io->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
ret = agm_session_write(handle, buf, &count);
|
||||
else
|
||||
ret = agm_session_read(handle, buf, &count);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = snd_pcm_bytes_to_frames(io->pcm, count);
|
||||
pcm->hw_pointer += ret;
|
||||
}
|
||||
|
||||
if (pcm->hw_pointer > pcm->boundary)
|
||||
pcm->hw_pointer -= pcm->boundary;
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_prepare(snd_pcm_ioplug_t * io)
|
||||
{
|
||||
uint64_t handle;
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
int ret = 0;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = agm_session_prepare(handle);
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_hw_params(snd_pcm_ioplug_t * io,
|
||||
snd_pcm_hw_params_t * params)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
struct agm_media_config *media_config;
|
||||
struct agm_buffer_config *buffer_config;
|
||||
struct agm_session_config *session_config = NULL;
|
||||
uint64_t handle;
|
||||
int ret = 0, sess_mode = 0;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
|
||||
pcm->frame_size = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
|
||||
|
||||
media_config = pcm->media_config;
|
||||
buffer_config = pcm->buffer_config;
|
||||
session_config = pcm->session_config;
|
||||
|
||||
media_config->rate = io->rate;
|
||||
media_config->channels = io->channels;
|
||||
media_config->format = io->format;
|
||||
|
||||
buffer_config->count = io->buffer_size / io->period_size;
|
||||
pcm->period_size = io->period_size;
|
||||
buffer_config->size = io->period_size * pcm->frame_size;
|
||||
pcm->hw_pointer = 0;
|
||||
|
||||
snd_card_def_get_int(pcm->pcm_node, "session_mode", &sess_mode);
|
||||
|
||||
session_config->dir = (io->stream == SND_PCM_STREAM_PLAYBACK) ? RX : TX;
|
||||
session_config->sess_mode = sess_mode;
|
||||
ret = agm_session_set_config(pcm->handle, session_config,
|
||||
pcm->media_config, pcm->buffer_config);
|
||||
if (!ret)
|
||||
pcm->state = AGM_IO_STATE_SETUP;
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
struct agm_session_config *session_config = NULL;
|
||||
uint64_t handle = 0;
|
||||
int ret = 0, sess_mode = 0;
|
||||
snd_pcm_uframes_t start_threshold;
|
||||
snd_pcm_uframes_t stop_threshold;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
session_config = pcm->session_config;
|
||||
|
||||
snd_card_def_get_int(pcm->pcm_node, "session_mode", &sess_mode);
|
||||
|
||||
session_config->dir = (io->stream == SND_PCM_STREAM_PLAYBACK) ? RX : TX;
|
||||
session_config->sess_mode = sess_mode;
|
||||
snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
|
||||
snd_pcm_sw_params_get_stop_threshold(params, &stop_threshold);
|
||||
snd_pcm_sw_params_get_boundary(params, &pcm->boundary);
|
||||
session_config->start_threshold = (uint32_t)start_threshold;
|
||||
session_config->stop_threshold = (uint32_t)stop_threshold;
|
||||
ret = agm_session_set_config(pcm->handle, session_config,
|
||||
pcm->media_config, pcm->buffer_config);
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_close(snd_pcm_ioplug_t * io)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
uint64_t handle;
|
||||
int ret = 0;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = agm_session_close(handle);
|
||||
|
||||
snd_card_def_put_card(pcm->card_node);
|
||||
free(pcm->buffer_config);
|
||||
free(pcm->media_config);
|
||||
free(pcm->session_config);
|
||||
free(io->private_data);
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int agm_io_pause(snd_pcm_ioplug_t * io, int enable)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
uint64_t handle;
|
||||
int ret = 0;
|
||||
|
||||
ret = agm_get_session_handle(pcm, &handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (enable)
|
||||
ret = agm_session_pause(handle);
|
||||
else
|
||||
ret = agm_session_resume(handle);
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int agm_io_poll_desc_count(snd_pcm_ioplug_t *io) {
|
||||
(void)io;
|
||||
/* TODO : Needed for ULL usecases */
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int agm_io_poll_desc(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
||||
unsigned int space)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
|
||||
/* TODO : Needed for ULL usecases, Need update */
|
||||
if (space != 1) {
|
||||
AGM_LOGE("%s space %u is not correct!\n", __func__, space);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (io->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
pfd[0].fd = pcm->event_fd;
|
||||
pfd[0].events = POLLOUT;
|
||||
} else {
|
||||
pfd[0].fd = pcm->event_fd;
|
||||
pfd[0].events = POLLIN;
|
||||
}
|
||||
|
||||
AGM_LOGD("%s: exit\n", __func__);
|
||||
return space;
|
||||
}
|
||||
|
||||
static int agm_io_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
|
||||
unsigned int nfds, unsigned short *revents)
|
||||
{
|
||||
struct agmio_priv *pcm = io->private_data;
|
||||
|
||||
/* TODO : Needed for ULL usecases, Need update */
|
||||
if (nfds != 1) {
|
||||
AGM_LOGE("%s nfds %u is not correct!\n", __func__, nfds);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
*revents = POLLIN;
|
||||
} else if (pfd[0].revents & POLLOUT) {
|
||||
*revents = POLLOUT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const snd_pcm_ioplug_callback_t agm_io_callback = {
|
||||
.start = agm_io_start,
|
||||
.stop = agm_io_stop,
|
||||
.pointer = agm_io_pointer,
|
||||
.drain = agm_io_drain,
|
||||
.transfer = agm_io_transfer,
|
||||
.prepare = agm_io_prepare,
|
||||
.hw_params = agm_io_hw_params,
|
||||
.sw_params = agm_io_sw_params,
|
||||
.close = agm_io_close,
|
||||
.pause = agm_io_pause,
|
||||
.poll_descriptors_count = agm_io_poll_desc_count,
|
||||
.poll_descriptors = agm_io_poll_desc,
|
||||
.poll_revents = agm_io_poll_revents,
|
||||
};
|
||||
|
||||
static int agm_hw_constraint(struct agmio_priv* priv)
|
||||
{
|
||||
snd_pcm_ioplug_t *io = &priv->io;
|
||||
int ret;
|
||||
|
||||
static const snd_pcm_access_t access_list[] = {
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
SND_PCM_ACCESS_MMAP_INTERLEAVED
|
||||
};
|
||||
static const unsigned int formats[] = {
|
||||
SND_PCM_FORMAT_U8,
|
||||
SND_PCM_FORMAT_S16_LE,
|
||||
SND_PCM_FORMAT_S32_LE,
|
||||
SND_PCM_FORMAT_S24_3LE,
|
||||
SND_PCM_FORMAT_S24_LE,
|
||||
};
|
||||
|
||||
ret = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
|
||||
ARRAY_SIZE(access_list),
|
||||
access_list);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
|
||||
ARRAY_SIZE(formats), formats);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
|
||||
1, 8);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
|
||||
8000, 384000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
|
||||
64, 122880);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
|
||||
1, 8);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SND_PCM_PLUGIN_DEFINE_FUNC(agm)
|
||||
{
|
||||
snd_config_iterator_t it, next;
|
||||
struct agmio_priv *priv = NULL;
|
||||
long card = 0, device = 100;
|
||||
struct agm_session_config *session_config;
|
||||
struct agm_media_config *media_config;
|
||||
struct agm_buffer_config *buffer_config;
|
||||
void *card_node, *pcm_node;
|
||||
enum agm_session_mode sess_mode = AGM_SESSION_DEFAULT;
|
||||
uint64_t handle;
|
||||
int ret = 0, session_id = device;
|
||||
|
||||
priv = calloc(1, sizeof(*priv));
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
media_config = calloc(1, sizeof(struct agm_media_config));
|
||||
if (!media_config)
|
||||
return -ENOMEM;
|
||||
|
||||
buffer_config = calloc(1, sizeof(struct agm_buffer_config));
|
||||
if (!buffer_config)
|
||||
return -ENOMEM;
|
||||
|
||||
session_config = calloc(1, sizeof(struct agm_session_config));
|
||||
if (!session_config)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_config_for_each(it, next, conf) {
|
||||
snd_config_t *n = snd_config_iterator_entry(it);
|
||||
const char *id;
|
||||
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
continue;
|
||||
if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
|
||||
continue;
|
||||
if (strcmp(id, "card") == 0) {
|
||||
if (snd_config_get_integer(n, &card) < 0) {
|
||||
AGM_LOGE("Invalid type for %s", id);
|
||||
ret = -EINVAL;
|
||||
goto err_free_priv;
|
||||
}
|
||||
AGM_LOGD("card id is %d\n", card);
|
||||
priv->card = card;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(id, "device") == 0) {
|
||||
if (snd_config_get_integer(n, &device) < 0) {
|
||||
AGM_LOGE("Invalid type for %s", id);
|
||||
ret = -EINVAL;
|
||||
goto err_free_priv;
|
||||
}
|
||||
AGM_LOGD("device id is %d\n", device);
|
||||
priv->device = device;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
card_node = snd_card_def_get_card(card);
|
||||
if (!card_node) {
|
||||
AGM_LOGE("card node is NULL\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_priv;
|
||||
}
|
||||
priv->card_node = card_node;
|
||||
|
||||
pcm_node = snd_card_def_get_node(card_node, device, SND_NODE_TYPE_PCM);
|
||||
if (!pcm_node) {
|
||||
AGM_LOGE("pcm node is NULL\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_priv;
|
||||
}
|
||||
priv->pcm_node = pcm_node;
|
||||
|
||||
snd_card_def_get_int(pcm_node, "session_mode", &sess_mode);
|
||||
|
||||
session_id = priv->device;
|
||||
ret = agm_session_open(session_id, sess_mode, &handle);
|
||||
if (ret) {
|
||||
AGM_LOGE("handle is NULL\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_priv;
|
||||
}
|
||||
|
||||
priv->media_config = media_config;
|
||||
priv->buffer_config = buffer_config;
|
||||
priv->session_config = session_config;
|
||||
priv->handle = handle;
|
||||
priv->event_fd = -1;
|
||||
priv->state = AGM_IO_STATE_OPEN;
|
||||
priv->io.version = SND_PCM_IOPLUG_VERSION;
|
||||
priv->io.name = "AGM PCM I/O Plugin";
|
||||
priv->io.mmap_rw = 0;
|
||||
priv->io.callback = &agm_io_callback;
|
||||
priv->io.private_data = priv;
|
||||
|
||||
ret = snd_pcm_ioplug_create(&priv->io, name, stream, mode);
|
||||
if (ret < 0) {
|
||||
AGM_LOGE("IO plugin create failed\n");
|
||||
goto err_free_priv;
|
||||
}
|
||||
|
||||
if ((priv->event_fd = eventfd(0, EFD_CLOEXEC)) == -1) {
|
||||
AGM_LOGE("failed to create event_fd\n");
|
||||
ret = -EINVAL;
|
||||
goto err_free_priv;
|
||||
}
|
||||
|
||||
ret = agm_hw_constraint(priv);
|
||||
if (ret < 0) {
|
||||
snd_pcm_ioplug_delete(&priv->io);
|
||||
goto err_free_priv;
|
||||
}
|
||||
|
||||
*pcmp = priv->io.pcm;
|
||||
return 0;
|
||||
err_free_priv:
|
||||
free(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SND_PCM_PLUGIN_SYMBOL(agm);
|
124
qcom/opensource/agm/plugins/tinyalsa/Android.mk
Normal file
124
qcom/opensource/agm/plugins/tinyalsa/Android.mk
Normal file
@@ -0,0 +1,124 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
# Build libagm_pcm_plugin
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libagm_pcm_plugin
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wall
|
||||
LOCAL_SRC_FILES := src/agm_pcm_plugin.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libarosal_headers
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libsndcardparser \
|
||||
libagmclient \
|
||||
libutils \
|
||||
libcutils \
|
||||
liblog
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DYNAMIC_LOG)), true)
|
||||
LOCAL_CFLAGS += -DDYNAMIC_LOG_ENABLED
|
||||
LOCAL_C_INCLUDES += $(TOP)/external/expat/lib/expat.h
|
||||
LOCAL_SHARED_LIBRARIES += libaudio_log_utils
|
||||
LOCAL_SHARED_LIBRARIES += libexpat
|
||||
LOCAL_HEADER_LIBRARIES += libaudiologutils_headers
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Build libagm_mixer_plugin
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libagm_mixer_plugin
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
LOCAL_SRC_FILES := src/agm_mixer_plugin.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libarosal_headers
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libsndcardparser \
|
||||
libagmclient \
|
||||
libcutils \
|
||||
libutils \
|
||||
liblog
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DYNAMIC_LOG)), true)
|
||||
LOCAL_CFLAGS += -DDYNAMIC_LOG_ENABLED
|
||||
LOCAL_C_INCLUDES += $(TOP)/external/expat/lib/expat.h
|
||||
LOCAL_SHARED_LIBRARIES += libaudio_log_utils
|
||||
LOCAL_SHARED_LIBRARIES += libexpat
|
||||
LOCAL_HEADER_LIBRARIES += libaudiologutils_headers
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Build libagm_compress_plugin
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libagm_compress_plugin
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
|
||||
LOCAL_SRC_FILES := src/agm_compress_plugin.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libarosal_headers
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libsndcardparser \
|
||||
libagmclient \
|
||||
libutils \
|
||||
libcutils \
|
||||
liblog
|
||||
|
||||
# Use flag based selection to use QTI vs open source tinycompress project
|
||||
|
||||
ifeq ($(TARGET_USES_QTI_TINYCOMPRESS),true)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa\
|
||||
libqti-tinycompress
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(TOP)/external/tinycompress/include
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa\
|
||||
libtinycompress
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DYNAMIC_LOG)), true)
|
||||
LOCAL_CFLAGS += -DDYNAMIC_LOG_ENABLED
|
||||
LOCAL_C_INCLUDES += $(TOP)/external/expat/lib/expat.h
|
||||
LOCAL_SHARED_LIBRARIES += libaudio_log_utils
|
||||
LOCAL_SHARED_LIBRARIES += libexpat
|
||||
LOCAL_HEADER_LIBRARIES += libaudiologutils_headers
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
68
qcom/opensource/agm/plugins/tinyalsa/Makefile.am
Normal file
68
qcom/opensource/agm/plugins/tinyalsa/Makefile.am
Normal file
@@ -0,0 +1,68 @@
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = agmplugin.pc
|
||||
EXTRA_DIST = $(pkgconfig_DATA)
|
||||
|
||||
library_includedir = $(includedir)
|
||||
|
||||
AM_CFLAGS := -Wno-unused-parameter
|
||||
if !BUILDSYSTEM_OPENWRT
|
||||
AM_CFLAGS += -I $(top_srcdir)/include @AGM_CFLAGS@
|
||||
AM_CFLAGS += @GLIB_CFLAGS@ -Dstrlcpy=g_strlcpy -Dstrlcat=g_strlcat -include glib.h
|
||||
AM_CFLAGS += -D__unused=__attribute__\(\(__unused__\)\) -DLINUX_ENABLED
|
||||
AM_CFLAGS += @SNDPARSER_CFLAGS@
|
||||
AM_CFLAGS += -Wno-unused-parameter
|
||||
AM_CFLAGS += -DDYNAMIC_LOG_ENABLED
|
||||
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = libagm_pcm_plugin.la
|
||||
libagm_pcm_plugin_la_SOURCES = src/agm_pcm_plugin.c
|
||||
libagm_pcm_plugin_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagm_pcm_plugin_la_LDFLAGS = -ltinyalsa -lsndcardparser -avoid-version -shared
|
||||
if BUILDSYSTEM_OPENWRT
|
||||
libagm_pcm_plugin_la_LDFLAGS += -lagmclientwrapper
|
||||
else
|
||||
libagm_pcm_plugin_la_LDFLAGS += -lagmclientwrapper -laudio_log_utils
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES += libagm_pcm_passthrough_plugin.la
|
||||
libagm_pcm_passthrough_plugin_la_SOURCES = src/agm_pcm_plugin.c
|
||||
libagm_pcm_passthrough_plugin_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagm_pcm_passthrough_plugin_la_LDFLAGS = -ltinyalsa -lsndcardparser -avoid-version -shared
|
||||
if BUILDSYSTEM_OPENWRT
|
||||
libagm_pcm_passthrough_plugin_la_LDFLAGS += -lagm
|
||||
else
|
||||
libagm_pcm_passthrough_plugin_la_LDFLAGS += -lagm -laudio_log_utils
|
||||
endif
|
||||
|
||||
|
||||
lib_LTLIBRARIES += libagm_compress_plugin.la
|
||||
libagm_compress_plugin_la_SOURCES = src/agm_compress_plugin.c
|
||||
libagm_compress_plugin_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagm_compress_plugin_la_LDFLAGS = -ltinyalsa -ltinycompress -lsndcardparser -lpthread -avoid-version -laudio_log_utils -shared -lagmclientwrapper
|
||||
|
||||
lib_LTLIBRARIES += libagm_compress_passthrough_plugin.la
|
||||
libagm_compress_passthrough_plugin_la_SOURCES = src/agm_compress_plugin.c
|
||||
libagm_compress_passthrough_plugin_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagm_compress_passthrough_plugin_la_LDFLAGS = -ltinyalsa -lsndcardparser -lpthread -avoid-version -laudio_log_utils -shared -lagm
|
||||
|
||||
lib_LTLIBRARIES += libagm_mixer_plugin.la
|
||||
libagm_mixer_plugin_la_SOURCES = src/agm_mixer_plugin.c
|
||||
libagm_mixer_plugin_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagm_mixer_plugin_la_LDFLAGS = -ltinyalsa -lsndcardparser -avoid-version -shared
|
||||
if BUILDSYSTEM_OPENWRT
|
||||
libagm_mixer_plugin_la_LDFLAGS += -lagmclientwrapper
|
||||
else
|
||||
libagm_mixer_plugin_la_LDFLAGS += -lagmclientwrapper -laudio_log_utils
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES += libagm_mixer_passthrough_plugin.la
|
||||
libagm_mixer_passthrough_plugin_la_SOURCES = src/agm_mixer_plugin.c
|
||||
libagm_mixer_passthrough_plugin_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagm_mixer_passthrough_plugin_la_LDFLAGS = -ltinyalsa -lsndcardparser -avoid-version -shared
|
||||
if BUILDSYSTEM_OPENWRT
|
||||
libagm_mixer_passthrough_plugin_la_LDFLAGS += -lagm
|
||||
else
|
||||
libagm_mixer_passthrough_plugin_la_LDFLAGS += -lagm
|
||||
libagm_mixer_passthrough_plugin_la_LDFLAGS += -laudio_log_utils
|
||||
endif
|
1
qcom/opensource/agm/plugins/tinyalsa/README.md
Normal file
1
qcom/opensource/agm/plugins/tinyalsa/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# agm_plugin
|
10
qcom/opensource/agm/plugins/tinyalsa/agmplugin.pc.in
Normal file
10
qcom/opensource/agm/plugins/tinyalsa/agmplugin.pc.in
Normal file
@@ -0,0 +1,10 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: agmplugin
|
||||
Description: agm plugin library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lagmplugin
|
||||
Cflags: -I${includedir}
|
57
qcom/opensource/agm/plugins/tinyalsa/configure.ac
Normal file
57
qcom/opensource/agm/plugins/tinyalsa/configure.ac
Normal file
@@ -0,0 +1,57 @@
|
||||
# Requires autoconf tool later than 2.61
|
||||
AC_PREREQ(2.69)
|
||||
# Initialize the agm plugin package version 1.0.0
|
||||
AC_INIT([agmplugin],1.0.0)
|
||||
# Does not strictly follow GNU Coding standards
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
# Disables auto rebuilding of configure, Makefile.ins
|
||||
AM_MAINTAINER_MODE
|
||||
# Verifies the --srcdir is correct by checking for the path
|
||||
AC_CONFIG_SRCDIR([src/agm_mixer_plugin.c])
|
||||
# defines some macros variable to be included by source
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AC_ARG_WITH([glib],
|
||||
AC_HELP_STRING([--with-glib],
|
||||
[enable glib, Build against glib. Use this when building for HLOS systems which use glib]))
|
||||
|
||||
if (test "x${with_glib}" = "xyes"); then
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||
AC_MSG_ERROR(GThread >= 2.16 is required))
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.16 is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
|
||||
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
|
||||
|
||||
# Checks for libraries
|
||||
PKG_CHECK_MODULES([AGM], [agm])
|
||||
AC_SUBST([AGM_CFLAGS])
|
||||
|
||||
PKG_CHECK_MODULES([SNDPARSER], [sndparser])
|
||||
AC_SUBST([SNDPARSER_CFLAGS])
|
||||
|
||||
AC_ARG_WITH([openwrt],
|
||||
AS_HELP_STRING([use openwrt (default is no)]),
|
||||
[with_openwrt=$withval],
|
||||
[with_openwrt=no])
|
||||
AM_CONDITIONAL([BUILDSYSTEM_OPENWRT], [test "x${with_openwrt}" = "xyes"])
|
||||
|
||||
AC_CONFIG_FILES([ Makefile agmplugin.pc ])
|
||||
AC_OUTPUT
|
1174
qcom/opensource/agm/plugins/tinyalsa/src/agm_compress_plugin.c
Normal file
1174
qcom/opensource/agm/plugins/tinyalsa/src/agm_compress_plugin.c
Normal file
File diff suppressed because it is too large
Load Diff
181
qcom/opensource/agm/plugins/tinyalsa/src/agm_dummy_impl.c
Normal file
181
qcom/opensource/agm/plugins/tinyalsa/src/agm_dummy_impl.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <agm/agm_api.h>
|
||||
#include <agm/utils.h>
|
||||
|
||||
#define ARRAY_SIZE(a) \
|
||||
(sizeof(a) / sizeof(a[0]))
|
||||
|
||||
#ifdef DYNAMIC_LOG_ENABLED
|
||||
#include <log_xml_parser.h>
|
||||
#define LOG_MASK AGM_MOD_FILE_AGM_DUMMY_IMPL
|
||||
#include <log_utils.h>
|
||||
#endif
|
||||
|
||||
int agm_session_write(struct session_obj *handle, void *buff, size_t count)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int agm_session_read(struct session_obj *handle, void *buff, size_t count)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_stop(struct session_obj *handle)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_start(struct session_obj *handle)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_prepare(struct session_obj *handle)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_close(struct session_obj *handle)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_set_config(struct session_obj *handle,
|
||||
struct agm_session_config *session_config,
|
||||
struct agm_media_config *media_config,
|
||||
struct agm_buffer_config *buffer_config)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_open(uint32_t session_id, enum agm_session_mode sess_mode,
|
||||
struct session_obj **handle)
|
||||
{
|
||||
struct session_obj *h = malloc(sizeof(100));
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
*handle = h;
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int agm_audio_intf_set_media_config(uint32_t audio_intf,
|
||||
struct agm_media_config *media_config)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_audio_intf_set_metadata(uint32_t audio_intf,
|
||||
struct agm_meta_data *metadata)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_set_metadata(uint32_t session_id,
|
||||
struct agm_meta_data *metadata)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_audio_inf_set_metadata(uint32_t session_id,
|
||||
uint32_t audio_intf,
|
||||
struct agm_meta_data *metadata)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_audio_inf_connect(uint32_t session_id,
|
||||
uint32_t audio_intf, bool state)
|
||||
{
|
||||
AGM_LOGD("%s: s_id %u, aif_id %u, %s\n", __func__,
|
||||
session_id, audio_intf,
|
||||
state ? "connect" : "disconnect");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct aif_info be_list[] = {
|
||||
{
|
||||
.aif_name = "SLIM_0_RX",
|
||||
.dir = RX,
|
||||
},
|
||||
{
|
||||
.aif_name = "SLIM_1_RX",
|
||||
.dir = RX,
|
||||
},
|
||||
{
|
||||
.aif_name = "SLIM_0_TX",
|
||||
.dir = TX,
|
||||
},
|
||||
{
|
||||
.aif_name = "SLIM_1_TX",
|
||||
.dir = TX,
|
||||
},
|
||||
};
|
||||
|
||||
int agm_get_aif_info_list(struct aif_info *aif_list, size_t *num_aif_info)
|
||||
{
|
||||
int i;
|
||||
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
if (*num_aif_info == 0) {
|
||||
*num_aif_info = ARRAY_SIZE(be_list);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < *num_aif_info; i++)
|
||||
memcpy((aif_list + i), &be_list[i], sizeof(struct aif_info));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int agm_session_set_loopback(uint32_t capture_session_id,
|
||||
uint32_t playback_session_id)
|
||||
{
|
||||
AGM_LOGD("%s %d\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
2463
qcom/opensource/agm/plugins/tinyalsa/src/agm_mixer_plugin.c
Normal file
2463
qcom/opensource/agm/plugins/tinyalsa/src/agm_mixer_plugin.c
Normal file
File diff suppressed because it is too large
Load Diff
1042
qcom/opensource/agm/plugins/tinyalsa/src/agm_pcm_plugin.c
Normal file
1042
qcom/opensource/agm/plugins/tinyalsa/src/agm_pcm_plugin.c
Normal file
File diff suppressed because it is too large
Load Diff
443
qcom/opensource/agm/plugins/tinyalsa/test/AgmCap.cpp
Normal file
443
qcom/opensource/agm/plugins/tinyalsa/test/AgmCap.cpp
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
** Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Copyright 2011, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of The Android Open Source Project nor the names of
|
||||
** its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
** DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "agmmixer.h"
|
||||
|
||||
#define ID_RIFF 0x46464952
|
||||
#define ID_WAVE 0x45564157
|
||||
#define ID_FMT 0x20746d66
|
||||
#define ID_DATA 0x61746164
|
||||
|
||||
#define FORMAT_PCM 1
|
||||
|
||||
struct wav_header {
|
||||
uint32_t riff_id;
|
||||
uint32_t riff_sz;
|
||||
uint32_t riff_fmt;
|
||||
uint32_t fmt_id;
|
||||
uint32_t fmt_sz;
|
||||
uint16_t audio_format;
|
||||
uint16_t num_channels;
|
||||
uint32_t sample_rate;
|
||||
uint32_t byte_rate;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
uint32_t data_id;
|
||||
uint32_t data_sz;
|
||||
};
|
||||
|
||||
int capturing = 1;
|
||||
|
||||
static unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
|
||||
unsigned int usb_device, unsigned int channels, unsigned int rate,
|
||||
enum pcm_format format, unsigned int period_size,
|
||||
unsigned int period_count, unsigned int cap_time,
|
||||
struct device_config *dev_config, unsigned int stream_kv,
|
||||
unsigned int device_kv, unsigned int instance_kv,
|
||||
unsigned int devicepp_kv);
|
||||
|
||||
static void sigint_handler(int sig)
|
||||
{
|
||||
capturing = 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf(" Usage: %s file.wav [-help print usage] [-D card] [-d device]\n"
|
||||
" [-c channels] [-r rate] [-b bits] [-p period_size]\n"
|
||||
" [-n n_periods] [-T capture time] [-i intf_name] [-dkv device_kv]\n"
|
||||
" [-dppkv deviceppkv] : Assign 0 if no device pp in the graph\n"
|
||||
" [-ikv instance_kv] : Assign 0 if no instance kv in the graph\n"
|
||||
" [-skv stream_kv]\n"
|
||||
" [-is_24_LE] : [0-1] Only to be used if user wants to record 32 bps clip\n"
|
||||
" [-usb_d usb device]\n"
|
||||
" 0: If bps is 32, and format should be S32_LE\n"
|
||||
" 1: If bps is 24, and format should be S24_LE\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *file;
|
||||
struct wav_header header;
|
||||
unsigned int card = 100;
|
||||
unsigned int device = 101;
|
||||
unsigned int usb_device = 1;
|
||||
unsigned int channels = 2;
|
||||
unsigned int rate = 44100;
|
||||
unsigned int bits = 16;
|
||||
unsigned int frames;
|
||||
unsigned int period_size = 1024;
|
||||
unsigned int period_count = 4;
|
||||
unsigned int cap_time = 0;
|
||||
char *intf_name = NULL;
|
||||
unsigned int device_kv = 0;
|
||||
struct device_config config;
|
||||
enum pcm_format format;
|
||||
int ret = 0;
|
||||
unsigned int devicepp_kv = 0;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int instance_kv = INSTANCE_1;
|
||||
bool is_24_LE = false;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = fopen(argv[1], "wb");
|
||||
if (!file) {
|
||||
printf("Unable to create file '%s'\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse command line arguments */
|
||||
argv += 2;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
channels = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-r") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
rate = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-b") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
bits = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-p") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
period_size = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-n") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
period_count = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-T") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
cap_time = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_name = *argv;
|
||||
} else if (strcmp(*argv, "-dkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-ikv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
instance_kv = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-dppkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
devicepp_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-is_24_LE") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
is_24_LE = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-usb_d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
usb_device = atoi(*argv);
|
||||
}else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
header.riff_id = ID_RIFF;
|
||||
header.riff_sz = 0;
|
||||
header.riff_fmt = ID_WAVE;
|
||||
header.fmt_id = ID_FMT;
|
||||
header.fmt_sz = 16;
|
||||
header.audio_format = FORMAT_PCM;
|
||||
header.num_channels = channels;
|
||||
header.sample_rate = rate;
|
||||
|
||||
switch (bits) {
|
||||
case 32:
|
||||
if (is_24_LE)
|
||||
format = PCM_FORMAT_S24_LE;
|
||||
else
|
||||
format = PCM_FORMAT_S32_LE;
|
||||
break;
|
||||
case 24:
|
||||
format = PCM_FORMAT_S24_3LE;
|
||||
break;
|
||||
case 16:
|
||||
format = PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
default:
|
||||
printf("%u bits is not supported.\n", bits);
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (intf_name == NULL)
|
||||
return 1;
|
||||
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, intf_name, &config);
|
||||
if (ret) {
|
||||
printf("Invalid input, entry not found for %s\n", intf_name);
|
||||
fclose(file);
|
||||
return ret;
|
||||
}
|
||||
if (config.format != PCM_FORMAT_INVALID) {
|
||||
printf("Valid format from backend_conf %d\n", config.format);
|
||||
config.bits = get_pcm_bit_width(config.format);
|
||||
}
|
||||
|
||||
header.bits_per_sample = pcm_format_to_bits(format);
|
||||
header.byte_rate = (header.bits_per_sample / 8) * channels * rate;
|
||||
header.block_align = channels * (header.bits_per_sample / 8);
|
||||
header.data_id = ID_DATA;
|
||||
|
||||
/* leave enough room for header */
|
||||
fseek(file, sizeof(struct wav_header), SEEK_SET);
|
||||
|
||||
/* install signal handler and begin capturing */
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGHUP, sigint_handler);
|
||||
signal(SIGTERM, sigint_handler);
|
||||
frames = capture_sample(file, card, device, usb_device, header.num_channels,
|
||||
header.sample_rate, format,
|
||||
period_size, period_count, cap_time, &config,
|
||||
stream_kv, device_kv, instance_kv, devicepp_kv);
|
||||
printf("Captured %u frames\n", frames);
|
||||
|
||||
/* write header now all information is known */
|
||||
header.data_sz = frames * header.block_align;
|
||||
header.riff_sz = header.data_sz + sizeof(header) - 8;
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fwrite(&header, sizeof(struct wav_header), 1, file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
|
||||
unsigned int usb_device, unsigned int channels, unsigned int rate,
|
||||
enum pcm_format format, unsigned int period_size,
|
||||
unsigned int period_count, unsigned int cap_time,
|
||||
struct device_config *dev_config, unsigned int stream_kv,
|
||||
unsigned int device_kv, unsigned int instance_kv, unsigned int devicepp_kv)
|
||||
{
|
||||
struct pcm_config config;
|
||||
struct pcm *pcm;
|
||||
struct mixer *mixer;
|
||||
char *buffer;
|
||||
char *intf_name = dev_config->name;
|
||||
unsigned int size;
|
||||
unsigned int bytes_read = 0;
|
||||
unsigned int frames = 0;
|
||||
struct timespec end;
|
||||
struct timespec now;
|
||||
uint32_t miid = 0;
|
||||
int ret = 0;
|
||||
struct usbAudioConfig cfg;
|
||||
uint8_t* payload = NULL;
|
||||
size_t payloadSize = 0;
|
||||
|
||||
stream_kv = stream_kv ? stream_kv : PCM_RECORD;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.channels = channels;
|
||||
config.rate = rate;
|
||||
config.period_size = period_size;
|
||||
config.period_count = period_count;
|
||||
config.format = format;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
|
||||
if (NULL == intf_name) {
|
||||
printf("No interface name mentioned, Exiting !!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(strcmp(intf_name, "USB_AUDIO-TX") == 0) {
|
||||
dev_config->rate = rate;
|
||||
dev_config->ch = channels;
|
||||
}
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, intf_name, dev_config)) {
|
||||
printf("Failed to set device media config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, intf_name, device_kv, CAPTURE,
|
||||
dev_config->rate, dev_config->bits, stream_kv)) {
|
||||
printf("Failed to set device metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set stream metadata mixer control */
|
||||
if (set_agm_capture_stream_metadata(mixer, device, stream_kv, CAPTURE, STREAM_PCM,
|
||||
instance_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (devicepp_kv != 0) {
|
||||
if (set_agm_streamdevice_metadata(mixer, device, stream_kv, CAPTURE, STREAM_PCM,
|
||||
intf_name, devicepp_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name, STREAM_PCM, TAG_STREAM_MFC, &miid);
|
||||
if (ret) {
|
||||
printf("MFC not present for this graph\n");
|
||||
} else {
|
||||
if (configure_mfc(mixer, device, intf_name, TAG_STREAM_MFC,
|
||||
STREAM_PCM, rate, channels, get_pcm_bit_width(format), miid)) {
|
||||
printf("Failed to configure stream mfc\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(intf_name, "USB_AUDIO-TX") == 0) {
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name, STREAM_PCM, DEVICE_HW_ENDPOINT_TX, &miid);
|
||||
if (ret == 0) {
|
||||
cfg.usb_token = (usb_device << 16)|0x1;
|
||||
cfg.svc_interval = 0;
|
||||
get_agm_usb_audio_config_payload(&payload, &payloadSize, miid, &cfg);
|
||||
|
||||
if (payloadSize) {
|
||||
ret = set_agm_device_custom_payload(mixer, intf_name, payload, payloadSize);
|
||||
} else {
|
||||
ret = -1;
|
||||
printf("set_agm_device_custom_payload failed\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
} else {
|
||||
printf("Failed to get miid for USB_AUDIO-TX\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* connect pcm stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, true)) {
|
||||
printf("Failed to connect pcm to audio interface\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
pcm = pcm_open(card, device, PCM_IN, &config);
|
||||
if (!pcm || !pcm_is_ready(pcm)) {
|
||||
printf("Unable to open PCM device (%s)\n",
|
||||
pcm_get_error(pcm));
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
|
||||
buffer = (char *)malloc(size);
|
||||
if (!buffer) {
|
||||
printf("Unable to allocate %u bytes\n", size);
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
|
||||
pcm_format_to_bits(format));
|
||||
|
||||
if (pcm_start(pcm) < 0) {
|
||||
printf("start error\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
end.tv_sec = now.tv_sec + cap_time;
|
||||
end.tv_nsec = now.tv_nsec;
|
||||
|
||||
while (capturing && !pcm_read(pcm, buffer, size)) {
|
||||
if (fwrite(buffer, 1, size, file) != size) {
|
||||
printf("Error capturing sample\n");
|
||||
break;
|
||||
}
|
||||
bytes_read += size;
|
||||
if (cap_time) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (now.tv_sec > end.tv_sec ||
|
||||
(now.tv_sec == end.tv_sec && now.tv_nsec >= end.tv_nsec))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frames = pcm_bytes_to_frames(pcm, bytes_read);
|
||||
free(buffer);
|
||||
|
||||
pcm_stop(pcm);
|
||||
err_close_pcm:
|
||||
connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, false);
|
||||
pcm_close(pcm);
|
||||
err_close_mixer:
|
||||
if (payload) {
|
||||
free(payload);
|
||||
}
|
||||
mixer_close(mixer);
|
||||
return frames;
|
||||
}
|
234
qcom/opensource/agm/plugins/tinyalsa/test/AgmMixerWrapper.h
Normal file
234
qcom/opensource/agm/plugins/tinyalsa/test/AgmMixerWrapper.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __AGMMIXERWRAPPER_H__
|
||||
#define __AGMMIXERWRAPPER_H__
|
||||
|
||||
#include <iostream>
|
||||
#include "agmmixer.h"
|
||||
|
||||
class AgmMixerWrapper {
|
||||
protected:
|
||||
struct mixer *mixer;
|
||||
struct device_config deviceConfig;
|
||||
struct group_config groupConfig;
|
||||
struct usbAudioConfig usbAudioConfig;
|
||||
|
||||
public:
|
||||
virtual ~AgmMixerWrapper() = default;
|
||||
virtual int mixerOpen(unsigned int card) = 0;
|
||||
virtual int mixerClose(void) = 0;
|
||||
virtual struct device_config getDeviceMediaConfig(char* filename, char *intf_name) = 0;
|
||||
virtual int setDeviceMediaConfig(char *intf_name, struct device_config *config) = 0;
|
||||
virtual int setAudioInterfaceMetadata(char *intf_name, unsigned int dkv,
|
||||
enum usecase_type usecase, int rate, int bitwidth, uint32_t stream_kv) = 0;
|
||||
virtual int setStreamMetadata(int device, uint32_t stream_kv, unsigned int instance_kv) = 0;
|
||||
virtual int setStreamDeviceMetadata(int device, uint32_t stream_kv, char *intf_name,
|
||||
unsigned int devicepp_kv) = 0;
|
||||
virtual int connectAudioInterfaceToStream(unsigned int device, char *intf_name) = 0;
|
||||
virtual int configureMFC(int device, char *intf_name, struct device_config) = 0;
|
||||
virtual struct group_config getGroupConfig(char *intf_name) = 0;
|
||||
virtual int setGroupConfig(unsigned int device, char *intf_name, unsigned int device_kv, struct group_config config, unsigned int channels) = 0;
|
||||
virtual int setDeviceCustomPayload(char *intf_name, int device, unsigned int usb_device) = 0;
|
||||
virtual int disconnectAudioInterfaceToStream(unsigned int device, char *intf_name) = 0;
|
||||
};
|
||||
|
||||
class AgmMixerWrapperImpl: public AgmMixerWrapper {
|
||||
public:
|
||||
int mixerOpen(unsigned int card) override {
|
||||
int ret = 0;
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
std::cout << "Failed to open mixer" << std::endl;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mixerClose(void) override {
|
||||
mixer_close(mixer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct device_config getDeviceMediaConfig(char* filename, char *intf_name) override {
|
||||
if (get_device_media_config(BACKEND_CONF_FILE, intf_name, &deviceConfig)) {
|
||||
std::cout << "Invalid input, entry not found for :" << intf_name << std::endl;
|
||||
}
|
||||
|
||||
if (deviceConfig.format != PCM_FORMAT_INVALID) {
|
||||
deviceConfig.bits = get_pcm_bit_width(deviceConfig.format);
|
||||
}
|
||||
return deviceConfig;
|
||||
}
|
||||
|
||||
int setDeviceMediaConfig(char *intf_name, struct device_config *config) override {
|
||||
int ret = 0;
|
||||
ret = set_agm_device_media_config(mixer, intf_name, config);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set agm device media config " << ret << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int setAudioInterfaceMetadata(char *intf_name, unsigned int dkv,
|
||||
enum usecase_type usecase, int rate, int bitwidth, uint32_t stream_kv) override {
|
||||
int ret = 0;
|
||||
ret = set_agm_audio_intf_metadata(mixer, intf_name, dkv, usecase,
|
||||
rate, bitwidth, stream_kv);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set device metadata " << ret << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int setStreamMetadata(int device, uint32_t stream_kv, unsigned int instance_kv) override {
|
||||
return set_agm_stream_metadata(mixer, device, stream_kv, PLAYBACK, STREAM_PCM, instance_kv);
|
||||
}
|
||||
|
||||
int setStreamDeviceMetadata(int device, uint32_t stream_kv, char *intf_name,
|
||||
unsigned int devicepp_kv) override {
|
||||
int ret = 0;
|
||||
|
||||
if (devicepp_kv == 0) {
|
||||
std::cout << "There is no devicepp keyvector" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = set_agm_streamdevice_metadata(mixer, device, stream_kv, PLAYBACK, STREAM_PCM, intf_name,
|
||||
devicepp_kv);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set streamdevice metadata " << ret << std::endl;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int setDeviceCustomPayload(char *intf_name, int device, unsigned int usb_device) override {
|
||||
int ret = 0;
|
||||
unsigned int miid = 0;
|
||||
struct usbAudioConfig cfg;
|
||||
uint8_t* payload;
|
||||
size_t payloadSize;
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name, STREAM_PCM, DEVICE_HW_ENDPOINT_RX, &miid);
|
||||
if (ret) {
|
||||
std::cout << "Failed to get miid for USB_AUDIO-TX " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
cfg.usb_token = usb_device << 16;
|
||||
cfg.svc_interval = 0;
|
||||
get_agm_usb_audio_config_payload(&payload, &payloadSize, miid, &cfg);
|
||||
|
||||
if (payloadSize) {
|
||||
ret = set_agm_device_custom_payload(mixer, intf_name, payload, payloadSize);
|
||||
} else {
|
||||
ret = -1;
|
||||
std::cout << "set_agm_device_custom_payload failed" << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connectAudioInterfaceToStream(unsigned int device, char *intf_name) override {
|
||||
int ret = 0;
|
||||
ret = connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, true);
|
||||
if (ret) {
|
||||
std::cout << "Failed to connect pcm to audio interface " << ret << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual int configureMFC(int device, char *intf_name, struct device_config config) override {
|
||||
int ret = 0;
|
||||
unsigned int miid = 0;
|
||||
ret = agm_mixer_get_miid(mixer, device, intf_name, STREAM_PCM, PER_STREAM_PER_DEVICE_MFC, &miid);
|
||||
if (ret) {
|
||||
std::cout << "MFC not present for this graph " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = configure_mfc(mixer, device, intf_name, PER_STREAM_PER_DEVICE_MFC,
|
||||
STREAM_PCM, config.rate, config.ch,
|
||||
config.bits, miid);
|
||||
if (ret) {
|
||||
std::cout << "Failed to configure pspd mfc " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct group_config getGroupConfig(char *intf_name) override {
|
||||
if (isVirtualInterface(intf_name)) {
|
||||
if (get_group_device_info(BACKEND_CONF_FILE, intf_name, &groupConfig)) {
|
||||
std::cout << "Failed to get grp device config" << std::endl;
|
||||
}
|
||||
}
|
||||
return groupConfig;
|
||||
}
|
||||
|
||||
int setGroupConfig(unsigned int device, char *intf_name, unsigned int device_kv, struct group_config config, unsigned int channels) override {
|
||||
int ret = 0;
|
||||
if (isVirtualInterface(intf_name)) {
|
||||
ret = set_agm_group_device_config(mixer, intf_name, &config);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set grp device config " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((device_kv == SPEAKER) || (device_kv == HANDSET)) {
|
||||
ret = set_agm_group_mux_config(mixer, device, &config, intf_name, channels);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set grp device config " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int disconnectAudioInterfaceToStream(unsigned int device, char *intf_name) override {
|
||||
int ret = 0;
|
||||
ret = connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, false);
|
||||
if (ret) {
|
||||
std::cout << "Failed to disconnect pcm to audio interface " << ret << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
char* isVirtualInterface(char *intfName) {
|
||||
return strstr(intfName, "VIRT-");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
98
qcom/opensource/agm/plugins/tinyalsa/test/AgmPcmWrapper.h
Normal file
98
qcom/opensource/agm/plugins/tinyalsa/test/AgmPcmWrapper.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __AGMPCMWRAPPER_H__
|
||||
#define __AGMPCMWRAPPER_H__
|
||||
|
||||
#include <iostream>
|
||||
#include "agmmixer.h"
|
||||
|
||||
class AgmPcmWrapper {
|
||||
protected:
|
||||
struct pcm *pcm;
|
||||
|
||||
public:
|
||||
virtual ~AgmPcmWrapper() = default;
|
||||
virtual int pcmOpen(unsigned int card, unsigned int device, struct pcm_config *config) = 0;
|
||||
virtual int pcmFramesToBytes(void) = 0;
|
||||
virtual int pcmStart(void) = 0;
|
||||
virtual int pcmWrite(char *buffer, int num_read) = 0;
|
||||
virtual int pcmStop(void) = 0;
|
||||
virtual int pcmClose(void) = 0;
|
||||
};
|
||||
|
||||
class AgmPcmWrapperImpl: public AgmPcmWrapper {
|
||||
public:
|
||||
int pcmOpen(unsigned int card, unsigned int device, struct pcm_config *config) override {
|
||||
int ret = 0;
|
||||
pcm = pcm_open(card, device, PCM_OUT, config);
|
||||
if (!pcm || !pcm_is_ready(pcm)) {
|
||||
std::cout << "Unable to open PCM device " << device << " (" << pcm_get_error(pcm) << ")" << std::endl;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pcmFramesToBytes(void) override {
|
||||
return pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
|
||||
}
|
||||
|
||||
int pcmStart(void) override {
|
||||
int ret = 0;
|
||||
ret = pcm_start(pcm);
|
||||
if (ret < 0) {
|
||||
std::cout << "start error" << std::endl;
|
||||
pcm_close(pcm);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pcmWrite(char *buffer, int num_read) override {
|
||||
int ret = 0;
|
||||
ret = pcm_write(pcm, buffer, num_read);
|
||||
if (ret < 0) {
|
||||
std::cout << "Error playing sample" << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pcmStop(void) override {
|
||||
return pcm_stop(pcm);
|
||||
}
|
||||
|
||||
int pcmClose(void) override {
|
||||
return pcm_close(pcm);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
76
qcom/opensource/agm/plugins/tinyalsa/test/AgmPlay.cpp
Normal file
76
qcom/opensource/agm/plugins/tinyalsa/test/AgmPlay.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
** Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Copyright 2011, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of The Android Open Source Project nor the names of
|
||||
** its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
** DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "AgmPlayer.h"
|
||||
#include "PlaybackCommandParser.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::ifstream file;
|
||||
HeaderParser* riffWaveParser = new RiffWaveParser();
|
||||
HeaderParser* chunkParser = new ChunkParser();
|
||||
PlaybackCommandParser playbackCommandParser;
|
||||
|
||||
if (argc < 3) {
|
||||
playbackCommandParser.usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
file.open(argv[1], std::ios::binary);
|
||||
if (!file) {
|
||||
std::cout << "Unable to open file" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
riffWaveParser->parseHeader(file);
|
||||
if (!riffWaveParser->isValid()) {
|
||||
std::cout << "It is not a riff/wave file" << std::endl;
|
||||
file.close();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
chunkParser->parseHeader(file);
|
||||
playbackCommandParser.parseCommandLine(argv);
|
||||
|
||||
if (playbackCommandParser.getPlaybackCommand().getInterfaceName() == nullptr) {
|
||||
std::cout << "interface name is NULL" << std::endl;
|
||||
file.close();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
AgmPlayer agmPlayer;
|
||||
agmPlayer.playSample(file, chunkParser->getFormat(), playbackCommandParser.getPlaybackCommand());
|
||||
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
314
qcom/opensource/agm/plugins/tinyalsa/test/AgmPlayer.cpp
Normal file
314
qcom/opensource/agm/plugins/tinyalsa/test/AgmPlayer.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
** Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Copyright 2011, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of The Android Open Source Project nor the names of
|
||||
** its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
** DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "AgmPlayer.h"
|
||||
#include "SignalHandler.h"
|
||||
|
||||
int AgmPlayer::playSample(std::ifstream& file, ChunkFormat format, PlaybackCommand playbackCommand)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
getPlaybackInfo(&playbackCommand);
|
||||
setPlaybackInfo(format);
|
||||
|
||||
ret = openMixer(card);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
allocConfigMemory();
|
||||
ret = setDeviceConfig();
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = setStreamConfig();
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = setDevicePostProcessingConfig();
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = startPlayback(file);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
stopPlayback();
|
||||
|
||||
err:
|
||||
deallocConfigMemory();
|
||||
closeMixer();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AgmPlayer::getPlaybackInfo(PlaybackCommand* playbackCommand)
|
||||
{
|
||||
card = playbackCommand->getCard();
|
||||
device = playbackCommand->getDevice();
|
||||
device_kv = playbackCommand->getDeviceKeyVector();
|
||||
stream_kv = playbackCommand->getStreamKeyVector();
|
||||
instance_kv = playbackCommand->getInstanceKeyVector();
|
||||
devicepp_kv = playbackCommand->getDeviceppKeyVector();
|
||||
haptics = playbackCommand->getHaptics();
|
||||
intf_name = playbackCommand->getInterfaceName();
|
||||
intf_num = playbackCommand->getInterfaceNumber();
|
||||
is_24_LE = playbackCommand->is24LE();
|
||||
usb_device = playbackCommand->getUsbDevice();
|
||||
channels = playbackCommand->getChannel();
|
||||
rate = playbackCommand->getSampleRate();
|
||||
bits = playbackCommand->getBitWidth();
|
||||
}
|
||||
|
||||
void AgmPlayer::setPlaybackInfo(ChunkFormat format)
|
||||
{
|
||||
config.channels = format.num_channels;
|
||||
config.rate = format.sample_rate;
|
||||
|
||||
switch (format.bits_per_sample) {
|
||||
case 32:
|
||||
config.format = is_24_LE? PCM_FORMAT_S24_LE : PCM_FORMAT_S32_LE;
|
||||
break;
|
||||
case 24:
|
||||
config.format = PCM_FORMAT_S24_3LE;
|
||||
break;
|
||||
case 16:
|
||||
config.format = PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
default:
|
||||
std::cout << "Unsupported bit width" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (haptics) {
|
||||
playback_path = HAPTICS;
|
||||
stream_kv = stream_kv ? stream_kv : HAPTICS_PLAYBACK;
|
||||
} else {
|
||||
playback_path = PLAYBACK;
|
||||
stream_kv = stream_kv ? stream_kv : PCM_LL_PLAYBACK;
|
||||
}
|
||||
}
|
||||
|
||||
int AgmPlayer::openMixer(unsigned int card)
|
||||
{
|
||||
return agmMixer->mixerOpen(card);
|
||||
}
|
||||
|
||||
int AgmPlayer::closeMixer(void)
|
||||
{
|
||||
return agmMixer->mixerClose();
|
||||
}
|
||||
|
||||
void AgmPlayer::allocConfigMemory(void)
|
||||
{
|
||||
dev_config = new device_config[intf_num];
|
||||
if (!dev_config) {
|
||||
std::cout << "Failed to allocate memory for dev config" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
grp_config = new group_config[intf_num];
|
||||
if (!grp_config) {
|
||||
std::cout << "Failed to allocate memory for group config" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AgmPlayer::deallocConfigMemory(void)
|
||||
{
|
||||
if (dev_config) {
|
||||
delete[] dev_config;
|
||||
dev_config = nullptr;
|
||||
}
|
||||
|
||||
if (grp_config) {
|
||||
delete[] grp_config;
|
||||
grp_config = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool AgmPlayer::isUSBInterface(int index)
|
||||
{
|
||||
if(intf_name[index] != NULL && strcmp(intf_name[index], "USB_AUDIO-RX") == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AgmPlayer::getDeviceMediaConfig(int index)
|
||||
{
|
||||
if(isUSBInterface(index)) {
|
||||
dev_config[index].rate = rate;
|
||||
dev_config[index].ch = channels;
|
||||
dev_config[index].bits = bits;
|
||||
}
|
||||
else {
|
||||
dev_config[index] = agmMixer->getDeviceMediaConfig(BACKEND_CONF_FILE, intf_name[index]);
|
||||
}
|
||||
}
|
||||
|
||||
int AgmPlayer::setDeviceConfig(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (int index = 0; index < intf_num; index++) {
|
||||
getDeviceMediaConfig(index);
|
||||
|
||||
ret = agmMixer->setDeviceMediaConfig(intf_name[index], &dev_config[index]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = agmMixer->setAudioInterfaceMetadata(intf_name[index], device_kv[index], playback_path,
|
||||
dev_config[index].rate, dev_config[index].bits, stream_kv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AgmPlayer::setStreamConfig(void)
|
||||
{
|
||||
return agmMixer->setStreamMetadata(device, stream_kv, instance_kv);
|
||||
}
|
||||
|
||||
int AgmPlayer::setDevicePostProcessingConfig(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (int index = 0; index < intf_num; index++) {
|
||||
ret = agmMixer->setStreamDeviceMetadata(device, stream_kv, intf_name[index], devicepp_kv[index]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (isUSBInterface(index)) {
|
||||
ret = agmMixer->setDeviceCustomPayload(intf_name[index], device, usb_device);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = agmMixer->connectAudioInterfaceToStream(device, intf_name[index]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = agmMixer->configureMFC(device, intf_name[index], dev_config[index]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
grp_config[index] = agmMixer->getGroupConfig(intf_name[index]);
|
||||
ret = agmMixer->setGroupConfig(device, intf_name[index], device_kv[index], grp_config[index], dev_config[index].ch);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AgmPlayer::startPlayback(std::ifstream& file)
|
||||
{
|
||||
int size = 0;
|
||||
int num_read = 0;
|
||||
int ret = 0;
|
||||
char *buffer;
|
||||
SignalHandler stream;
|
||||
|
||||
ret = agmPcm->pcmOpen(card, device, &config);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
size = agmPcm->pcmFramesToBytes();
|
||||
buffer = new char[size];
|
||||
if (!buffer) {
|
||||
std::cout << "Unable to allocate " << size << " bytes" << std::endl;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = agmPcm->pcmStart();
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
stream.open();
|
||||
do {
|
||||
file.read(buffer, size);
|
||||
num_read = file.gcount();
|
||||
if (num_read > 0) {
|
||||
ret = agmPcm->pcmWrite(buffer, num_read);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} while (!stream.isClosed() && num_read > 0);
|
||||
|
||||
err:
|
||||
if (buffer) {
|
||||
delete[] buffer;
|
||||
buffer = nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AgmPlayer::stopPlayback(void)
|
||||
{
|
||||
agmPcm->pcmStop();
|
||||
for (int index = 0; index < intf_num; index++) {
|
||||
agmMixer->disconnectAudioInterfaceToStream(device, intf_name[index]);
|
||||
}
|
||||
agmPcm->pcmClose();
|
||||
}
|
||||
|
||||
AgmPlayer::AgmPlayer()
|
||||
{
|
||||
agmMixer = new AgmMixerWrapperImpl();
|
||||
agmPcm = new AgmPcmWrapperImpl();
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.period_size = 1024;
|
||||
config.period_count = 4;
|
||||
config.format = PCM_FORMAT_S16_LE;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
};
|
||||
|
||||
AgmPlayer::AgmPlayer(AgmMixerWrapper *agmMixer, AgmPcmWrapper *agmPcm)
|
||||
: agmMixer(agmMixer), agmPcm(agmPcm)
|
||||
{
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.period_size = 1024;
|
||||
config.period_count = 4;
|
||||
config.format = PCM_FORMAT_S16_LE;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
}
|
89
qcom/opensource/agm/plugins/tinyalsa/test/AgmPlayer.h
Normal file
89
qcom/opensource/agm/plugins/tinyalsa/test/AgmPlayer.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __AGMPLAY_H__
|
||||
#define __AGMPLAY_H__
|
||||
|
||||
#include <iostream>
|
||||
#include "ChunkParser.h"
|
||||
#include "RiffWaveParser.h"
|
||||
#include "PlaybackCommand.h"
|
||||
#include "AgmMixerWrapper.h"
|
||||
#include "AgmPcmWrapper.h"
|
||||
|
||||
|
||||
class AgmPlayer {
|
||||
public:
|
||||
AgmPlayer();
|
||||
AgmPlayer(AgmMixerWrapper *agmMixer, AgmPcmWrapper *agmPcm);
|
||||
~AgmPlayer() {};
|
||||
int playSample(std::ifstream& file, ChunkFormat fmt, PlaybackCommand playbackCommand);
|
||||
|
||||
private:
|
||||
unsigned int card;
|
||||
unsigned int device;
|
||||
unsigned int *device_kv;
|
||||
unsigned int stream_kv;
|
||||
unsigned int instance_kv;
|
||||
unsigned int *devicepp_kv;
|
||||
unsigned int usb_device;
|
||||
unsigned int channels;
|
||||
unsigned int rate;
|
||||
unsigned int bits;
|
||||
bool haptics;
|
||||
char **intf_name;
|
||||
int intf_num;
|
||||
bool is_24_LE;
|
||||
struct pcm_config config;
|
||||
struct group_config *grp_config;
|
||||
struct device_config *dev_config;
|
||||
enum usecase_type playback_path;
|
||||
AgmMixerWrapper *agmMixer;
|
||||
AgmPcmWrapper *agmPcm;
|
||||
|
||||
int openMixer(unsigned int card);
|
||||
int closeMixer(void);
|
||||
void getPlaybackInfo(PlaybackCommand* playbackCommand);
|
||||
void setPlaybackInfo(ChunkFormat format);
|
||||
void allocConfigMemory(void);
|
||||
void deallocConfigMemory(void);
|
||||
bool isUSBInterface(int index);
|
||||
void getDeviceMediaConfig(int index);
|
||||
int setDeviceConfig(void);
|
||||
int setStreamConfig(void);
|
||||
int setDevicePostProcessingConfig(void);
|
||||
int startPlayback(std::ifstream& file);
|
||||
void stopPlayback(void);
|
||||
};
|
||||
|
||||
#endif
|
217
qcom/opensource/agm/plugins/tinyalsa/test/Android.mk
Normal file
217
qcom/opensource/agm/plugins/tinyalsa/test/Android.mk
Normal file
@@ -0,0 +1,217 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libagmmixer
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_SRC_FILES := agmmixer.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libexpat
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Build agmplay
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := agmplay
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
LOCAL_CFLAGS += -fexceptions
|
||||
LOCAL_SRC_FILES := AgmPlay.cpp \
|
||||
AgmPlayer.cpp \
|
||||
RiffWaveParser.cpp \
|
||||
ChunkParser.cpp \
|
||||
PlaybackCommand.cpp \
|
||||
PlaybackCommandParser.cpp
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := agmcap
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
LOCAL_SRC_FILES := AgmCap.cpp
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := agmhostless
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
LOCAL_SRC_FILES := agmhostless.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := agmcompressplay
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
|
||||
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
|
||||
LOCAL_SRC_FILES := agmcompressplay.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
# Use flag based selection to use QTI vs open source tinycompress project
|
||||
|
||||
ifeq ($(TARGET_USES_QTI_TINYCOMPRESS),true)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa\
|
||||
libqti-tinycompress
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(TOP)/external/tinycompress/include
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa\
|
||||
libtinycompress
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := agmcompresscap
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
|
||||
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
|
||||
LOCAL_SRC_FILES := agmcompresscap.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
# Use flag based selection to use QTI vs open source tinycompress project
|
||||
|
||||
ifeq ($(TARGET_USES_QTI_TINYCOMPRESS),true)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa\
|
||||
libqti-tinycompress
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(TOP)/external/tinycompress/include
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa\
|
||||
libtinycompress
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := agmvoiceui
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
LOCAL_SRC_FILES := agm_voiceui.c
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
72
qcom/opensource/agm/plugins/tinyalsa/test/ChunkParser.cpp
Normal file
72
qcom/opensource/agm/plugins/tinyalsa/test/ChunkParser.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "ChunkParser.h"
|
||||
|
||||
void ChunkParser::readHeader(std::ifstream& file)
|
||||
{
|
||||
int more_chunks = 1;
|
||||
|
||||
do {
|
||||
file.read((char*)&chunkId, sizeof(chunkId));
|
||||
file.read((char*)&chunkSize, sizeof(chunkSize));
|
||||
|
||||
switch (chunkId) {
|
||||
case ID_FMT:
|
||||
parseChunkFormat(file);
|
||||
break;
|
||||
case ID_DATA:
|
||||
more_chunks = 0;
|
||||
break;
|
||||
default:
|
||||
file.seekg(getChunkSize(), std::ios::cur);
|
||||
}
|
||||
} while (more_chunks);
|
||||
}
|
||||
|
||||
ChunkFormat ChunkParser::getChuckAudioFormat(void)
|
||||
{
|
||||
return chunkFormat;
|
||||
}
|
||||
|
||||
void ChunkParser::parseChunkFormat(std::ifstream& file)
|
||||
{
|
||||
file.read((char*)&chunkFormat, sizeof(chunkFormat));
|
||||
if (getChunkSize() > sizeof(chunkFormat))
|
||||
file.seekg(getChunkSize() - sizeof(chunkFormat), std::ios::cur);
|
||||
}
|
||||
|
||||
uint32_t ChunkParser::getChunkSize(void)
|
||||
{
|
||||
return chunkSize;
|
||||
}
|
58
qcom/opensource/agm/plugins/tinyalsa/test/ChunkParser.h
Normal file
58
qcom/opensource/agm/plugins/tinyalsa/test/ChunkParser.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __CHUNKPARSER_H__
|
||||
#define __CHUNKPARSER_H__
|
||||
|
||||
#include "HeaderParser.h"
|
||||
|
||||
const uint32_t ID_FMT = 0x20746d66;
|
||||
const uint32_t ID_DATA = 0x61746164;
|
||||
|
||||
class ChunkParser : public HeaderParser {
|
||||
private:
|
||||
uint32_t chunkId;
|
||||
uint32_t chunkSize;
|
||||
uint32_t getChunkSize(void);
|
||||
ChunkFormat chunkFormat;
|
||||
void parseChunkFormat(std::ifstream& file);
|
||||
|
||||
public:
|
||||
~ChunkParser() {}
|
||||
|
||||
protected:
|
||||
void readHeader(std::ifstream& file) override;
|
||||
ChunkFormat getChuckAudioFormat(void) override;
|
||||
};
|
||||
|
||||
#endif
|
74
qcom/opensource/agm/plugins/tinyalsa/test/HeaderParser.h
Normal file
74
qcom/opensource/agm/plugins/tinyalsa/test/HeaderParser.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __HEADERPARSER_H__
|
||||
#define __HEADERPARSER_H__
|
||||
|
||||
#include <fstream>
|
||||
|
||||
class ChunkFormat {
|
||||
public:
|
||||
uint16_t audio_format;
|
||||
uint16_t num_channels;
|
||||
uint32_t sample_rate;
|
||||
uint32_t byte_rate;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
};
|
||||
|
||||
class HeaderParser
|
||||
{
|
||||
public:
|
||||
void parseHeader(std::ifstream& file) {
|
||||
readHeader(file);
|
||||
}
|
||||
|
||||
bool isValid(void) {
|
||||
return isValidFile();
|
||||
}
|
||||
|
||||
ChunkFormat getFormat(void) {
|
||||
return getChuckAudioFormat();
|
||||
}
|
||||
|
||||
virtual ~HeaderParser() {}
|
||||
|
||||
protected:
|
||||
ChunkFormat format;
|
||||
|
||||
virtual void readHeader(std::ifstream& file) = 0;
|
||||
virtual bool isValidFile(void) { return true; };
|
||||
virtual ChunkFormat getChuckAudioFormat(void) { return format; };
|
||||
};
|
||||
|
||||
#endif
|
60
qcom/opensource/agm/plugins/tinyalsa/test/Makefile.am
Normal file
60
qcom/opensource/agm/plugins/tinyalsa/test/Makefile.am
Normal file
@@ -0,0 +1,60 @@
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = agmtest.pc
|
||||
EXTRA_DIST = $(pkgconfig_DATA)
|
||||
|
||||
AM_CFLAGS := -Wno-unused-parameter -Wno-unused-result
|
||||
if !BUILDSYSTEM_OPENWRT
|
||||
AM_CFLAGS += -I $(PKG_CONFIG_SYSROOT_DIR)/usr/include/
|
||||
endif
|
||||
AM_CFLAGS += @GLIB_CFLAGS@ -Dstrlcpy=g_strlcpy -Dstrlcat=g_strlcat -include glib.h
|
||||
AM_CFLAGS += @MMHEADERS_CFLAGS@
|
||||
|
||||
AM_CFLAGS += -DBACKEND_CONF_FILE=\"/etc/backend_conf.xml\"
|
||||
|
||||
lib_LTLIBRARIES = libagmmixer.la
|
||||
libagmmixer_la_SOURCES = agmmixer.c
|
||||
libagmmixer_la_CFLAGS := $(AM_CFLAGS)
|
||||
libagmmixer_la_LDFLAGS = -lcutils -ldl -lexpat -ltinyalsa -avoid-version
|
||||
|
||||
bin_PROGRAMS := agmplay
|
||||
agmplay_SOURCES := agmplay.c
|
||||
|
||||
agmplay_la_CFLAGS := $(AM_CFLAGS)
|
||||
agmplay_LDADD := -ltinyalsa libagmmixer.la
|
||||
|
||||
bin_PROGRAMS += agmcap
|
||||
agmcap_SOURCES := agmcap.c
|
||||
|
||||
agmcap_la_CFLAGS := $(AM_CFLAGS)
|
||||
agmcap_LDADD := -ltinyalsa libagmmixer.la
|
||||
|
||||
bin_PROGRAMS += agmhostless
|
||||
agmhostless_SOURCES := agmhostless.c
|
||||
|
||||
agmhostless_la_CFLAGS := $(AM_CFLAGS)
|
||||
agmhostless_LDADD := -ltinyalsa libagmmixer.la
|
||||
|
||||
if !BUILDSYSTEM_OPENWRT
|
||||
bin_PROGRAMS += agmcompressplay
|
||||
agmcompressplay_SOURCES := agmcompressplay.c
|
||||
|
||||
agmcompressplay_la_CFLAGS := $(AM_CFLAGS)
|
||||
agmcompressplay_LDADD := -ltinycompress -ltinyalsa libagmmixer.la
|
||||
|
||||
bin_PROGRAMS += agmcompresscap
|
||||
agmcompresscap_SOURCES := agmcompresscap.c
|
||||
|
||||
agmcompresscap_la_CFLAGS := $(AM_CFLAGS)
|
||||
agmcompresscap_LDADD := -ltinycompress -ltinyalsa libagmmixer.la
|
||||
endif
|
||||
|
||||
bin_PROGRAMS += agmvoiceui
|
||||
agmvoiceui_SOURCES := agm_voiceui.c
|
||||
|
||||
agmvoiceui_la_CFLAGS := $(AM_CFLAGS)
|
||||
agmvoiceui_LDADD := -lpthread -ltinyalsa libagmmixer.la
|
||||
# install xml files under /etc
|
||||
root_etcdir = "/etc"
|
||||
root_etc_SCRIPTS = backend_conf.xml
|
||||
install-data-hook:
|
||||
chmod go-x $(DESTDIR)$(root_etcdir)/backend_conf.xml
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __MOCK_AGMMIXERWRAPPER_H__
|
||||
#define __MOCK_AGMMIXERWRAPPER_H__
|
||||
|
||||
#include "AgmMixerWrapper.h"
|
||||
|
||||
class MockAgmMixerWrapper : public AgmMixerWrapper {
|
||||
public:
|
||||
MOCK_METHOD(int, mixerOpen, (unsigned int card), (override));
|
||||
MOCK_METHOD(int, mixerClose, (), (override));
|
||||
MOCK_METHOD(struct device_config, getDeviceMediaConfig, (char* filename, char *intf_name), (override));
|
||||
MOCK_METHOD(int, setDeviceMediaConfig, (char *intf_name, struct device_config *config), (override));
|
||||
MOCK_METHOD(int, setAudioInterfaceMetadata, (char *intf_name, unsigned int dkv, enum usecase_type usecase, int rate, int bitwidth, uint32_t stream_kv), (override));
|
||||
MOCK_METHOD(int, setStreamMetadata, (int device, uint32_t stream_kv, unsigned int instance_kv), (override));
|
||||
MOCK_METHOD(int, setStreamDeviceMetadata, (int device, uint32_t stream_kv, char *intf_name, unsigned int devicepp_kv), (override));
|
||||
MOCK_METHOD(int, connectAudioInterfaceToStream, (unsigned int device, char *intf_name), (override));
|
||||
MOCK_METHOD(int, configureMFC, (int device, char *intf_name, struct device_config), (override));
|
||||
MOCK_METHOD(struct group_config, getGroupConfig, (char *intf_name), (override));
|
||||
MOCK_METHOD(int, setGroupConfig, (unsigned int device, char *intf_name, unsigned int device_kv, struct group_config config, unsigned int channels), (override));
|
||||
MOCK_METHOD(int, setDeviceCustomPayload, (char *intf_name, int device, unsigned int usb_device), (override));
|
||||
MOCK_METHOD(int, disconnectAudioInterfaceToStream, (unsigned int device, char *intf_name), (override));
|
||||
};
|
||||
|
||||
#endif
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __MOCK_AGMPCMWRAPPER_H__
|
||||
#define __MOCK_AGMPCMWRAPPER_H__
|
||||
|
||||
#include "AgmPcmWrapper.h"
|
||||
|
||||
class MockAgmPcmWrapper : public AgmPcmWrapper {
|
||||
public:
|
||||
MOCK_METHOD(int, pcmOpen, (unsigned int card, unsigned int device, struct pcm_config *config), (override));
|
||||
MOCK_METHOD(int, pcmFramesToBytes, (), (override));
|
||||
MOCK_METHOD(int, pcmStart, (), (override));
|
||||
MOCK_METHOD(int, pcmWrite, (char *buffer, int num_read), (override));
|
||||
MOCK_METHOD(int, pcmStop, (), (override));
|
||||
MOCK_METHOD(int, pcmClose, (), (override));
|
||||
};
|
||||
#endif
|
235
qcom/opensource/agm/plugins/tinyalsa/test/PlaybackCommand.cpp
Normal file
235
qcom/opensource/agm/plugins/tinyalsa/test/PlaybackCommand.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "PlaybackCommand.h"
|
||||
|
||||
void PlaybackCommand::setCard(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setDevice(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setInterfaceNumber(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_num = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setStreamKeyVector(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setInstanceKeyVector(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv) {
|
||||
instance_kv = atoi(*argv);
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCommand::setHaptics(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
haptics = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setInterfaceName(char **argv)
|
||||
{
|
||||
intf_name = (char**) malloc(intf_num * sizeof(char*));
|
||||
if (!intf_name) {
|
||||
std::cout << "insufficient memory" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < intf_num ; i++){
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_name[i] = *argv;
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCommand::set24LE(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv) {
|
||||
is_24_LE = atoi(*argv);
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCommand::setDeviceppKeyVector(char **argv)
|
||||
{
|
||||
devicepp_kv = new unsigned int[intf_num];
|
||||
if (!devicepp_kv) {
|
||||
std::cout << "insufficient memory" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < intf_num ; i++) {
|
||||
devicepp_kv[i] = DEVICEPP_RX_AUDIO_MBDRC;
|
||||
}
|
||||
|
||||
for (int i = 0; i < intf_num ; i++)
|
||||
{
|
||||
argv++;
|
||||
if (*argv) {
|
||||
devicepp_kv[i] = convert_char_to_hex(*argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCommand::setDeviceKeyVector(char **argv)
|
||||
{
|
||||
device_kv = new unsigned int[intf_num];
|
||||
if (!device_kv) {
|
||||
std::cout << "insufficient memory" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < intf_num ; i++) {
|
||||
argv++;
|
||||
if (*argv) {
|
||||
device_kv[i] = convert_char_to_hex(*argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCommand::setChannel(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
channels = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setSampleRate(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
rate = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setBitWidth(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
bits = atoi(*argv);
|
||||
}
|
||||
|
||||
void PlaybackCommand::setUsbDevice(char **argv)
|
||||
{
|
||||
argv++;
|
||||
if (*argv)
|
||||
usb_device = atoi(*argv);
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getCard(void)
|
||||
{
|
||||
return card;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getDevice(void)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
|
||||
int PlaybackCommand::getInterfaceNumber()
|
||||
{
|
||||
return intf_num;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getStreamKeyVector()
|
||||
{
|
||||
return stream_kv;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getInstanceKeyVector()
|
||||
{
|
||||
return instance_kv;
|
||||
}
|
||||
|
||||
bool PlaybackCommand::getHaptics()
|
||||
{
|
||||
return haptics;
|
||||
}
|
||||
|
||||
char **PlaybackCommand::getInterfaceName()
|
||||
{
|
||||
return intf_name;
|
||||
}
|
||||
|
||||
bool PlaybackCommand::is24LE()
|
||||
{
|
||||
return is_24_LE;
|
||||
}
|
||||
|
||||
unsigned int *PlaybackCommand::getDeviceppKeyVector()
|
||||
{
|
||||
return devicepp_kv;
|
||||
}
|
||||
|
||||
unsigned int *PlaybackCommand::getDeviceKeyVector()
|
||||
{
|
||||
return device_kv;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getChannel()
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getSampleRate()
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getBitWidth()
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
|
||||
unsigned int PlaybackCommand::getUsbDevice()
|
||||
{
|
||||
return usb_device;
|
||||
}
|
128
qcom/opensource/agm/plugins/tinyalsa/test/PlaybackCommand.h
Normal file
128
qcom/opensource/agm/plugins/tinyalsa/test/PlaybackCommand.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __PLAYBACKCOMMAND_H__
|
||||
#define __PLAYBACKCOMMAND_H__
|
||||
|
||||
#include "agmmixer.h"
|
||||
|
||||
class PlaybackCommand {
|
||||
private:
|
||||
unsigned int card;
|
||||
unsigned int device;
|
||||
int intf_num;
|
||||
unsigned int stream_kv;
|
||||
unsigned int instance_kv;
|
||||
unsigned int *devicepp_kv;
|
||||
unsigned int *device_kv;
|
||||
unsigned int usb_device;
|
||||
unsigned int channels;
|
||||
unsigned int rate;
|
||||
unsigned int bits;
|
||||
char **intf_name;
|
||||
bool haptics;
|
||||
bool is_24_LE;
|
||||
|
||||
public:
|
||||
PlaybackCommand()
|
||||
: card(100),
|
||||
device(100),
|
||||
intf_num(1),
|
||||
stream_kv(0),
|
||||
instance_kv(INSTANCE_1),
|
||||
haptics(false),
|
||||
intf_name(nullptr),
|
||||
is_24_LE(false),
|
||||
devicepp_kv(nullptr),
|
||||
device_kv(nullptr),
|
||||
usb_device(1),
|
||||
channels(2),
|
||||
rate(48000),
|
||||
bits(16)
|
||||
{
|
||||
devicepp_kv = new unsigned int[intf_num];
|
||||
device_kv = new unsigned int[intf_num];
|
||||
|
||||
if (!device_kv || !devicepp_kv) {
|
||||
std::cout << " insufficient memory" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
device_kv[0] = SPEAKER;
|
||||
devicepp_kv[0] = DEVICEPP_RX_AUDIO_MBDRC;
|
||||
}
|
||||
|
||||
~PlaybackCommand()
|
||||
{
|
||||
if (!devicepp_kv) {
|
||||
delete[] devicepp_kv;
|
||||
devicepp_kv = nullptr;
|
||||
}
|
||||
if (!device_kv) {
|
||||
delete[] device_kv;
|
||||
device_kv = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setCard(char **argv);
|
||||
void setDevice(char **argv);
|
||||
void setInterfaceNumber(char **argv);
|
||||
void setStreamKeyVector(char **argv);
|
||||
void setInstanceKeyVector(char **argv);
|
||||
void setHaptics(char **argv);
|
||||
void setInterfaceName(char **argv);
|
||||
void set24LE(char **argv);
|
||||
void setDeviceKeyVector(char **argv);
|
||||
void setDeviceppKeyVector(char **argv);
|
||||
void setChannel(char **argv);
|
||||
void setSampleRate(char **argv);
|
||||
void setBitWidth(char **argv);
|
||||
void setUsbDevice(char **argv);
|
||||
|
||||
unsigned int getCard();
|
||||
unsigned int getDevice();
|
||||
int getInterfaceNumber();
|
||||
unsigned int getStreamKeyVector();
|
||||
unsigned int getInstanceKeyVector();
|
||||
bool getHaptics();
|
||||
char **getInterfaceName();
|
||||
bool is24LE();
|
||||
unsigned int *getDeviceKeyVector();
|
||||
unsigned int *getDeviceppKeyVector();
|
||||
unsigned int getChannel();
|
||||
unsigned int getSampleRate();
|
||||
unsigned int getBitWidth();
|
||||
unsigned int getUsbDevice();
|
||||
};
|
||||
|
||||
#endif
|
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "PlaybackCommandParser.h"
|
||||
|
||||
void PlaybackCommandParser::parseCommandLine(char **argv)
|
||||
{
|
||||
argv += 2;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
playbackCommand.setDevice(argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
playbackCommand.setCard(argv);
|
||||
} else if (strcmp(*argv, "-num_intf") == 0) {
|
||||
playbackCommand.setInterfaceNumber(argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
playbackCommand.setInterfaceName(argv);
|
||||
} else if (strcmp(*argv, "-h") == 0) {
|
||||
playbackCommand.setHaptics(argv);
|
||||
} else if (strcmp(*argv, "-dkv") == 0) {
|
||||
playbackCommand.setDeviceKeyVector(argv);
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
playbackCommand.setStreamKeyVector(argv);
|
||||
} else if (strcmp(*argv, "-ikv") == 0) {
|
||||
playbackCommand.setInstanceKeyVector(argv);
|
||||
} else if (strcmp(*argv, "-dppkv") == 0) {
|
||||
playbackCommand.setDeviceppKeyVector(argv);
|
||||
} else if (strcmp(*argv, "-is_24_LE") == 0) {
|
||||
playbackCommand.set24LE(argv);
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
playbackCommand.setChannel(argv);
|
||||
} else if (strcmp(*argv, "-r") == 0) {
|
||||
playbackCommand.setSampleRate(argv);
|
||||
} else if (strcmp(*argv, "-b") == 0) {
|
||||
playbackCommand.setBitWidth(argv);
|
||||
} else if (strcmp(*argv, "-usb_d") == 0) {
|
||||
playbackCommand.setUsbDevice(argv);
|
||||
} else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackCommand& PlaybackCommandParser::getPlaybackCommand() {
|
||||
return playbackCommand;
|
||||
}
|
||||
|
||||
void PlaybackCommandParser::usage(void)
|
||||
{
|
||||
std::cout << "Usage: %s file.wav [-help print usage] [-D card] [-d device]" << std::endl;
|
||||
std::cout << "[-c channels] [-r rate] [-b bits]" << std::endl;
|
||||
std::cout << " [-num_intf num of interfaces followed by interface name]" << std::endl;
|
||||
std::cout << " [-i intf_name] : Can be multiple if num_intf is more than 1" << std::endl;
|
||||
std::cout << " [-dkv device_kv] : Can be multiple if num_intf is more than 1" << std::endl;
|
||||
std::cout << " [-dppkv deviceppkv] : Assign 0 if no device pp in the graph" << std::endl;
|
||||
std::cout << " [-ikv instance_kv] : Assign 0 if no instance kv in the graph" << std::endl;
|
||||
std::cout << " [-skv stream_kv] [-h haptics usecase]" << std::endl;
|
||||
std::cout << " [is_24_LE] : [0-1] Only to be used if user wants to play S24_LE clip" << std::endl;
|
||||
std::cout << " [-usb_d usb device]" << std::endl;
|
||||
std::cout << " 0: If clip bps is 32, and format is S32_LE" << std::endl;
|
||||
std::cout << " 1: If clip bps is 24, and format is S24_LE" << std::endl;
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __PLAYBACKCOMMANDPARSER_H__
|
||||
#define __PLAYBACKCOMMANDPARSER_H__
|
||||
|
||||
#include <iostream>
|
||||
#include "PlaybackCommand.h"
|
||||
|
||||
class PlaybackCommandParser {
|
||||
private:
|
||||
PlaybackCommand playbackCommand;
|
||||
|
||||
public:
|
||||
~PlaybackCommandParser() {};
|
||||
void parseCommandLine(char **argv);
|
||||
PlaybackCommand& getPlaybackCommand();
|
||||
void usage(void);
|
||||
};
|
||||
|
||||
#endif
|
1
qcom/opensource/agm/plugins/tinyalsa/test/README.md
Normal file
1
qcom/opensource/agm/plugins/tinyalsa/test/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# tinyalsa_agmtest
|
49
qcom/opensource/agm/plugins/tinyalsa/test/RiffWaveParser.cpp
Normal file
49
qcom/opensource/agm/plugins/tinyalsa/test/RiffWaveParser.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include "RiffWaveParser.h"
|
||||
|
||||
void RiffWaveParser::readHeader(std::ifstream& file)
|
||||
{
|
||||
file.read((char*)&riffId, sizeof(riffId));
|
||||
file.read((char*)&riffSize, sizeof(riffSize));
|
||||
file.read((char*)&waveId, sizeof(waveId));
|
||||
}
|
||||
|
||||
bool RiffWaveParser::isValidFile(void)
|
||||
{
|
||||
if ((riffId != ID_RIFF) || (waveId != ID_WAVE)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
56
qcom/opensource/agm/plugins/tinyalsa/test/RiffWaveParser.h
Normal file
56
qcom/opensource/agm/plugins/tinyalsa/test/RiffWaveParser.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __RIFFWAVEPARSER_H__
|
||||
#define __RIFFWAVEPARSER_H__
|
||||
|
||||
#include "HeaderParser.h"
|
||||
|
||||
const uint32_t ID_RIFF = 0x46464952;
|
||||
const uint32_t ID_WAVE = 0x45564157;
|
||||
|
||||
class RiffWaveParser : public HeaderParser {
|
||||
private:
|
||||
uint32_t riffId;
|
||||
uint32_t riffSize;
|
||||
uint32_t waveId;
|
||||
|
||||
public:
|
||||
~RiffWaveParser() {}
|
||||
|
||||
protected:
|
||||
void readHeader(std::ifstream& file) override;
|
||||
bool isValidFile(void) override;
|
||||
};
|
||||
|
||||
#endif
|
72
qcom/opensource/agm/plugins/tinyalsa/test/SignalHandler.h
Normal file
72
qcom/opensource/agm/plugins/tinyalsa/test/SignalHandler.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __SIGNALHANDLER_H__
|
||||
#define __SIGNALHANDLER_H__
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
class SignalHandler {
|
||||
public:
|
||||
SignalHandler() : closed(false) {}
|
||||
|
||||
void open() {
|
||||
signal(SIGINT, SignalHandler::signalHandler);
|
||||
}
|
||||
|
||||
void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
bool isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
void Handler(int sig) {
|
||||
signal(sig, SIG_IGN);
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool closed;
|
||||
static SignalHandler instance;
|
||||
|
||||
static void signalHandler(int sig) {
|
||||
instance.Handler(sig);
|
||||
}
|
||||
};
|
||||
|
||||
SignalHandler SignalHandler::instance;
|
||||
|
||||
#endif
|
476
qcom/opensource/agm/plugins/tinyalsa/test/agm_voiceui.c
Normal file
476
qcom/opensource/agm/plugins/tinyalsa/test/agm_voiceui.c
Normal file
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
** Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
#include <sound/asound.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <agm/agm_api.h>
|
||||
#include "agmmixer.h"
|
||||
|
||||
static pthread_t event_thread;
|
||||
static int done = 0;
|
||||
|
||||
char *audio_interface_name[] = {
|
||||
"CODEC_DMA-LPAIF_VA-TX-0",
|
||||
"CODEC_DMA-LPAIF_VA-TX-1",
|
||||
"CODEC_DMA-LPAIF_RXTX-TX-3",
|
||||
"MI2S-LPAIF_AXI-TX-PRIMARY",
|
||||
"TDM-LPAIF_AXI-TX-PRIMARY",
|
||||
"AUXPCM-LPAIF_AXI-TX-PRIMARY",
|
||||
};
|
||||
|
||||
char *ec_aif_name[] = {
|
||||
"CODEC_DMA-LPAIF_WSA-RX-0",
|
||||
"CODEC_DMA-LPAIF_WSA-RX-1",
|
||||
"MI2S-LPAIF_AXI-RX-PRIMARY",
|
||||
"TDM-LPAIF_AXI-RX-PRIMARY",
|
||||
"AUXPCM-LPAIF_AXI-RX-PRIMARY",
|
||||
};
|
||||
|
||||
static void read_event_data(struct mixer *mixer, char *mixer_str)
|
||||
{
|
||||
struct mixer_ctl *ctl;
|
||||
char *buf = NULL;
|
||||
unsigned int num_values;
|
||||
int i, ret;
|
||||
struct agm_event_cb_params *params;
|
||||
|
||||
ctl = mixer_get_ctl_by_name(mixer, mixer_str);
|
||||
num_values = mixer_ctl_get_num_values(ctl);
|
||||
printf("%s - %d\n", __func__, num_values);
|
||||
buf = calloc(1, num_values);
|
||||
if (!buf) {
|
||||
printf("Failed to allocate memory for buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = mixer_ctl_get_array(ctl, buf, num_values);
|
||||
if (ret < 0) {
|
||||
printf("Failed to mixer_ctl_get_array\n");
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
params = (struct agm_event_cb_params *)buf;
|
||||
printf("%s params.source_module_id %x\n", __func__, params->source_module_id);
|
||||
printf("%s params.event_id %d\n", __func__, params->event_id);
|
||||
printf("%s params.event_payload_size %x\n", __func__, params->event_payload_size);
|
||||
}
|
||||
|
||||
static void event_wait_thread_loop(void *context)
|
||||
{
|
||||
struct mixer *mixer = (struct mixer *)context;
|
||||
int ret = 0;
|
||||
struct ctl_event mixer_event = {0};
|
||||
|
||||
printf("subscribing for event\n");
|
||||
mixer_subscribe_events(mixer, 1);
|
||||
|
||||
printf("going to wait for event\n");
|
||||
ret = mixer_wait_event(mixer, 30000);
|
||||
if (ret < 0) {
|
||||
printf("%s: mixer_wait_event err!, ret = %d\n", __func__, ret);
|
||||
} else if (ret > 0) {
|
||||
ret = mixer_read_event(mixer, &mixer_event);
|
||||
if (ret >= 0) {
|
||||
printf("Event Received %s\n", mixer_event.data.elem.id.name);
|
||||
read_event_data(mixer, mixer_event.data.elem.id.name);
|
||||
} else {
|
||||
printf("%s: mixer_read failed, ret = %d\n", __func__, ret);
|
||||
}
|
||||
done = 1;
|
||||
}
|
||||
|
||||
mixer_subscribe_events(mixer, 0);
|
||||
}
|
||||
|
||||
static void record_lab_buffer(struct pcm *pcm, unsigned int cap_time)
|
||||
{
|
||||
struct timespec end;
|
||||
struct timespec now;
|
||||
unsigned int size;
|
||||
char *buffer;
|
||||
FILE *file;
|
||||
int ret;
|
||||
|
||||
ret = pthread_join(event_thread, (void **) NULL);
|
||||
if (ret < 0) {
|
||||
printf("%s: Unable to join event thread\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
return;
|
||||
|
||||
file = fopen("/data/voice_rec.wav", "wb");
|
||||
if (!file) {
|
||||
printf("Unable to create voice_rec file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
|
||||
buffer = malloc(size);
|
||||
if (!buffer) {
|
||||
printf("Unable to allocate %u bytes\n", size);
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
end.tv_sec = now.tv_sec + cap_time;
|
||||
end.tv_nsec = now.tv_nsec;
|
||||
|
||||
while (!pcm_read(pcm, buffer, size)) {
|
||||
if (fwrite(buffer, 1, size, file) != size) {
|
||||
printf("Error capturing sample\n");
|
||||
break;
|
||||
}
|
||||
if (cap_time) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (now.tv_sec > end.tv_sec ||
|
||||
(now.tv_sec == end.tv_sec && now.tv_nsec >= end.tv_nsec))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
static int get_file_size(char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
int size = 0;
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
printf("%s: Unable to open file '%s'\n", __func__, filename);
|
||||
return 0;
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
printf("%s - sizeof %s is %d\n", __func__, filename, size);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fclose(fp);
|
||||
return size;
|
||||
}
|
||||
|
||||
static void fill_payload(char *filename, int size, void *payload)
|
||||
{
|
||||
FILE *fp;
|
||||
int bytes_read;
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
printf("%s: Unable to open file '%s'\n", __func__, filename);
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_read = fread((char*)payload, 1, size , fp);
|
||||
if (bytes_read != size) {
|
||||
printf("%s failed to read data from file %s, bytes read = %d\n", __func__, filename, bytes_read);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void* merge_payload(uint32_t miid, int num, int *sum, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int i = 0, total_size = 0, offset = 0;
|
||||
int *size = calloc(num, sizeof(int));
|
||||
char **temp = calloc(num, sizeof(char *));
|
||||
void *payload = NULL;
|
||||
uint8_t *buf;
|
||||
uint32_t *module_instance_id = NULL;
|
||||
|
||||
if (!size || !temp) {
|
||||
printf("Failed to allocate memory for size and temp\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(valist, num);
|
||||
for (i = 0; i < num; i++) {
|
||||
temp[i] = va_arg(valist, char *);
|
||||
size[i] = get_file_size(temp[i]);
|
||||
total_size += size[i];
|
||||
}
|
||||
va_end(valist);
|
||||
|
||||
payload = calloc(1, total_size);
|
||||
if (!payload)
|
||||
return NULL;
|
||||
|
||||
buf = payload;
|
||||
for (i = 0; i < num; i++) {
|
||||
fill_payload(temp[i], size[i], buf);
|
||||
// Update SVA miid
|
||||
module_instance_id = (uint32_t *)buf;
|
||||
*module_instance_id = miid;
|
||||
buf += size[i];
|
||||
}
|
||||
*sum = total_size;
|
||||
/* TODO : free memory */
|
||||
return payload;
|
||||
}
|
||||
|
||||
void voice_ui_test(unsigned int card, unsigned int device, unsigned int audio_intf, unsigned int cap_time, int ec_aif,
|
||||
unsigned int device_kv, unsigned int stream_kv, unsigned int instance_kv, unsigned int devicepp_kv)
|
||||
{
|
||||
struct mixer *mixer;
|
||||
char *intf_name = audio_interface_name[audio_intf];
|
||||
char *ec_intf_name = NULL;
|
||||
struct pcm_config config;
|
||||
struct pcm *pcm;
|
||||
struct device_config dev_config;
|
||||
int ret = 0;
|
||||
enum pcm_format format = PCM_FORMAT_S16_LE;
|
||||
uint32_t miid = 0, param_size = 0;
|
||||
void *param_buf = NULL;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.channels = 2;
|
||||
config.rate = 48000;
|
||||
config.period_size = 1024;
|
||||
config.period_count = 4;
|
||||
config.format = format;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
stream_kv = stream_kv ? stream_kv : VOICE_UI;
|
||||
|
||||
dev_config.rate = config.rate;
|
||||
dev_config.ch = config.channels;
|
||||
dev_config.bits = get_pcm_bit_width(config.format);
|
||||
dev_config.format = config.format;
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, intf_name, &dev_config)) {
|
||||
printf("Failed to set device media config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, intf_name, 0, CAPTURE, config.rate,
|
||||
pcm_format_to_bits(format), stream_kv)) {
|
||||
printf("Failed to set device metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set stream metadata mixer control */
|
||||
if (set_agm_stream_metadata(mixer, device, stream_kv, CAPTURE, STREAM_PCM,
|
||||
instance_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (devicepp_kv != 0) {
|
||||
if (set_agm_streamdevice_metadata(mixer, device, stream_kv, CAPTURE, STREAM_PCM,
|
||||
intf_name, devicepp_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
/* connect pcm stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, true)) {
|
||||
printf("Failed to connect pcm to audio interface\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
ret = agm_mixer_get_miid(mixer, device, intf_name, STREAM_PCM, DEVICE_SVA, &miid);
|
||||
if (ret) {
|
||||
printf("%s Get MIID from tag data failed\n", __func__);
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
param_buf = merge_payload(miid, 3, ¶m_size, "/vendor/etc/sound_model",
|
||||
"/vendor/etc/wakeup_config", "/vendor/etc/buffer_config");
|
||||
|
||||
if (agm_mixer_set_param(mixer, device, STREAM_PCM, param_buf, param_size)) {
|
||||
printf("setparam failed\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
pcm = pcm_open(card, device, PCM_IN, &config);
|
||||
if (!pcm || !pcm_is_ready(pcm)) {
|
||||
printf("Unable to open PCM device (%s)\n",
|
||||
pcm_get_error(pcm));
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Load Sound Model */
|
||||
if (agm_mixer_set_param_with_file(mixer, device, STREAM_PCM, "/etc/sound_model")) {
|
||||
printf("soundmodel load failed\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
/* Register voice wakeup config */
|
||||
if (agm_mixer_set_param_with_file(mixer, device, STREAM_PCM, "/etc/wakeup_config")) {
|
||||
printf("wakeup config registration failed\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
#endif
|
||||
// Call API to register event with GSL here
|
||||
// Same as GSL_CMD_REGISTER_CUSTOM_EVENT
|
||||
if (agm_mixer_register_event(mixer, device, STREAM_PCM, miid, 1)) {
|
||||
printf("GSL event registration failed\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Register buffer config */
|
||||
if (agm_mixer_set_param_with_file(mixer, device, STREAM_PCM, "/etc/buffer_config")) {
|
||||
printf("buffer config registration failed\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
#endif
|
||||
/* Setup EC ref path */
|
||||
if (ec_aif != -1) {
|
||||
if (agm_mixer_set_ecref_path(mixer, device, STREAM_PCM, ec_aif_name[ec_aif])) {
|
||||
printf("EC ref path failed\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcm_start(pcm) < 0) { // This internally calls pcm_prepare too.
|
||||
printf("start error\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
pthread_create(&event_thread,
|
||||
(const pthread_attr_t *) NULL, event_wait_thread_loop, mixer);
|
||||
|
||||
record_lab_buffer(pcm, cap_time);
|
||||
|
||||
/* Reset Engine */
|
||||
if (agm_mixer_set_param_with_file(mixer, device, STREAM_PCM, "/vendor/etc/engine_reset")) {
|
||||
printf("stream setup duration configuration failed\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
err_close_pcm:
|
||||
if (ec_aif != -1)
|
||||
agm_mixer_set_ecref_path(mixer, device, STREAM_PCM, "ZERO");
|
||||
pcm_close(pcm);
|
||||
err_close_mixer:
|
||||
mixer_close(mixer);
|
||||
printf("completed event test\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int device = 100;
|
||||
unsigned int card = 0;
|
||||
unsigned int audio_intf = 0;
|
||||
int ec_aif = -1;
|
||||
unsigned int cap_time = 5;
|
||||
unsigned int device_kv = 0;
|
||||
unsigned int devicepp_kv = DEVICEPP_TX_FLUENCE_FFECNS;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int instance_kv = INSTANCE_1;
|
||||
|
||||
argv += 1;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
}
|
||||
if (*argv && strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
}
|
||||
if (*argv && strcmp(*argv, "-i") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
audio_intf = atoi(*argv);
|
||||
if (audio_intf >= sizeof(audio_interface_name)/sizeof(char *)) {
|
||||
printf("Invalid audio interface index denoted by -i\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (*argv && strcmp(*argv, "-e") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
ec_aif = atoi(*argv);
|
||||
if (ec_aif >= sizeof(ec_aif_name)/sizeof(char *)) {
|
||||
printf("Invalid echoref audio interface index denoted by -i\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (*argv && strcmp(*argv, "-T") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
cap_time = atoi(*argv);
|
||||
} else if (*argv && strcmp(*argv, "-dkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device_kv = convert_char_to_hex(*argv);
|
||||
} else if (*argv && strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (*argv && strcmp(*argv, "-ikv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
instance_kv = atoi(*argv);
|
||||
} else if (*argv && strcmp(*argv, "-dppkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
devicepp_kv = convert_char_to_hex(*argv);
|
||||
}
|
||||
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
voice_ui_test(card, device, audio_intf, cap_time, ec_aif, device_kv, stream_kv,
|
||||
instance_kv, devicepp_kv);
|
||||
return 0;
|
||||
}
|
445
qcom/opensource/agm/plugins/tinyalsa/test/agmcap.c
Normal file
445
qcom/opensource/agm/plugins/tinyalsa/test/agmcap.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
** Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Copyright 2011, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of The Android Open Source Project nor the names of
|
||||
** its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
** DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center, Inc. are provided under the following license:
|
||||
** Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "agmmixer.h"
|
||||
|
||||
#define ID_RIFF 0x46464952
|
||||
#define ID_WAVE 0x45564157
|
||||
#define ID_FMT 0x20746d66
|
||||
#define ID_DATA 0x61746164
|
||||
|
||||
#define FORMAT_PCM 1
|
||||
|
||||
struct wav_header {
|
||||
uint32_t riff_id;
|
||||
uint32_t riff_sz;
|
||||
uint32_t riff_fmt;
|
||||
uint32_t fmt_id;
|
||||
uint32_t fmt_sz;
|
||||
uint16_t audio_format;
|
||||
uint16_t num_channels;
|
||||
uint32_t sample_rate;
|
||||
uint32_t byte_rate;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
uint32_t data_id;
|
||||
uint32_t data_sz;
|
||||
};
|
||||
|
||||
int capturing = 1;
|
||||
|
||||
static unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
|
||||
unsigned int usb_device, unsigned int channels, unsigned int rate,
|
||||
unsigned int bits, enum pcm_format format, unsigned int period_size,
|
||||
unsigned int period_count, unsigned int cap_time,
|
||||
struct device_config *dev_config, unsigned int stream_kv,
|
||||
unsigned int device_kv, unsigned int instance_kv,
|
||||
unsigned int devicepp_kv);
|
||||
|
||||
static void sigint_handler(int sig)
|
||||
{
|
||||
capturing = 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf(" Usage: %s file.wav [-help print usage] [-D card] [-d device]\n"
|
||||
" [-c channels] [-r rate] [-b bits] [-p period_size]\n"
|
||||
" [-n n_periods] [-T capture time] [-i intf_name] [-dkv device_kv]\n"
|
||||
" [-dppkv deviceppkv] : Assign 0 if no device pp in the graph\n"
|
||||
" [-ikv instance_kv] : Assign 0 if no instance kv in the graph\n"
|
||||
" [-skv stream_kv]\n"
|
||||
" [-is_24_LE] : [0-1] Only to be used if user wants to record 32 bps clip\n"
|
||||
" [-usb_d usb device]\n"
|
||||
" 0: If bps is 32, and format should be S32_LE\n"
|
||||
" 1: If bps is 24, and format should be S24_LE\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *file;
|
||||
struct wav_header header;
|
||||
unsigned int card = 100;
|
||||
unsigned int device = 101;
|
||||
unsigned int usb_device = 1;
|
||||
unsigned int channels = 2;
|
||||
unsigned int rate = 44100;
|
||||
unsigned int bits = 16;
|
||||
unsigned int frames;
|
||||
unsigned int period_size = 1024;
|
||||
unsigned int period_count = 4;
|
||||
unsigned int cap_time = 0;
|
||||
char *intf_name = NULL;
|
||||
unsigned int device_kv = 0;
|
||||
struct device_config config;
|
||||
enum pcm_format format;
|
||||
int ret = 0;
|
||||
unsigned int devicepp_kv = 0;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int instance_kv = INSTANCE_1;
|
||||
bool is_24_LE = false;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
file = fopen(argv[1], "wb");
|
||||
if (!file) {
|
||||
printf("Unable to create file '%s'\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse command line arguments */
|
||||
argv += 2;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
channels = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-r") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
rate = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-b") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
bits = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-p") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
period_size = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-n") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
period_count = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-T") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
cap_time = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_name = *argv;
|
||||
} else if (strcmp(*argv, "-dkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-ikv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
instance_kv = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-dppkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
devicepp_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-is_24_LE") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
is_24_LE = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-usb_d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
usb_device = atoi(*argv);
|
||||
}else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
header.riff_id = ID_RIFF;
|
||||
header.riff_sz = 0;
|
||||
header.riff_fmt = ID_WAVE;
|
||||
header.fmt_id = ID_FMT;
|
||||
header.fmt_sz = 16;
|
||||
header.audio_format = FORMAT_PCM;
|
||||
header.num_channels = channels;
|
||||
header.sample_rate = rate;
|
||||
|
||||
switch (bits) {
|
||||
case 32:
|
||||
if (is_24_LE)
|
||||
format = PCM_FORMAT_S24_LE;
|
||||
else
|
||||
format = PCM_FORMAT_S32_LE;
|
||||
break;
|
||||
case 24:
|
||||
format = PCM_FORMAT_S24_3LE;
|
||||
break;
|
||||
case 16:
|
||||
format = PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
default:
|
||||
printf("%u bits is not supported.\n", bits);
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (intf_name == NULL)
|
||||
return 1;
|
||||
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, intf_name, &config);
|
||||
if (ret) {
|
||||
printf("Invalid input, entry not found for %s\n", intf_name);
|
||||
fclose(file);
|
||||
return ret;
|
||||
}
|
||||
if (config.format != PCM_FORMAT_INVALID) {
|
||||
printf("Valid format from backend_conf %d\n", config.format);
|
||||
config.bits = get_pcm_bit_width(config.format);
|
||||
}
|
||||
|
||||
header.bits_per_sample = pcm_format_to_bits(format);
|
||||
header.byte_rate = (header.bits_per_sample / 8) * channels * rate;
|
||||
header.block_align = channels * (header.bits_per_sample / 8);
|
||||
header.data_id = ID_DATA;
|
||||
|
||||
/* leave enough room for header */
|
||||
fseek(file, sizeof(struct wav_header), SEEK_SET);
|
||||
|
||||
/* install signal handler and begin capturing */
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGHUP, sigint_handler);
|
||||
signal(SIGTERM, sigint_handler);
|
||||
frames = capture_sample(file, card, device, usb_device, header.num_channels,
|
||||
header.sample_rate, bits, format,
|
||||
period_size, period_count, cap_time, &config,
|
||||
stream_kv, device_kv, instance_kv, devicepp_kv);
|
||||
printf("Captured %u frames\n", frames);
|
||||
|
||||
/* write header now all information is known */
|
||||
header.data_sz = frames * header.block_align;
|
||||
header.riff_sz = header.data_sz + sizeof(header) - 8;
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fwrite(&header, sizeof(struct wav_header), 1, file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
|
||||
unsigned int usb_device, unsigned int channels, unsigned int rate,
|
||||
unsigned int bits, enum pcm_format format, unsigned int period_size,
|
||||
unsigned int period_count, unsigned int cap_time,
|
||||
struct device_config *dev_config, unsigned int stream_kv,
|
||||
unsigned int device_kv, unsigned int instance_kv, unsigned int devicepp_kv)
|
||||
{
|
||||
struct pcm_config config;
|
||||
struct pcm *pcm;
|
||||
struct mixer *mixer;
|
||||
char *buffer;
|
||||
char *intf_name = dev_config->name;
|
||||
unsigned int size;
|
||||
unsigned int bytes_read = 0;
|
||||
unsigned int frames = 0;
|
||||
struct timespec end;
|
||||
struct timespec now;
|
||||
uint32_t miid = 0;
|
||||
int ret = 0;
|
||||
struct usbAudioConfig cfg;
|
||||
uint8_t* payload = NULL;
|
||||
size_t payloadSize = 0;
|
||||
|
||||
stream_kv = stream_kv ? stream_kv : PCM_RECORD;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.channels = channels;
|
||||
config.rate = rate;
|
||||
config.period_size = period_size;
|
||||
config.period_count = period_count;
|
||||
config.format = format;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
|
||||
if (NULL == intf_name) {
|
||||
printf("No interface name mentioned, Exiting !!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(strcmp(intf_name, "USB_AUDIO-TX") == 0) {
|
||||
dev_config->rate = rate;
|
||||
dev_config->ch = channels;
|
||||
dev_config->bits = bits;
|
||||
dev_config->format = PCM_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, intf_name, dev_config)) {
|
||||
printf("Failed to set device media config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, intf_name, device_kv, CAPTURE,
|
||||
dev_config->rate, dev_config->bits, stream_kv)) {
|
||||
printf("Failed to set device metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set stream metadata mixer control */
|
||||
if (set_agm_capture_stream_metadata(mixer, device, stream_kv, CAPTURE, STREAM_PCM,
|
||||
instance_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (devicepp_kv != 0) {
|
||||
if (set_agm_streamdevice_metadata(mixer, device, stream_kv, CAPTURE, STREAM_PCM,
|
||||
intf_name, devicepp_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name, STREAM_PCM, TAG_STREAM_MFC, &miid);
|
||||
if (ret) {
|
||||
printf("MFC not present for this graph\n");
|
||||
} else {
|
||||
if (configure_mfc(mixer, device, intf_name, TAG_STREAM_MFC,
|
||||
STREAM_PCM, rate, channels, get_pcm_bit_width(format), miid)) {
|
||||
printf("Failed to configure stream mfc\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(intf_name, "USB_AUDIO-TX") == 0) {
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name, STREAM_PCM, DEVICE_HW_ENDPOINT_TX, &miid);
|
||||
if (ret == 0) {
|
||||
cfg.usb_token = (usb_device << 16)|0x1;
|
||||
cfg.svc_interval = 0;
|
||||
get_agm_usb_audio_config_payload(&payload, &payloadSize, miid, &cfg);
|
||||
|
||||
if (payloadSize) {
|
||||
ret = set_agm_device_custom_payload(mixer, intf_name, payload, payloadSize);
|
||||
} else {
|
||||
ret = -1;
|
||||
printf("set_agm_device_custom_payload failed\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
} else {
|
||||
printf("Failed to get miid for USB_AUDIO-TX\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* connect pcm stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, true)) {
|
||||
printf("Failed to connect pcm to audio interface\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
pcm = pcm_open(card, device, PCM_IN, &config);
|
||||
if (!pcm || !pcm_is_ready(pcm)) {
|
||||
printf("Unable to open PCM device (%s)\n",
|
||||
pcm_get_error(pcm));
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
|
||||
buffer = malloc(size);
|
||||
if (!buffer) {
|
||||
printf("Unable to allocate %u bytes\n", size);
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
|
||||
pcm_format_to_bits(format));
|
||||
|
||||
if (pcm_start(pcm) < 0) {
|
||||
printf("start error\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
end.tv_sec = now.tv_sec + cap_time;
|
||||
end.tv_nsec = now.tv_nsec;
|
||||
|
||||
while (capturing && !pcm_read(pcm, buffer, size)) {
|
||||
if (fwrite(buffer, 1, size, file) != size) {
|
||||
printf("Error capturing sample\n");
|
||||
break;
|
||||
}
|
||||
bytes_read += size;
|
||||
if (cap_time) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (now.tv_sec > end.tv_sec ||
|
||||
(now.tv_sec == end.tv_sec && now.tv_nsec >= end.tv_nsec))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frames = pcm_bytes_to_frames(pcm, bytes_read);
|
||||
free(buffer);
|
||||
|
||||
pcm_stop(pcm);
|
||||
err_close_pcm:
|
||||
connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_PCM, false);
|
||||
pcm_close(pcm);
|
||||
err_close_mixer:
|
||||
if (payload) {
|
||||
free(payload);
|
||||
}
|
||||
mixer_close(mixer);
|
||||
return frames;
|
||||
}
|
594
qcom/opensource/agm/plugins/tinyalsa/test/agmcompresscap.c
Normal file
594
qcom/opensource/agm/plugins/tinyalsa/test/agmcompresscap.c
Normal file
@@ -0,0 +1,594 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
* This code is used under the BSD license.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) 2011-2012, Intel Corporation
|
||||
* Copyright (c) 2013-2014, Wolfson Microelectronic Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Vinod Koul <vinod.koul@linux.intel.com>
|
||||
* Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* LGPL LICENSE
|
||||
*
|
||||
* Copyright (c) 2011-2012, Intel Corporation
|
||||
* Copyright (c) 2013-2014, Wolfson Microelectronic Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to
|
||||
* the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <linux/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#define __force
|
||||
//#define __bitwise
|
||||
#define __user
|
||||
#include <sound/compress_params.h>
|
||||
#include <sound/compress_offload.h>
|
||||
#include <tinycompress/tinycompress.h>
|
||||
|
||||
#include "agmmixer.h"
|
||||
|
||||
static int verbose;
|
||||
static int file;
|
||||
static FILE *finfo;
|
||||
static bool streamed;
|
||||
|
||||
static const unsigned int DEFAULT_CHANNELS = 1;
|
||||
static const unsigned int DEFAULT_RATE = 44100;
|
||||
static const unsigned int DEFAULT_FORMAT = SNDRV_PCM_FORMAT_S16_LE;
|
||||
|
||||
struct riff_chunk {
|
||||
char desc[4];
|
||||
uint32_t size;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct wave_header {
|
||||
struct {
|
||||
struct riff_chunk chunk;
|
||||
char format[4];
|
||||
} __attribute__((__packed__)) riff;
|
||||
|
||||
struct {
|
||||
struct riff_chunk chunk;
|
||||
uint16_t type;
|
||||
uint16_t channels;
|
||||
uint32_t rate;
|
||||
uint32_t byterate;
|
||||
uint16_t blockalign;
|
||||
uint16_t samplebits;
|
||||
} __attribute__((__packed__)) fmt;
|
||||
|
||||
struct {
|
||||
struct riff_chunk chunk;
|
||||
} __attribute__((__packed__)) data;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
static const struct wave_header blank_wave_header = {
|
||||
.riff = {
|
||||
.chunk = {
|
||||
.desc = "RIFF",
|
||||
},
|
||||
.format = "WAVE",
|
||||
},
|
||||
.fmt = {
|
||||
.chunk = {
|
||||
.desc = "fmt ", /* Note the space is important here */
|
||||
.size = sizeof(blank_wave_header.fmt) -
|
||||
sizeof(blank_wave_header.fmt.chunk),
|
||||
},
|
||||
.type = 0x01, /* PCM */
|
||||
},
|
||||
.data = {
|
||||
.chunk = {
|
||||
.desc = "data",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static void init_wave_header(struct wave_header *header, uint16_t channels,
|
||||
uint32_t rate, uint16_t samplebits)
|
||||
{
|
||||
memcpy(header, &blank_wave_header, sizeof(blank_wave_header));
|
||||
|
||||
header->fmt.channels = channels;
|
||||
header->fmt.rate = rate;
|
||||
header->fmt.byterate = channels * rate * (samplebits / 8);
|
||||
header->fmt.blockalign = channels * (samplebits / 8);
|
||||
header->fmt.samplebits = samplebits;
|
||||
}
|
||||
|
||||
static void size_wave_header(struct wave_header *header, uint32_t size)
|
||||
{
|
||||
header->riff.chunk.size = sizeof(*header) -
|
||||
sizeof(header->riff.chunk) + size;
|
||||
header->data.chunk.size = size;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: crec [OPTIONS] [filename]\n"
|
||||
"-D\tcard number\n"
|
||||
"-d\tdevice node\n"
|
||||
"-buf\tbuffer size\n"
|
||||
"-f\tfragments\n"
|
||||
"-v\tverbose mode\n"
|
||||
"-l\tlength of record in seconds\n"
|
||||
" [-help print usage]\n"
|
||||
" [-c channels] [-r rate] [-b bits]\n"
|
||||
" [-n n_periods] [-i intf_name] [-dkv device_kv]\n"
|
||||
" [-dppkv deviceppkv] : Assign 0 if no device pp in the graph\n"
|
||||
" [-ikv instance_kv] : Assign 0 if no instance kv in the graph\n"
|
||||
" [-skv stream_kv]");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int print_time(struct compress *compress)
|
||||
{
|
||||
unsigned int avail;
|
||||
struct timespec tstamp;
|
||||
|
||||
if (compress_get_hpointer(compress, &avail, &tstamp) != 0) {
|
||||
fprintf(stderr, "Error querying timestamp\n");
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
return -1;
|
||||
} else {
|
||||
fprintf(finfo, "DSP recorded %jd.%jd\n",
|
||||
(intmax_t)tstamp.tv_sec, (intmax_t)tstamp.tv_nsec*1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int finish_record(void)
|
||||
{
|
||||
struct wave_header header;
|
||||
int ret;
|
||||
size_t nread, written;
|
||||
|
||||
if (!file)
|
||||
return -ENOENT;
|
||||
|
||||
/* can't rewind if streaming to stdout */
|
||||
if (streamed)
|
||||
return 0;
|
||||
|
||||
/* Get amount of data written to file */
|
||||
ret = lseek(file, 0, SEEK_END);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
written = ret;
|
||||
if (written < sizeof(header))
|
||||
return -ENOENT;
|
||||
written -= sizeof(header);
|
||||
|
||||
/* Sync file header from file */
|
||||
ret = lseek(file, 0, SEEK_SET);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
nread = read(file, &header, sizeof(header));
|
||||
if (nread != sizeof(header))
|
||||
return -errno;
|
||||
|
||||
/* Update file header */
|
||||
ret = lseek(file, 0, SEEK_SET);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
size_wave_header(&header, written);
|
||||
|
||||
written = write(file, &header, sizeof(header));
|
||||
if (written != sizeof(header))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void capture_samples(char *name, unsigned int card, unsigned int device,
|
||||
unsigned long buffer_size, unsigned int frag,
|
||||
unsigned int length, unsigned int rate,
|
||||
unsigned int channels, unsigned int format, struct device_config *dev_config, unsigned int stream_kv,
|
||||
unsigned int device_kv, unsigned int instance_kv, unsigned int devicepp_kv)
|
||||
{
|
||||
struct compr_config config;
|
||||
struct snd_codec codec;
|
||||
struct compress *compress;
|
||||
struct mixer *mixer;
|
||||
struct wave_header header;
|
||||
char *buffer;
|
||||
size_t written;
|
||||
int read, ret;
|
||||
unsigned int size, total_read = 0;
|
||||
unsigned int samplebits;
|
||||
uint32_t miid = 0;
|
||||
char *intf_name = dev_config->name;
|
||||
//TODO: Change default stream_kv to COMPRESS_RECORD later.
|
||||
stream_kv = stream_kv ? stream_kv : PCM_RECORD;
|
||||
|
||||
switch (format) {
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
samplebits = 32;
|
||||
break;
|
||||
default:
|
||||
samplebits = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Convert length from seconds to bytes */
|
||||
length = length * rate * (samplebits / 8) * channels;
|
||||
|
||||
if (verbose)
|
||||
fprintf(finfo, "%s: entry, reading %u bytes\n", __func__, length);
|
||||
if (!name) {
|
||||
file = STDOUT_FILENO;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
file = open(name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
if (file == -1) {
|
||||
fprintf(stderr, "Unable to open file '%s'\n", name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a header, will update with size once record is complete */
|
||||
if (!streamed) {
|
||||
init_wave_header(&header, channels, rate, samplebits);
|
||||
written = write(file, &header, sizeof(header));
|
||||
if (written != sizeof(header)) {
|
||||
fprintf(stderr, "Error writing output file header: %s\n",
|
||||
strerror(errno));
|
||||
goto file_exit;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&codec, 0, sizeof(codec));
|
||||
memset(&config, 0, sizeof(config));
|
||||
codec.id = SND_AUDIOCODEC_PCM;
|
||||
codec.ch_in = channels;
|
||||
codec.ch_out = channels;
|
||||
codec.sample_rate = rate;
|
||||
if (!codec.sample_rate) {
|
||||
fprintf(stderr, "invalid sample rate %d\n", rate);
|
||||
goto file_exit;
|
||||
}
|
||||
codec.format = format;
|
||||
if ((buffer_size != 0) && (frag != 0)) {
|
||||
config.fragment_size = buffer_size/frag;
|
||||
config.fragments = frag;
|
||||
}
|
||||
config.codec = &codec;
|
||||
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
goto file_exit;
|
||||
}
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, intf_name, dev_config)) {
|
||||
printf("Failed to set device media config\n");
|
||||
goto mixer_exit;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, intf_name, device_kv, CAPTURE,
|
||||
dev_config->rate, dev_config->bits, stream_kv)) {
|
||||
printf("Failed to set device metadata\n");
|
||||
goto mixer_exit;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
/* Change pcm_record to compress_record */
|
||||
if (set_agm_capture_stream_metadata(mixer, device, stream_kv, CAPTURE, STREAM_COMPRESS,
|
||||
instance_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto mixer_exit;
|
||||
}
|
||||
|
||||
if (devicepp_kv != 0) {
|
||||
if (set_agm_streamdevice_metadata(mixer, device, stream_kv, CAPTURE, STREAM_COMPRESS,
|
||||
intf_name, devicepp_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto mixer_exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name, STREAM_COMPRESS, TAG_STREAM_MFC, &miid);
|
||||
if (ret) {
|
||||
printf("MFC not present for this graph");
|
||||
} else {
|
||||
if (configure_mfc(mixer, device, intf_name, TAG_STREAM_MFC,
|
||||
STREAM_COMPRESS, rate, channels, pcm_format_to_bits(format), miid)) {
|
||||
printf("Failed to configure pspd mfc\n");
|
||||
goto mixer_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: No common metadata as of now*/
|
||||
|
||||
/* connect stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_COMPRESS, true)) {
|
||||
printf("Failed to connect stream to audio interface\n");
|
||||
goto mixer_exit;
|
||||
}
|
||||
|
||||
compress = compress_open(card, device, COMPRESS_OUT, &config);
|
||||
if (!compress || !is_compress_ready(compress)) {
|
||||
fprintf(stderr, "Unable to open Compress device %d:%d\n",
|
||||
card, device);
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
goto mixer_exit;
|
||||
};
|
||||
|
||||
if (verbose)
|
||||
fprintf(finfo, "%s: Opened compress device\n", __func__);
|
||||
|
||||
size = config.fragment_size;
|
||||
buffer = malloc(size * config.fragments);
|
||||
if (!buffer) {
|
||||
fprintf(stderr, "Unable to allocate %d bytes\n", size);
|
||||
goto comp_exit;
|
||||
}
|
||||
|
||||
fprintf(finfo, "Recording file %s On Card %u device %u, with buffer of %lu bytes\n",
|
||||
name, card, device, buffer_size);
|
||||
fprintf(finfo, "Codec %u Format %u Channels %u, %u Hz\n",
|
||||
codec.id, codec.format, codec.ch_out, rate);
|
||||
|
||||
compress_start(compress);
|
||||
|
||||
if (verbose)
|
||||
fprintf(finfo, "%s: Capturing audio NOW!!!\n", __func__);
|
||||
|
||||
do {
|
||||
read = compress_read(compress, buffer, size);
|
||||
if (read < 0) {
|
||||
fprintf(stderr, "Error reading sample\n");
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
goto buf_exit;
|
||||
}
|
||||
if ((unsigned int)read != size) {
|
||||
fprintf(stderr, "We read %d, DSP sent %d\n",
|
||||
size, read);
|
||||
}
|
||||
|
||||
if (read > 0) {
|
||||
total_read += read;
|
||||
|
||||
written = write(file, buffer, read);
|
||||
if (written != (size_t)read) {
|
||||
fprintf(stderr, "Error writing output file: %s\n",
|
||||
strerror(errno));
|
||||
goto buf_exit;
|
||||
}
|
||||
if (verbose) {
|
||||
print_time(compress);
|
||||
fprintf(finfo, "%s: read %d\n", __func__, read);
|
||||
}
|
||||
}
|
||||
} while (!length || total_read < length);
|
||||
|
||||
ret = compress_stop(compress);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error closing stream\n");
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
}
|
||||
|
||||
ret = finish_record();
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to finish header: %s\n", strerror(ret));
|
||||
goto buf_exit;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
fprintf(finfo, "%s: exit success\n", __func__);
|
||||
|
||||
free(buffer);
|
||||
close(file);
|
||||
file = 0;
|
||||
|
||||
compress_close(compress);
|
||||
|
||||
return;
|
||||
buf_exit:
|
||||
free(buffer);
|
||||
comp_exit:
|
||||
compress_close(compress);
|
||||
connect_agm_audio_intf_to_stream(mixer, device, intf_name, STREAM_COMPRESS, false);
|
||||
mixer_exit:
|
||||
mixer_close(mixer);
|
||||
file_exit:
|
||||
close(file);
|
||||
|
||||
if (verbose)
|
||||
fprintf(finfo, "%s: exit failure\n", __func__);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void sig_handler(int signum __attribute__ ((unused)))
|
||||
{
|
||||
finish_record();
|
||||
|
||||
if (file)
|
||||
close(file);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *file = NULL;
|
||||
unsigned long buffer_size = 0;
|
||||
unsigned int card = 0, device = 0, frag = 0, length = 0;
|
||||
unsigned int rate = DEFAULT_RATE, channels = DEFAULT_CHANNELS;
|
||||
unsigned int bits = 16;
|
||||
unsigned int format = DEFAULT_FORMAT;
|
||||
char* intf_name = NULL;
|
||||
int ret = 0;
|
||||
unsigned int devicepp_kv = DEVICEPP_TX_AUDIO_FLUENCE_SMECNS;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int instance_kv = INSTANCE_1;
|
||||
struct device_config config;
|
||||
unsigned int device_kv = 0;
|
||||
|
||||
if (signal(SIGINT, sig_handler) == SIG_ERR) {
|
||||
fprintf(stderr, "Error registering signal handler\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc < 3)
|
||||
usage();
|
||||
|
||||
verbose = 0;
|
||||
|
||||
file = argv[1];
|
||||
/* parse command line arguments */
|
||||
argv += 2;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
channels = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-r") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
rate = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-b") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
bits = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-l") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
length = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_name = *argv;
|
||||
} else if (strcmp(*argv, "-dkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-ikv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
instance_kv = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-dppkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
devicepp_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-buf") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
buffer_size = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-f") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
frag = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-v") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
verbose = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (intf_name == NULL) {
|
||||
printf("Invalid audio interface index denoted by -i\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, intf_name, &config);
|
||||
if (ret) {
|
||||
printf("Invalid input, entry not found for %s\n", intf_name);
|
||||
fclose(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (bits) {
|
||||
case 32:
|
||||
format = SNDRV_PCM_FORMAT_S32_LE;
|
||||
break;
|
||||
default:
|
||||
format = SNDRV_PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
}
|
||||
capture_samples(file, card, device, buffer_size, frag, length,
|
||||
rate, channels, format, &config, stream_kv, device_kv, instance_kv,
|
||||
devicepp_kv);
|
||||
|
||||
fprintf(finfo, "Finish capturing... Close Normally\n");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
653
qcom/opensource/agm/plugins/tinyalsa/test/agmcompressplay.c
Normal file
653
qcom/opensource/agm/plugins/tinyalsa/test/agmcompressplay.c
Normal file
@@ -0,0 +1,653 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
* This code is used under the BSD license.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) 2011-2012, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Vinod Koul <vinod.koul@linux.intel.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* LGPL LICENSE
|
||||
*
|
||||
* Copyright (c) 2011-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to
|
||||
* the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/time.h>
|
||||
#define __force
|
||||
//#define __bitwise
|
||||
#define __user
|
||||
#include <sound/compress_params.h>
|
||||
#include <tinycompress/tinycompress.h>
|
||||
|
||||
#include "agmmixer.h"
|
||||
|
||||
|
||||
#define MP3_SYNC 0xe0ff
|
||||
|
||||
const int mp3_sample_rates[3][3] = {
|
||||
{44100, 48000, 32000}, /* MPEG-1 */
|
||||
{22050, 24000, 16000}, /* MPEG-2 */
|
||||
{11025, 12000, 8000}, /* MPEG-2.5 */
|
||||
};
|
||||
|
||||
const int mp3_bit_rates[3][3][15] = {
|
||||
{
|
||||
/* MPEG-1 */
|
||||
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, /* Layer 1 */
|
||||
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, /* Layer 2 */
|
||||
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}, /* Layer 3 */
|
||||
},
|
||||
{
|
||||
/* MPEG-2 */
|
||||
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, /* Layer 1 */
|
||||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 2 */
|
||||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 3 */
|
||||
},
|
||||
{
|
||||
/* MPEG-2.5 */
|
||||
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, /* Layer 1 */
|
||||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 2 */
|
||||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, /* Layer 3 */
|
||||
},
|
||||
};
|
||||
|
||||
enum mpeg_version {
|
||||
MPEG1 = 0,
|
||||
MPEG2 = 1,
|
||||
MPEG25 = 2
|
||||
};
|
||||
|
||||
enum mp3_stereo_mode {
|
||||
STEREO = 0x00,
|
||||
JOINT = 0x01,
|
||||
DUAL = 0x02,
|
||||
MONO = 0x03
|
||||
};
|
||||
|
||||
static int verbose;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: cplay [OPTIONS] filename\n"
|
||||
"-D\tcard number\n"
|
||||
"-d\tdevice node\n"
|
||||
"-b\tbuffer size\n"
|
||||
"-f\tfragments\n\n"
|
||||
"-v\tverbose mode\n"
|
||||
"-help\tPrints this help list\n\n"
|
||||
"-t\tcodec type\n\n"
|
||||
"1 : mp3"
|
||||
"2 : aac"
|
||||
"-p\tpause/resume with 2 secs sleep\n\n"
|
||||
" [-num_intf num of interfaces followed by interface name]\n"
|
||||
" [-i intf_name] : Can be multiple if num_intf is more than 1\n"
|
||||
" [-dkv device_kv] : Can be multiple if num_intf is more than 1\n"
|
||||
" [-dppkv deviceppkv] : Assign 0 if no device pp in the graph\n"
|
||||
" [-ikv instance_kv] : Assign 0 if no instance kv in the graph\n"
|
||||
" [-skv stream_kv]");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void play_samples(char *name, unsigned int card, unsigned int device, unsigned int *device_kv,
|
||||
unsigned int stream_kv, unsigned int instance_kv, unsigned int *devicepp_kv,
|
||||
unsigned long buffer_size, unsigned int frag, unsigned int format,
|
||||
int pause, char **intf_name, int intf_num);
|
||||
|
||||
struct mp3_header {
|
||||
uint16_t sync;
|
||||
uint8_t format1;
|
||||
uint8_t format2;
|
||||
};
|
||||
|
||||
#define ADTS_SYNC 0xF0FF
|
||||
#define MP3_FORMAT 1
|
||||
#define AAC_ADTS_FORMAT 2
|
||||
|
||||
struct adts_header {
|
||||
uint32_t sync;
|
||||
uint8_t format1;
|
||||
uint8_t format2;
|
||||
uint8_t format3;
|
||||
};
|
||||
|
||||
uint aac_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 48000, 48000, 48000};
|
||||
|
||||
int parse_aac_header(struct adts_header *header, unsigned int *num_channels,
|
||||
unsigned int *sample_rate, unsigned int *protection_absent)
|
||||
{
|
||||
int profile, sample_rate_idx;
|
||||
|
||||
/* check sync bits */
|
||||
if ((header->sync & 0xF0FF) != ADTS_SYNC) {
|
||||
fprintf(stderr, "Error: Can't find sync word: 0x%X\n", header->sync);
|
||||
return -1;
|
||||
}
|
||||
*protection_absent = (header->sync >> 8) & 0x01;
|
||||
profile = ((header->sync >> 22) & 0x03) - 1;
|
||||
sample_rate_idx = ((header->sync >> 18) & 0x0F);
|
||||
// channel_idx = ((header->format1 >> 7) & 0x07);
|
||||
// frame_length = ((header->format1 >> 14) & 0x1FFF);
|
||||
|
||||
*num_channels = 2;
|
||||
*sample_rate = aac_sample_rates[sample_rate_idx];
|
||||
// *size = frame_length - ((protection_absent == 1)? 7: 9));
|
||||
|
||||
if (verbose)
|
||||
printf("%s: exit sr %d\n", __func__, *sample_rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_mp3_header(struct mp3_header *header, unsigned int *num_channels,
|
||||
unsigned int *sample_rate, unsigned int *bit_rate)
|
||||
{
|
||||
int ver_idx, mp3_version, layer, bit_rate_idx, sample_rate_idx, channel_idx;
|
||||
|
||||
/* check sync bits */
|
||||
if ((header->sync & MP3_SYNC) != MP3_SYNC) {
|
||||
fprintf(stderr, "Error: Can't find sync word\n");
|
||||
return -1;
|
||||
}
|
||||
ver_idx = (header->sync >> 11) & 0x03;
|
||||
mp3_version = ver_idx == 0 ? MPEG25 : ((ver_idx & 0x1) ? MPEG1 : MPEG2);
|
||||
layer = 4 - ((header->sync >> 9) & 0x03);
|
||||
bit_rate_idx = ((header->format1 >> 4) & 0x0f);
|
||||
sample_rate_idx = ((header->format1 >> 2) & 0x03);
|
||||
channel_idx = ((header->format2 >> 6) & 0x03);
|
||||
|
||||
if (sample_rate_idx == 3 || layer == 4 || bit_rate_idx == 15) {
|
||||
fprintf(stderr, "Error: Can't find valid header\n");
|
||||
return -1;
|
||||
}
|
||||
*num_channels = (channel_idx == MONO ? 1 : 2);
|
||||
*sample_rate = mp3_sample_rates[mp3_version][sample_rate_idx];
|
||||
*bit_rate = (mp3_bit_rates[mp3_version][layer - 1][bit_rate_idx]) * 1000;
|
||||
if (verbose)
|
||||
printf("%s: exit\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_codec_format_supported(unsigned int card, unsigned int device, struct snd_codec *codec)
|
||||
{
|
||||
if (is_codec_supported(card, device, COMPRESS_IN, codec) == false) {
|
||||
fprintf(stderr, "Error: This codec or format is not supported by DSP\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_time(struct compress *compress)
|
||||
{
|
||||
unsigned int avail;
|
||||
struct timespec tstamp;
|
||||
|
||||
if (compress_get_hpointer(compress, &avail, &tstamp) != 0) {
|
||||
fprintf(stderr, "Error querying timestamp\n");
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
return -1;
|
||||
} else
|
||||
fprintf(stderr, "DSP played %ld.%ld\n", tstamp.tv_sec, tstamp.tv_nsec*1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *file;
|
||||
unsigned long buffer_size = 0;
|
||||
char **intf_name = NULL;
|
||||
int ret = 0, i = 0;
|
||||
unsigned int card = 0, device = 0, frag = 0, audio_format = 0, pause = 0;
|
||||
int intf_num = 1;
|
||||
uint32_t dkv = SPEAKER;
|
||||
uint32_t dppkv = DEVICEPP_RX_AUDIO_MBDRC;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int instance_kv = INSTANCE_1;
|
||||
unsigned int *device_kv = (unsigned int *) malloc(intf_num * sizeof(unsigned int));
|
||||
unsigned int *devicepp_kv = (unsigned int *) malloc(intf_num * sizeof(unsigned int));
|
||||
|
||||
if (!device_kv || !devicepp_kv) {
|
||||
printf(" insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
device_kv[0] = dkv;
|
||||
devicepp_kv[0] = dppkv;
|
||||
|
||||
file = argv[1];
|
||||
/* parse command line arguments */
|
||||
argv += 2;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-t") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
audio_format = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-p") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
pause = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-f") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
frag = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-v") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
verbose = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-num_intf") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_num = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
intf_name = (char**) malloc(intf_num * sizeof(char*));
|
||||
if (!intf_name) {
|
||||
printf("insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++){
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_name[i] = *argv;
|
||||
}
|
||||
} else if (strcmp(*argv, "-dkv") == 0) {
|
||||
device_kv = (unsigned int *) realloc(device_kv, intf_num * sizeof(unsigned int));
|
||||
if (!device_kv) {
|
||||
printf(" insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++) {
|
||||
argv++;
|
||||
if (*argv) {
|
||||
device_kv[i] = convert_char_to_hex(*argv);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-ikv") == 0) {
|
||||
argv++;
|
||||
if (*argv) {
|
||||
instance_kv = atoi(*argv);
|
||||
}
|
||||
} else if (strcmp(*argv, "-dppkv") == 0) {
|
||||
devicepp_kv = (unsigned int *) realloc(devicepp_kv, intf_num * sizeof(unsigned int));
|
||||
if (!devicepp_kv) {
|
||||
printf(" insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++) {
|
||||
devicepp_kv[i] = DEVICEPP_RX_AUDIO_MBDRC;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++)
|
||||
{
|
||||
argv++;
|
||||
if(*argv) {
|
||||
devicepp_kv[i] = convert_char_to_hex(*argv);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (intf_name == NULL)
|
||||
return 1;
|
||||
|
||||
play_samples(file, card, device, device_kv, stream_kv, instance_kv, devicepp_kv,
|
||||
buffer_size, frag, audio_format, pause,
|
||||
intf_name, intf_num);
|
||||
|
||||
fprintf(stderr, "Finish Playing.... Close Normally\n");
|
||||
if (device_kv)
|
||||
free(device_kv);
|
||||
if (devicepp_kv)
|
||||
free(devicepp_kv);
|
||||
if (intf_name)
|
||||
free(intf_name);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void play_samples(char *name, unsigned int card, unsigned int device, unsigned int *device_kv,
|
||||
unsigned int stream_kv, unsigned int instance_kv, unsigned int *devicepp_kv,
|
||||
unsigned long buffer_size, unsigned int frag, unsigned int format,
|
||||
int pause, char **intf_name, int intf_num)
|
||||
{
|
||||
struct compr_config config;
|
||||
struct snd_codec codec;
|
||||
struct compress *compress;
|
||||
struct mp3_header header;
|
||||
struct adts_header adts_header;
|
||||
struct mixer *mixer;
|
||||
FILE *file;
|
||||
char *buffer;
|
||||
int num_read, wrote;
|
||||
unsigned int channels = 0, rate = 0, bits = 0;
|
||||
struct device_config *dev_config = NULL;
|
||||
struct group_config *grp_config = NULL;
|
||||
int size, index, ret = 0;
|
||||
uint32_t miid = 0;
|
||||
|
||||
dev_config = (struct device_config *) malloc(intf_num * sizeof(struct device_config));
|
||||
if (!dev_config) {
|
||||
printf("Failed to allocate memory for dev config");
|
||||
return;
|
||||
}
|
||||
grp_config = (struct group_config *) malloc(intf_num * sizeof(struct group_config));
|
||||
if (!grp_config) {
|
||||
printf("Failed to allocate memory for group config");
|
||||
return;
|
||||
}
|
||||
|
||||
stream_kv = stream_kv ? stream_kv : COMPRESSED_OFFLOAD_PLAYBACK;
|
||||
|
||||
if (verbose)
|
||||
printf("%s: entry\n", __func__);
|
||||
file = fopen(name, "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Unable to open file '%s'\n", name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (format == MP3_FORMAT) {
|
||||
fread(&header, sizeof(header), 1, file);
|
||||
|
||||
if (parse_mp3_header(&header, &channels, &rate, &bits) == -1) {
|
||||
fclose(file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
codec.id = SND_AUDIOCODEC_MP3;
|
||||
#ifdef SND_COMPRESS_DEC_HDR
|
||||
} else if (format == AAC_ADTS_FORMAT) {
|
||||
uint16_t protection_absent, crc;
|
||||
fread(&adts_header, sizeof(adts_header), 1, file);
|
||||
if (parse_aac_header(&adts_header, &channels, &rate, (unsigned int*)&protection_absent) == -1) {
|
||||
fclose(file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!protection_absent) {
|
||||
fread(&crc, 2, 1, file);
|
||||
}
|
||||
codec.id = SND_AUDIOCODEC_AAC;
|
||||
codec.format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
|
||||
bits = 16;
|
||||
codec.options.aac_dec.audio_obj_type = 29;
|
||||
codec.options.aac_dec.pce_bits_size = 0;
|
||||
#endif
|
||||
} else {
|
||||
printf("unknown format");
|
||||
}
|
||||
codec.ch_in = channels;
|
||||
codec.ch_out = channels;
|
||||
codec.sample_rate = rate;
|
||||
if (!codec.sample_rate) {
|
||||
fprintf(stderr, "invalid sample rate %d\n", rate);
|
||||
fclose(file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
codec.bit_rate = bits;
|
||||
codec.rate_control = 0;
|
||||
codec.profile = 0;
|
||||
codec.level = 0;
|
||||
codec.ch_mode = 0;
|
||||
codec.format = 0;
|
||||
if ((buffer_size != 0) && (frag != 0)) {
|
||||
config.fragment_size = buffer_size/frag;
|
||||
config.fragments = frag;
|
||||
} else {
|
||||
/* use driver defaults */
|
||||
config.fragment_size = 0;
|
||||
config.fragments = 0;
|
||||
}
|
||||
config.codec = &codec;
|
||||
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
goto FILE_EXIT;
|
||||
}
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, intf_name[index], &dev_config[index]);
|
||||
if (ret) {
|
||||
printf("Invalid input, entry not found for : %s\n", intf_name[index]);
|
||||
fclose(file);
|
||||
}
|
||||
printf("Backend %s rate ch bit : %d, %d, %d\n", intf_name[index],
|
||||
dev_config[index].rate, dev_config[index].ch, dev_config[index].bits);
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, intf_name[index], &dev_config[index])) {
|
||||
printf("Failed to set device media config\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, intf_name[index], device_kv[index], PLAYBACK,
|
||||
dev_config[index].rate, dev_config[index].bits, stream_kv)) {
|
||||
printf("Failed to set device metadata\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_stream_metadata(mixer, device, stream_kv, PLAYBACK, STREAM_COMPRESS,
|
||||
instance_kv)) {
|
||||
printf("Failed to set stream metadata\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
|
||||
/* Note: No common metadata as of now*/
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
if (devicepp_kv[index] != 0) {
|
||||
if (set_agm_streamdevice_metadata(mixer, device, stream_kv, PLAYBACK, STREAM_COMPRESS, intf_name[index],
|
||||
devicepp_kv[index])) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
/* connect stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, device, intf_name[index], STREAM_COMPRESS, true)) {
|
||||
printf("Failed to connect pcm to audio interface\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name[index], STREAM_PCM, PER_STREAM_PER_DEVICE_MFC, &miid);
|
||||
if (ret) {
|
||||
printf("MFC not present for this graph\n");
|
||||
} else {
|
||||
if (configure_mfc(mixer, device, intf_name[index], PER_STREAM_PER_DEVICE_MFC,
|
||||
STREAM_COMPRESS, dev_config[index].rate, dev_config[index].ch,
|
||||
dev_config[index].bits, miid)) {
|
||||
printf("Failed to configure pspd mfc\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(intf_name[index], "VIRT-")) {
|
||||
if (get_group_device_info(BACKEND_CONF_FILE, intf_name[index], &grp_config[index]))
|
||||
goto MIXER_EXIT;
|
||||
|
||||
if (set_agm_group_device_config(mixer, intf_name[index], &grp_config[index])) {
|
||||
printf("Failed to set grp device config\n");
|
||||
goto MIXER_EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
compress = compress_open(card, device, COMPRESS_IN, &config);
|
||||
if (!compress || !is_compress_ready(compress)) {
|
||||
fprintf(stderr, "Unable to open Compress device %d:%d\n",
|
||||
card, device);
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
goto MIXER_EXIT;
|
||||
};
|
||||
if (verbose)
|
||||
printf("%s: Opened compress device\n", __func__);
|
||||
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
if (strstr(intf_name[index], "VIRT-") || (device_kv[index] == SPEAKER) || (device_kv[index] == HANDSET)) {
|
||||
if (set_agm_group_mux_config(mixer, device, &grp_config[index], intf_name[index], dev_config[index].ch)) {
|
||||
printf("Failed to set grp device config\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
size = config.fragment_size;
|
||||
buffer = malloc(size * config.fragments);
|
||||
if (!buffer) {
|
||||
fprintf(stderr, "Unable to allocate %d bytes\n", size);
|
||||
goto COMP_EXIT;
|
||||
}
|
||||
|
||||
/* we will write frag fragment_size and then start */
|
||||
num_read = fread(buffer, 1, size * config.fragments, file);
|
||||
if (num_read > 0) {
|
||||
if (verbose)
|
||||
printf("%s: Doing first buffer write of %d\n", __func__, num_read);
|
||||
wrote = compress_write(compress, buffer, num_read);
|
||||
if (wrote < 0) {
|
||||
fprintf(stderr, "Error %d playing sample\n", wrote);
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
goto BUF_EXIT;
|
||||
}
|
||||
if (wrote != num_read) {
|
||||
/* TODO: Buufer pointer needs to be set here */
|
||||
fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote);
|
||||
}
|
||||
}
|
||||
printf("Playing file %s On Card %u device %u, with buffer of %lu bytes\n",
|
||||
name, card, device, buffer_size);
|
||||
printf("Format %u Channels %u, %u Hz, Bit Rate %d\n",
|
||||
SND_AUDIOCODEC_MP3, channels, rate, bits);
|
||||
|
||||
compress_start(compress);
|
||||
if (verbose)
|
||||
printf("%s: You should hear audio NOW!!!\n", __func__);
|
||||
|
||||
do {
|
||||
num_read = fread(buffer, 1, size, file);
|
||||
if (num_read > 0) {
|
||||
wrote = compress_write(compress, buffer, num_read);
|
||||
if (wrote < 0) {
|
||||
fprintf(stderr, "Error playing sample\n");
|
||||
fprintf(stderr, "ERR: %s\n", compress_get_error(compress));
|
||||
goto BUF_EXIT;
|
||||
}
|
||||
if (wrote != num_read) {
|
||||
/* TODO: Buffer pointer needs to be set here */
|
||||
fprintf(stderr, "We wrote %d, DSP accepted %d\n", num_read, wrote);
|
||||
}
|
||||
if (verbose) {
|
||||
print_time(compress);
|
||||
printf("%s: wrote %d\n", __func__, wrote);
|
||||
}
|
||||
if (pause) {
|
||||
printf("%s: pause \n", __func__);
|
||||
compress_pause(compress);
|
||||
sleep(2);
|
||||
printf("%s: resume \n", __func__);
|
||||
compress_resume(compress);
|
||||
}
|
||||
}
|
||||
} while (num_read > 0);
|
||||
|
||||
if (verbose)
|
||||
printf("%s: exit success\n", __func__);
|
||||
/* issue drain if it supports */
|
||||
compress_drain(compress);
|
||||
/* disconnect stream to audio intf */
|
||||
for(index = 0; index < intf_num; index++) {
|
||||
connect_agm_audio_intf_to_stream(mixer, device, intf_name[index], STREAM_COMPRESS, false);
|
||||
}
|
||||
free(buffer);
|
||||
fclose(file);
|
||||
compress_close(compress);
|
||||
return;
|
||||
BUF_EXIT:
|
||||
free(buffer);
|
||||
COMP_EXIT:
|
||||
compress_close(compress);
|
||||
MIXER_EXIT:
|
||||
if (dev_config)
|
||||
free(dev_config);
|
||||
if (grp_config)
|
||||
free(grp_config);
|
||||
mixer_close(mixer);
|
||||
FILE_EXIT:
|
||||
fclose(file);
|
||||
if (verbose)
|
||||
printf("%s: exit failure\n", __func__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
392
qcom/opensource/agm/plugins/tinyalsa/test/agmhostless.c
Normal file
392
qcom/opensource/agm/plugins/tinyalsa/test/agmhostless.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include "agmmixer.h"
|
||||
|
||||
static int close_f = 0;
|
||||
|
||||
void sigint_handler(int sig)
|
||||
{
|
||||
close_f = 1;
|
||||
}
|
||||
|
||||
void play_loopback(unsigned int card, unsigned int p_device, unsigned int c_device, unsigned int channels,
|
||||
unsigned int rate, enum pcm_format format, struct device_config *cap_config,
|
||||
struct device_config *p_config, unsigned int period_size,
|
||||
unsigned int period_count, unsigned int play_cap_time, char* capture_intf,
|
||||
char* play_intf, unsigned int pdkv, unsigned int cdkv, unsigned int stream_kv,
|
||||
unsigned int do_loopback);
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf(" Usage: %s [-D card] [-P Hostless Playback device] [-C Hostless Capture device] [-p period_size]\n"
|
||||
" [-n n_periods] [-c channels] [-r rate] [-b bits] [-T playback/capture time ]\n"
|
||||
" [-i capture intf] [-o playback intf]\n"
|
||||
" [-cdkv capture_device_kv] [-pdkv playback_device_kv] [-skv stream_kv]\n"
|
||||
" Used to enable 'hostless' mode for audio devices with a DSP back-end.\n"
|
||||
" Alternatively, specify '-l' for loopback mode: this program will read\n"
|
||||
" from the capture device and write to the playback device.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int card = 100;
|
||||
unsigned int p_device = 1;
|
||||
unsigned int c_device = 0;
|
||||
unsigned int period_size = 1024;
|
||||
unsigned int period_count = 4;
|
||||
unsigned int bits = 16;
|
||||
unsigned int num_channels = 2;
|
||||
unsigned int sample_rate = 48000;
|
||||
unsigned int play_cap_time = 10;
|
||||
char* c_intf_name = NULL;
|
||||
char* p_intf_name = NULL;
|
||||
unsigned int do_loopback = 0;
|
||||
enum pcm_format format;
|
||||
struct device_config capture_config;
|
||||
struct device_config play_config;
|
||||
unsigned int c_device_kv = 0;
|
||||
unsigned int p_device_kv = 0;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse command line arguments */
|
||||
argv += 1;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-P") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
p_device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-C") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
c_device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-p") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
period_size = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-n") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
period_count = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
num_channels = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-r") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
sample_rate = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-b") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
bits = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-T") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
play_cap_time = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
c_intf_name = *argv;
|
||||
} else if (strcmp(*argv, "-o") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
p_intf_name = *argv;
|
||||
} else if (strcmp(*argv, "-l") == 0) {
|
||||
do_loopback = 1;
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-cdkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
c_device_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-pdkv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
p_device_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, c_intf_name, &capture_config);
|
||||
if (ret) {
|
||||
printf("Invalid input, assigning default values for : %s\n", c_intf_name);
|
||||
capture_config.rate = sample_rate;
|
||||
capture_config.bits = bits;
|
||||
capture_config.ch = num_channels;
|
||||
}
|
||||
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, p_intf_name, &play_config);
|
||||
if (ret) {
|
||||
printf("Invalid input, assigning default values for : %s\n", p_intf_name);
|
||||
play_config.rate = sample_rate;
|
||||
play_config.bits = bits;
|
||||
play_config.ch = num_channels;
|
||||
}
|
||||
|
||||
switch (bits) {
|
||||
case 32:
|
||||
format = PCM_FORMAT_S32_LE;
|
||||
break;
|
||||
case 24:
|
||||
format = PCM_FORMAT_S24_LE;
|
||||
break;
|
||||
case 16:
|
||||
format = PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
default:
|
||||
printf("%u bits is not supported.\n", bits);
|
||||
return 1;
|
||||
}
|
||||
play_loopback(card, p_device, c_device, num_channels, sample_rate, format, &capture_config, &play_config, period_size,
|
||||
period_count, play_cap_time, c_intf_name, p_intf_name, p_device_kv,
|
||||
c_device_kv, stream_kv, do_loopback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void play_loopback(unsigned int card, unsigned int p_device, unsigned int c_device, unsigned int channels,
|
||||
unsigned int rate, enum pcm_format format, struct device_config *cap_config,
|
||||
struct device_config *p_config, unsigned int period_size,
|
||||
unsigned int period_count, unsigned int play_cap_time, char* capture_intf,
|
||||
char* play_intf, unsigned int pdkv, unsigned int cdkv, unsigned int stream_kv,
|
||||
unsigned int do_loopback)
|
||||
{
|
||||
struct pcm_config config;
|
||||
struct pcm *p_pcm, *c_pcm;
|
||||
struct mixer *mixer;
|
||||
char *buffer = NULL;
|
||||
char *p_intf_name = play_intf;
|
||||
char *c_intf_name = capture_intf;
|
||||
unsigned int size;
|
||||
unsigned int bytes_read = 0;
|
||||
unsigned int frames = 0, ret = 0, miid = 0;
|
||||
struct timespec end;
|
||||
struct timespec now;
|
||||
struct group_config grp_config;
|
||||
stream_kv = stream_kv ? stream_kv : PCM_RX_LOOPBACK;
|
||||
|
||||
if (!cap_config || !p_config || !capture_intf || !play_intf) {
|
||||
printf("%s: %d: Invalid arguments.\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.channels = channels;
|
||||
config.rate = rate;
|
||||
config.period_size = period_size;
|
||||
config.period_count = period_count;
|
||||
config.format = format;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, p_intf_name, p_config)) {
|
||||
printf("Failed to set playback device media config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (set_agm_device_media_config(mixer, c_intf_name, cap_config)) {
|
||||
printf("Failed to set capture device media config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, c_intf_name, cdkv, CAPTURE, rate, cap_config->bits, stream_kv)) {
|
||||
printf("Failed to set capture device metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (set_agm_audio_intf_metadata(mixer, p_intf_name, pdkv, PLAYBACK, rate, p_config->bits, stream_kv)) {
|
||||
printf("Failed to set playback device metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (set_agm_stream_metadata(mixer, p_device, stream_kv, LOOPBACK, STREAM_PCM,
|
||||
0)) {
|
||||
printf("Failed to capture stream metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* Note: No common metadata as of now*/
|
||||
|
||||
/* connect pcm stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, p_device, p_intf_name, STREAM_PCM, true)) {
|
||||
printf("Failed to connect playback pcm to audio interface\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (connect_agm_audio_intf_to_stream(mixer, c_device, c_intf_name, STREAM_PCM, true)) {
|
||||
printf("Failed to connect capture pcm to audio interface\n");
|
||||
connect_agm_audio_intf_to_stream(mixer, p_device, p_intf_name, STREAM_PCM, false);
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
if (connect_play_pcm_to_cap_pcm(mixer, p_device, c_device)) {
|
||||
printf("Failed to connect capture pcm to audio interface\n");
|
||||
goto err_disconnect;
|
||||
}
|
||||
|
||||
if (strstr(p_intf_name, "VIRT-")) {
|
||||
if (get_group_device_info(BACKEND_CONF_FILE, p_intf_name, &grp_config))
|
||||
goto err_disconnect;
|
||||
|
||||
if (set_agm_group_device_config(mixer, p_intf_name, &grp_config)) {
|
||||
printf("Failed to set grp device config\n");
|
||||
goto err_disconnect;
|
||||
}
|
||||
}
|
||||
ret = agm_mixer_get_miid (mixer, p_device, p_intf_name, STREAM_PCM, PER_STREAM_PER_DEVICE_MFC, &miid);
|
||||
if (ret) {
|
||||
printf("MFC not present for this graph\n");
|
||||
} else {
|
||||
if (configure_mfc(mixer, p_device, p_intf_name, PER_STREAM_PER_DEVICE_MFC,
|
||||
STREAM_PCM, p_config->rate, p_config->ch,
|
||||
p_config->bits, miid)) {
|
||||
printf("Failed to configure pspd mfc\n");
|
||||
goto err_disconnect;
|
||||
}
|
||||
}
|
||||
|
||||
p_pcm = pcm_open(card, p_device, PCM_OUT, &config);
|
||||
if (!p_pcm || !pcm_is_ready(p_pcm)) {
|
||||
printf("Unable to open playback PCM device (%s)\n",
|
||||
pcm_get_error(p_pcm));
|
||||
goto err_disconnect;
|
||||
}
|
||||
if (strstr(p_intf_name, "VIRT-") || (pdkv == SPEAKER) || (pdkv == HANDSET)) {
|
||||
if (set_agm_group_mux_config(mixer, p_device, &grp_config, p_intf_name, p_config->ch)) {
|
||||
printf("Failed to set mux config\n");
|
||||
goto err_close_p_pcm;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcm_start(p_pcm) < 0) {
|
||||
printf("start error");
|
||||
goto err_close_p_pcm;
|
||||
}
|
||||
|
||||
c_pcm = pcm_open(card, c_device, PCM_IN, &config);
|
||||
if (!c_pcm || !pcm_is_ready(c_pcm)) {
|
||||
printf("Unable to open playback PCM device (%s)\n",
|
||||
pcm_get_error(c_pcm));
|
||||
goto err_close_p_pcm;
|
||||
}
|
||||
|
||||
if (pcm_start(c_pcm) < 0) {
|
||||
printf("start error");
|
||||
goto err_close_c_pcm;
|
||||
}
|
||||
|
||||
if (do_loopback) {
|
||||
size = pcm_frames_to_bytes(c_pcm, pcm_get_buffer_size(c_pcm));
|
||||
buffer = malloc(size);
|
||||
if (!buffer) {
|
||||
printf("Unable to allocate %d bytes\n", size);
|
||||
goto err_close_c_pcm;
|
||||
}
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
end.tv_sec += play_cap_time;
|
||||
while (1) {
|
||||
if (close_f)
|
||||
break;
|
||||
if (do_loopback) {
|
||||
if (pcm_read(c_pcm, buffer, size)) {
|
||||
printf("Unable to read from PCM capture device %u (%s)\n",
|
||||
c_device, pcm_get_error(c_pcm));
|
||||
break;
|
||||
}
|
||||
if (pcm_write(p_pcm, buffer, size)) {
|
||||
printf("Unable to write to PCM playback device %u (%s)\n",
|
||||
p_device, pcm_get_error(p_pcm));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
if (play_cap_time) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (now.tv_sec > end.tv_sec ||
|
||||
(now.tv_sec == end.tv_sec && now.tv_nsec >= end.tv_nsec))
|
||||
break;
|
||||
}
|
||||
}
|
||||
connect_play_pcm_to_cap_pcm(mixer, -1, c_device);
|
||||
err_close_c_pcm:
|
||||
pcm_close(c_pcm);
|
||||
err_close_p_pcm:
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
pcm_close(p_pcm);
|
||||
err_disconnect:
|
||||
connect_agm_audio_intf_to_stream(mixer, p_device, p_intf_name, STREAM_PCM, false);
|
||||
connect_agm_audio_intf_to_stream(mixer, c_device, c_intf_name, STREAM_PCM, false);
|
||||
err_close_mixer:
|
||||
mixer_close(mixer);
|
||||
}
|
1625
qcom/opensource/agm/plugins/tinyalsa/test/agmmixer.c
Normal file
1625
qcom/opensource/agm/plugins/tinyalsa/test/agmmixer.c
Normal file
File diff suppressed because it is too large
Load Diff
121
qcom/opensource/agm/plugins/tinyalsa/test/agmmixer.h
Normal file
121
qcom/opensource/agm/plugins/tinyalsa/test/agmmixer.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
** Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __AGM_COMMON_H__
|
||||
#define __AGM_COMMON_H__
|
||||
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
#include <kvh2xml.h>
|
||||
|
||||
enum usecase_type{
|
||||
PLAYBACK,
|
||||
CAPTURE,
|
||||
LOOPBACK,
|
||||
HAPTICS,
|
||||
};
|
||||
|
||||
enum stream_type {
|
||||
STREAM_PCM,
|
||||
STREAM_COMPRESS,
|
||||
};
|
||||
|
||||
struct device_config {
|
||||
char name[80];
|
||||
unsigned int rate;
|
||||
unsigned int ch;
|
||||
unsigned int bits;
|
||||
enum pcm_format format;
|
||||
};
|
||||
|
||||
struct usbAudioConfig {
|
||||
uint32_t usb_token;
|
||||
uint32_t svc_interval;
|
||||
};
|
||||
|
||||
struct group_config {
|
||||
char name[80];
|
||||
unsigned int rate;
|
||||
unsigned int ch;
|
||||
unsigned int bits;
|
||||
unsigned int slot_mask;
|
||||
enum pcm_format format;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SLOT_MASK1 = 1,
|
||||
SLOT_MASK3 = 3,
|
||||
SLOT_MASK7 = 7,
|
||||
SLOT_MASK15 = 15,
|
||||
}slot_mask_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int convert_char_to_hex(char *char_num);
|
||||
int get_pcm_bit_width(enum pcm_format fmt_id);
|
||||
int set_agm_device_media_config(struct mixer *mixer, char *intf_name, struct device_config *config);
|
||||
int set_agm_device_custom_payload(struct mixer *mixer, char *intf_name, void *payload, size_t size);
|
||||
void get_agm_usb_audio_config_payload(uint8_t** payload, size_t* size, uint32_t miid, struct usbAudioConfig *data);
|
||||
int set_agm_group_device_config(struct mixer *mixer, char *intf_name, struct group_config *config);
|
||||
int set_agm_group_mux_config(struct mixer *mixer, unsigned int device, struct group_config *config, char *intf_name, unsigned int channels);
|
||||
int connect_play_pcm_to_cap_pcm(struct mixer *mixer, unsigned int p_device, unsigned int c_device);
|
||||
int set_agm_audio_intf_metadata(struct mixer *mixer, char *intf_name, unsigned int dkv, enum usecase_type, int rate, int bitwidth, uint32_t val);
|
||||
int set_agm_stream_metadata_type(struct mixer *mixer, int device, char *val, enum stream_type stype);
|
||||
int set_agm_streamdevice_metadata(struct mixer *mixer, int device, uint32_t val, enum usecase_type usecase, enum stream_type stype,
|
||||
char *intf_name, unsigned int devicepp_kv);
|
||||
int set_agm_stream_metadata(struct mixer *mixer, int device, uint32_t val, enum usecase_type utype, enum stream_type stype,
|
||||
unsigned int instance_kv);
|
||||
int set_agm_capture_stream_metadata(struct mixer *mixer, int device, uint32_t val, enum usecase_type utype, enum stream_type stype,
|
||||
unsigned int instance_kv);
|
||||
int connect_agm_audio_intf_to_stream(struct mixer *mixer, unsigned int device,
|
||||
char *intf_name, enum stream_type, bool connect);
|
||||
int agm_mixer_register_event(struct mixer *mixer, int device, enum stream_type stype, uint32_t miid, uint8_t is_register);
|
||||
int agm_mixer_get_miid(struct mixer *mixer, int device, char *intf_name, enum stream_type stype, int tag_id, uint32_t *miid);
|
||||
int agm_mixer_set_param(struct mixer *mixer, int device,
|
||||
enum stream_type stype, void *payload, int size);
|
||||
int agm_mixer_set_param_with_file(struct mixer *mixer, int device,
|
||||
enum stream_type stype, char *path);
|
||||
int agm_mixer_set_ecref_path(struct mixer *mixer, unsigned int device, enum stream_type stype, char *intf_name);
|
||||
int agm_mixer_get_event_param(struct mixer *mixer, int device, enum stream_type stype,uint32_t miid);
|
||||
int agm_mixer_get_buf_tstamp(struct mixer *mixer, int device, enum stream_type stype, uint64_t *tstamp);
|
||||
int get_device_media_config(char* filename, char *intf_name, struct device_config *config);
|
||||
int get_group_device_info(char* filename, char *intf_name, struct group_config *config);
|
||||
int configure_mfc(struct mixer *mixer, int device, char *intf_name, int tag, enum stream_type stype, unsigned int rate,
|
||||
unsigned int channels, unsigned int bits, uint32_t miid);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
516
qcom/opensource/agm/plugins/tinyalsa/test/agmplay.c
Normal file
516
qcom/opensource/agm/plugins/tinyalsa/test/agmplay.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
** Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Copyright 2011, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of The Android Open Source Project nor the names of
|
||||
** its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
** DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center, Inc. are provided under the following license:
|
||||
** Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <agm/agm_api.h>
|
||||
#include "agmmixer.h"
|
||||
|
||||
#define ID_RIFF 0x46464952
|
||||
#define ID_WAVE 0x45564157
|
||||
#define ID_FMT 0x20746d66
|
||||
#define ID_DATA 0x61746164
|
||||
|
||||
struct riff_wave_header {
|
||||
uint32_t riff_id;
|
||||
uint32_t riff_sz;
|
||||
uint32_t wave_id;
|
||||
};
|
||||
|
||||
struct chunk_header {
|
||||
uint32_t id;
|
||||
uint32_t sz;
|
||||
};
|
||||
|
||||
struct chunk_fmt {
|
||||
uint16_t audio_format;
|
||||
uint16_t num_channels;
|
||||
uint32_t sample_rate;
|
||||
uint32_t byte_rate;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
};
|
||||
|
||||
static int close = 0;
|
||||
|
||||
void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int usb_device,
|
||||
unsigned int channels, unsigned int rate, unsigned int bits,
|
||||
unsigned int *device_kv, unsigned int stream_kv, unsigned int instance_kv,
|
||||
unsigned int *devicepp_kv, struct chunk_fmt fmt, bool haptics, char **intf_name,
|
||||
int intf_num, bool is_24_LE);
|
||||
|
||||
void stream_close(int sig)
|
||||
{
|
||||
/* allow the stream to be closed gracefully */
|
||||
signal(sig, SIG_IGN);
|
||||
close = 1;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf(" Usage: %s file.wav [-help print usage] [-D card] [-d device]\n"
|
||||
" [-c channels] [-r rate] [-b bits]\n"
|
||||
" [-num_intf num of interfaces followed by interface name]\n"
|
||||
" [-i intf_name] : Can be multiple if num_intf is more than 1\n"
|
||||
" [-dkv device_kv] : Can be multiple if num_intf is more than 1\n"
|
||||
" [-dppkv deviceppkv] : Assign 0 if no device pp in the graph\n"
|
||||
" [-ikv instance_kv] : Assign 0 if no instance kv in the graph\n"
|
||||
" [-skv stream_kv] [-h haptics usecase]\n"
|
||||
" [is_24_LE] : [0-1] Only to be used if user wants to play S24_LE clip\n"
|
||||
" [-usb_d usb device]\n"
|
||||
" 0: If clip bps is 32, and format is S32_LE\n"
|
||||
" 1: If clip bps is 24, and format is S24_LE\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *file;
|
||||
struct riff_wave_header riff_wave_header;
|
||||
struct chunk_header chunk_header;
|
||||
struct chunk_fmt chunk_fmt;
|
||||
unsigned int card = 100, device = 100, i=0;
|
||||
unsigned int usb_device = 1;
|
||||
unsigned int channels = 2;
|
||||
unsigned int rate = 48000;
|
||||
unsigned int bits = 16;
|
||||
int intf_num = 1;
|
||||
uint32_t dkv = SPEAKER;
|
||||
uint32_t dppkv = DEVICEPP_RX_AUDIO_MBDRC;
|
||||
unsigned int stream_kv = 0;
|
||||
unsigned int instance_kv = INSTANCE_1;
|
||||
bool haptics = false;
|
||||
char **intf_name = NULL;
|
||||
char *filename;
|
||||
int more_chunks = 1, ret = 0;
|
||||
bool is_24_LE = false;
|
||||
unsigned int *devicepp_kv = (unsigned int *) malloc(intf_num * sizeof(unsigned int));
|
||||
unsigned int *device_kv = (unsigned int *) malloc(intf_num * sizeof(unsigned int));
|
||||
|
||||
if (!device_kv || !devicepp_kv) {
|
||||
printf(" insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
device_kv[0] = dkv;
|
||||
devicepp_kv[0] = dppkv;
|
||||
|
||||
filename = argv[1];
|
||||
file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
printf("Unable to open file '%s'\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
|
||||
if ((riff_wave_header.riff_id != ID_RIFF) ||
|
||||
(riff_wave_header.wave_id != ID_WAVE)) {
|
||||
printf("Error: '%s' is not a riff/wave file\n", filename);
|
||||
fclose(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
do {
|
||||
fread(&chunk_header, sizeof(chunk_header), 1, file);
|
||||
|
||||
switch (chunk_header.id) {
|
||||
case ID_FMT:
|
||||
fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
|
||||
/* If the format header is larger, skip the rest */
|
||||
if (chunk_header.sz > sizeof(chunk_fmt))
|
||||
fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
|
||||
break;
|
||||
case ID_DATA:
|
||||
/* Stop looking for chunks */
|
||||
more_chunks = 0;
|
||||
break;
|
||||
default:
|
||||
/* Unknown chunk, skip bytes */
|
||||
fseek(file, chunk_header.sz, SEEK_CUR);
|
||||
}
|
||||
} while (more_chunks);
|
||||
|
||||
/* parse command line arguments */
|
||||
argv += 2;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, "-d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-c") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
channels = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-r") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
rate = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-b") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
bits = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-D") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
card = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-num_intf") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_num = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-i") == 0) {
|
||||
intf_name = (char**) malloc(intf_num * sizeof(char*));
|
||||
if (!intf_name) {
|
||||
printf("insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++){
|
||||
argv++;
|
||||
if (*argv)
|
||||
intf_name[i] = *argv;
|
||||
}
|
||||
} else if (strcmp(*argv, "-h") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
haptics = *argv;
|
||||
} else if (strcmp(*argv, "-dkv") == 0) {
|
||||
device_kv = (unsigned int *) realloc(device_kv, intf_num * sizeof(unsigned int));
|
||||
if (!device_kv) {
|
||||
printf(" insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++) {
|
||||
argv++;
|
||||
if (*argv) {
|
||||
device_kv[i] = convert_char_to_hex(*argv);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(*argv, "-skv") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
stream_kv = convert_char_to_hex(*argv);
|
||||
} else if (strcmp(*argv, "-ikv") == 0) {
|
||||
argv++;
|
||||
if (*argv) {
|
||||
instance_kv = atoi(*argv);
|
||||
}
|
||||
} else if (strcmp(*argv, "-dppkv") == 0) {
|
||||
devicepp_kv = (unsigned int *) realloc(devicepp_kv, intf_num * sizeof(unsigned int));
|
||||
if (!devicepp_kv) {
|
||||
printf(" insufficient memory\n");
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++) {
|
||||
devicepp_kv[i] = DEVICEPP_RX_AUDIO_MBDRC;
|
||||
}
|
||||
for (i = 0; i < intf_num ; i++)
|
||||
{
|
||||
argv++;
|
||||
if (*argv) {
|
||||
devicepp_kv[i] = convert_char_to_hex(*argv);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(*argv, "-is_24_LE") == 0) {
|
||||
argv++;
|
||||
if (*argv) {
|
||||
is_24_LE = atoi(*argv);
|
||||
}
|
||||
} else if (strcmp(*argv, "-usb_d") == 0) {
|
||||
argv++;
|
||||
if (*argv)
|
||||
usb_device = atoi(*argv);
|
||||
} else if (strcmp(*argv, "-help") == 0) {
|
||||
usage();
|
||||
}
|
||||
if (*argv)
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (intf_name == NULL)
|
||||
return 1;
|
||||
|
||||
play_sample(file, card, device, usb_device, channels, rate, bits, device_kv, stream_kv,
|
||||
instance_kv, devicepp_kv, chunk_fmt, haptics, intf_name, intf_num, is_24_LE);
|
||||
|
||||
fclose(file);
|
||||
if (device_kv)
|
||||
free(device_kv);
|
||||
if (devicepp_kv)
|
||||
free(devicepp_kv);
|
||||
if (intf_name)
|
||||
free(intf_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int usb_device,
|
||||
unsigned int channels, unsigned int rate, unsigned int bits,
|
||||
unsigned int *device_kv, unsigned int stream_kv, unsigned int instance_kv,
|
||||
unsigned int *devicepp_kv, struct chunk_fmt fmt, bool haptics, char **intf_name,
|
||||
int intf_num, bool is_24_LE)
|
||||
{
|
||||
struct pcm_config config;
|
||||
struct pcm *pcm;
|
||||
struct mixer *mixer;
|
||||
char *buffer;
|
||||
int playback_path, playback_value;
|
||||
int size, index, ret = 0;
|
||||
int num_read;
|
||||
struct group_config *grp_config = NULL;
|
||||
struct device_config *dev_config = NULL;
|
||||
uint32_t miid = 0;
|
||||
struct usbAudioConfig cfg;
|
||||
uint8_t* payload = NULL;
|
||||
size_t payloadSize = 0;
|
||||
|
||||
grp_config = (struct group_config *) malloc(intf_num * sizeof(struct group_config));
|
||||
if (!grp_config) {
|
||||
printf("Failed to allocate memory for group config");
|
||||
return;
|
||||
}
|
||||
|
||||
dev_config = (struct device_config *) malloc(intf_num * sizeof(struct device_config));
|
||||
if (!dev_config) {
|
||||
printf("Failed to allocate memory for dev config");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.channels = fmt.num_channels;
|
||||
config.rate = fmt.sample_rate;
|
||||
config.period_size = 1024;
|
||||
config.period_count = 4;
|
||||
if (fmt.bits_per_sample == 32) {
|
||||
if (is_24_LE)
|
||||
config.format = PCM_FORMAT_S24_LE;
|
||||
else
|
||||
config.format = PCM_FORMAT_S32_LE;
|
||||
} else if (fmt.bits_per_sample == 24)
|
||||
config.format = PCM_FORMAT_S24_3LE;
|
||||
else if (fmt.bits_per_sample == 16)
|
||||
config.format = PCM_FORMAT_S16_LE;
|
||||
config.start_threshold = 0;
|
||||
config.stop_threshold = 0;
|
||||
config.silence_threshold = 0;
|
||||
|
||||
mixer = mixer_open(card);
|
||||
if (!mixer) {
|
||||
printf("Failed to open mixer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (haptics) {
|
||||
playback_path = HAPTICS;
|
||||
stream_kv = stream_kv ? stream_kv : HAPTICS_PLAYBACK;
|
||||
} else {
|
||||
playback_path = PLAYBACK;
|
||||
stream_kv = stream_kv ? stream_kv : PCM_LL_PLAYBACK;
|
||||
}
|
||||
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
if(intf_name[index] != NULL && strcmp(intf_name[index], "USB_AUDIO-RX") == 0) {
|
||||
dev_config[index].rate = rate;
|
||||
dev_config[index].ch = channels;
|
||||
dev_config[index].bits = bits;
|
||||
dev_config[index].format = PCM_FORMAT_INVALID;
|
||||
} else {
|
||||
ret = get_device_media_config(BACKEND_CONF_FILE, intf_name[index], &dev_config[index]);
|
||||
if (ret) {
|
||||
printf("Invalid input, entry not found for : %s\n", intf_name[index]);
|
||||
fclose(file);
|
||||
}
|
||||
if (dev_config[index].format != PCM_FORMAT_INVALID) {
|
||||
printf("Valid format from backend_conf %d\n", dev_config[index].format);
|
||||
/* Updating bitwitdh based on format to avoid mismatch between bitwidth
|
||||
* and format, as device bw will be used to configure MFC.
|
||||
*/
|
||||
dev_config[index].bits = get_pcm_bit_width(dev_config[index].format);
|
||||
}
|
||||
}
|
||||
printf("Backend %s rate ch bit fmt : %d, %d, %d %d\n", intf_name[index],
|
||||
dev_config[index].rate, dev_config[index].ch, dev_config[index].bits,
|
||||
dev_config[index].format);
|
||||
|
||||
/* set device/audio_intf media config mixer control */
|
||||
if (set_agm_device_media_config(mixer, intf_name[index], &dev_config[index])) {
|
||||
printf("Failed to set device media config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_audio_intf_metadata(mixer, intf_name[index], device_kv[index], playback_path,
|
||||
dev_config[index].rate, dev_config[index].bits, stream_kv)) {
|
||||
printf("Failed to set device metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
/* set audio interface metadata mixer control */
|
||||
if (set_agm_stream_metadata(mixer, device, stream_kv, PLAYBACK, STREAM_PCM,
|
||||
instance_kv)) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
/* Note: No common metadata as of now*/
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
if (devicepp_kv[index] != 0) {
|
||||
if (set_agm_streamdevice_metadata(mixer, device, stream_kv, PLAYBACK, STREAM_PCM, intf_name[index],
|
||||
devicepp_kv[index])) {
|
||||
printf("Failed to set pcm metadata\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
if (intf_name[index] != NULL && strcmp(intf_name[index], "USB_AUDIO-RX") == 0) {
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name[index], STREAM_PCM, DEVICE_HW_ENDPOINT_RX, &miid);
|
||||
if (ret == 0) {
|
||||
cfg.usb_token = usb_device << 16;
|
||||
cfg.svc_interval = 0;
|
||||
get_agm_usb_audio_config_payload(&payload, &payloadSize, miid, &cfg);
|
||||
|
||||
if (payloadSize) {
|
||||
ret = set_agm_device_custom_payload(mixer, intf_name[index], payload, payloadSize);
|
||||
} else {
|
||||
ret = -1;
|
||||
printf("set_agm_device_custom_payload failed\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
} else {
|
||||
printf("Failed to get miid for USB_AUDIO-TX\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* connect pcm stream to audio intf */
|
||||
if (connect_agm_audio_intf_to_stream(mixer, device, intf_name[index], STREAM_PCM, true)) {
|
||||
printf("Failed to connect pcm to audio interface\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
ret = agm_mixer_get_miid (mixer, device, intf_name[index], STREAM_PCM, PER_STREAM_PER_DEVICE_MFC, &miid);
|
||||
if (ret) {
|
||||
printf("MFC not present for this graph\n");
|
||||
} else {
|
||||
if (configure_mfc(mixer, device, intf_name[index], PER_STREAM_PER_DEVICE_MFC,
|
||||
STREAM_PCM, dev_config[index].rate, dev_config[index].ch,
|
||||
dev_config[index].bits, miid)) {
|
||||
printf("Failed to configure pspd mfc\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(intf_name[index], "VIRT-")) {
|
||||
if (get_group_device_info(BACKEND_CONF_FILE, intf_name[index], &grp_config[index]))
|
||||
goto err_close_mixer;
|
||||
|
||||
if (set_agm_group_device_config(mixer, intf_name[index], &grp_config[index])) {
|
||||
printf("Failed to set grp device config\n");
|
||||
goto err_close_mixer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pcm = pcm_open(card, device, PCM_OUT, &config);
|
||||
if (!pcm || !pcm_is_ready(pcm)) {
|
||||
printf("Unable to open PCM device %u (%s)\n",
|
||||
device, pcm_get_error(pcm));
|
||||
goto err_close_mixer;
|
||||
}
|
||||
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
if (strstr(intf_name[index], "VIRT-") || (device_kv[index] == SPEAKER) || (device_kv[index] == HANDSET)) {
|
||||
if (set_agm_group_mux_config(mixer, device, &grp_config[index], intf_name[index], dev_config[index].ch)) {
|
||||
printf("Failed to set grp device config\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
|
||||
buffer = malloc(size);
|
||||
if (!buffer) {
|
||||
printf("Unable to allocate %d bytes\n", size);
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
printf("Playing sample: %u ch, %u hz, %u bit\n", fmt.num_channels,
|
||||
fmt.sample_rate, fmt.bits_per_sample);
|
||||
|
||||
if (pcm_start(pcm) < 0) {
|
||||
printf("start error\n");
|
||||
goto err_close_pcm;
|
||||
}
|
||||
|
||||
/* catch ctrl-c to shutdown cleanly */
|
||||
signal(SIGINT, stream_close);
|
||||
|
||||
do {
|
||||
num_read = fread(buffer, 1, size, file);
|
||||
if (num_read > 0) {
|
||||
if (pcm_write(pcm, buffer, num_read)) {
|
||||
printf("Error playing sample\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!close && num_read > 0);
|
||||
|
||||
pcm_stop(pcm);
|
||||
/* disconnect pcm stream to audio intf */
|
||||
for (index = 0; index < intf_num; index++) {
|
||||
connect_agm_audio_intf_to_stream(mixer, device, intf_name[index], STREAM_PCM, false);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
err_close_pcm:
|
||||
pcm_close(pcm);
|
||||
err_close_mixer:
|
||||
if (payload) {
|
||||
free(payload);
|
||||
}
|
||||
if (dev_config)
|
||||
free(dev_config);
|
||||
if (grp_config)
|
||||
free(grp_config);
|
||||
mixer_close(mixer);
|
||||
}
|
10
qcom/opensource/agm/plugins/tinyalsa/test/agmtest.pc.in
Normal file
10
qcom/opensource/agm/plugins/tinyalsa/test/agmtest.pc.in
Normal file
@@ -0,0 +1,10 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: agmtest
|
||||
Description: agm test tool
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir}
|
||||
Cflags: -I${includedir}/agmtest
|
90
qcom/opensource/agm/plugins/tinyalsa/test/backend_conf.xml
Normal file
90
qcom/opensource/agm/plugins/tinyalsa/test/backend_conf.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!-- Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. -->
|
||||
<!-- -->
|
||||
<!-- Redistribution and use in source and binary forms, with or without -->
|
||||
<!-- modification, are permitted provided that the following conditions are -->
|
||||
<!-- met: -->
|
||||
<!-- * Redistributions of source code must retain the above copyright -->
|
||||
<!-- notice, this list of conditions and the following disclaimer. -->
|
||||
<!-- * Redistributions in binary form must reproduce the above -->
|
||||
<!-- copyright notice, this list of conditions and the following -->
|
||||
<!-- disclaimer in the documentation and/or other materials provided -->
|
||||
<!-- with the distribution. -->
|
||||
<!-- * Neither the name of The Linux Foundation nor the names of its -->
|
||||
<!-- contributors may be used to endorse or promote products derived -->
|
||||
<!-- from this software without specific prior written permission. -->
|
||||
<!-- -->
|
||||
<!-- THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -->
|
||||
<!-- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -->
|
||||
<!-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -->
|
||||
<!-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -->
|
||||
<!-- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -->
|
||||
<!-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -->
|
||||
<!-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -->
|
||||
<!-- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -->
|
||||
<!-- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -->
|
||||
<!-- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -->
|
||||
<!-- IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->
|
||||
<!-- -->
|
||||
<!-- Changes from Qualcomm Innovation Center are provided under the following license: -->
|
||||
<!-- Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. -->
|
||||
<!-- SPDX-License-Identifier: BSD-3-Clause-Clear -->
|
||||
|
||||
<config>
|
||||
<group_device name="TDM-LPAIF-RX-TERTIARY" rate="96000" ch="3" bits="16" slot_mask="7"/>
|
||||
<device name="TDM-LPAIF-RX-TERTIARY-VIRT-0" rate="96000" ch="2" bits="16" />
|
||||
<!-- Format support per backend is optional, we can provide pcm format to specify which format -->
|
||||
<!-- BE should be configured to. If format is provided, and bitwidth does not match the format,-->
|
||||
<!-- bitwidth will be overwritten based on format. -->
|
||||
<device name="CODEC_DMA-LPAIF_WSA-RX-0" rate="48000" ch="1" bits="16" format="PCM_FORMAT_S16_LE"/>
|
||||
<device name="CODEC_DMA-LPAIF_WSA-RX-1" rate="48000" ch="1" bits="16" />
|
||||
<device name="CODEC_DMA-LPAIF_RXTX-RX-0" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_AXI-RX-PRIMARY" rate="48000" ch="2" bits="16" />
|
||||
<device name="SLIM-DEV1-RX-0" rate="48000" ch="2" bits="16" />
|
||||
<device name="DISPLAY_PORT-RX" rate="48000" ch="2" bits="16" />
|
||||
<device name="USB_AUDIO-RX" rate="48000" ch="2" bits="16" />
|
||||
<device name="CODEC_DMA-LPAIF_RXTX-TX-3" rate="48000" ch="1" bits="16" />
|
||||
<device name="CODEC_DMA-LPAIF_VA-TX-0" rate="48000" ch="1" bits="16" />
|
||||
<device name="CODEC_DMA-LPAIF_VA-TX-1" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_AXI-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="SLIM-DEV1-TX-0" rate="48000" ch="1" bits="16" />
|
||||
<device name="USB_AUDIO-TX" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_AUD-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_AUD-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF-RX-TERTIARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF-TX-TERTIARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF-RX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF-TX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_AUD-RX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_AUD-TX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_RXTX-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_RXTX-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_RXTX-RX-0" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_VA-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_VA-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_WSA-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="MI2S-LPAIF_WSA-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF-RX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF-TX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_AUD-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_AUD-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_AUD-RX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_AUD-TX-SECONDARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF-RX-TERTIARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF-TX-TERTIARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_RXTX-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_RXTX-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_VA-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_VA-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_WSA-RX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_WSA-TX-PRIMARY" rate="48000" ch="1" bits="16" />
|
||||
<device name="TDM-LPAIF_AXI-TX-PRIMARY" rate="48000" ch="2" bits="16" />
|
||||
<device name="AUXPCM-LPAIF_AXI-TX-PRIMARY" rate="48000" ch="2" bits="16" />
|
||||
<device name="MI2S-LPAIF_AXI-RX-PRIMARY" rate="48000" ch="2" bits="16" />
|
||||
<device name="AUXPCM-LPAIF_AXI-RX-PRIMARY" rate="48000" ch="2" bits="16" />
|
||||
</config>
|
||||
|
53
qcom/opensource/agm/plugins/tinyalsa/test/configure.ac
Normal file
53
qcom/opensource/agm/plugins/tinyalsa/test/configure.ac
Normal file
@@ -0,0 +1,53 @@
|
||||
# Requires autoconf tool later than 2.61
|
||||
AC_PREREQ(2.69)
|
||||
# Initialize the agm plugin package version 1.0.0
|
||||
AC_INIT([agmtest],1.0.0)
|
||||
# Does not strictly follow GNU Coding standards
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
# Disables auto rebuilding of configure, Makefile.ins
|
||||
AM_MAINTAINER_MODE
|
||||
# Verifies the --srcdir is correct by checking for the path
|
||||
#AC_CONFIG_SRCDIR([test/agmplay.c])
|
||||
# defines some macros variable to be included by source
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AC_ARG_WITH([glib],
|
||||
AC_HELP_STRING([--with-glib],
|
||||
[enable glib, Build against glib. Use this when building for HLOS systems which use glib]))
|
||||
|
||||
if (test "x${with_glib}" = "xyes"); then
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||
AC_MSG_ERROR(GThread >= 2.16 is required))
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
|
||||
AC_MSG_ERROR(GLib >= 2.16 is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
|
||||
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
|
||||
|
||||
# Checks for libraries
|
||||
PKG_CHECK_MODULES([MMHEADERS], [mm-audio-headers])
|
||||
AC_SUBST([MMHEADERS_CFLAGS])
|
||||
|
||||
AC_ARG_WITH([openwrt],
|
||||
AS_HELP_STRING([use openwrt (default is no)]),
|
||||
[with_openwrt=$withval],
|
||||
[with_openwrt=no])
|
||||
AM_CONDITIONAL([BUILDSYSTEM_OPENWRT], [test "x${with_openwrt}" = "xyes"])
|
||||
|
||||
AC_CONFIG_FILES([ Makefile agmtest.pc ])
|
||||
AC_OUTPUT
|
36
qcom/opensource/agm/plugins/tinyalsa/test/gtest/Android.mk
Normal file
36
qcom/opensource/agm/plugins/tinyalsa/test/gtest/Android.mk
Normal file
@@ -0,0 +1,36 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := gtest_agm_test
|
||||
LOCAL_MODULE_OWNER := qti
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_VENDOR_MODULE := true
|
||||
|
||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-result
|
||||
LOCAL_CFLAGS += -DBACKEND_CONF_FILE=\"/vendor/etc/backend_conf.xml\"
|
||||
LOCAL_SRC_FILES := gtest_agm_test.cpp \
|
||||
../AgmPlayer.cpp \
|
||||
../RiffWaveParser.cpp \
|
||||
../ChunkParser.cpp \
|
||||
../PlaybackCommand.cpp \
|
||||
../PlaybackCommandParser.cpp
|
||||
|
||||
LOCAL_HEADER_LIBRARIES := \
|
||||
libagm_headers \
|
||||
libacdb_headers
|
||||
|
||||
#if android version is R, refer to qtitinyxx otherwise use upstream ones
|
||||
#This assumes we would be using AR code only for Android R and subsequent versions.
|
||||
ifneq ($(filter 11 R, $(PLATFORM_VERSION)),)
|
||||
LOCAL_SHARED_LIBRARIES += libqti-tinyalsa
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libtinyalsa
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES += \
|
||||
libagmmixer liblog libcutils libutils
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libgmock libgtest libgtest_main
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
** Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above
|
||||
** copyright notice, this list of conditions and the following
|
||||
** disclaimer in the documentation and/or other materials provided
|
||||
** with the distribution.
|
||||
** * Neither the name of The Linux Foundation nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** Changes from Qualcomm Innovation Center are provided under the following license:
|
||||
** Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
** SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <iostream>
|
||||
#include "../AgmPlayer.h"
|
||||
#include "../PlaybackCommandParser.h"
|
||||
#include "../MockAgmMixerWrapper.h"
|
||||
#include "../MockAgmPcmWrapper.h"
|
||||
|
||||
class ParserTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
riffWaveParser = new RiffWaveParser();
|
||||
chunkParser = new ChunkParser();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
delete riffWaveParser;
|
||||
delete chunkParser;
|
||||
}
|
||||
|
||||
std::ifstream file;
|
||||
HeaderParser* riffWaveParser;
|
||||
HeaderParser* chunkParser;
|
||||
};
|
||||
|
||||
TEST_F(ParserTest, RiffWavParserIsValidFail) {
|
||||
file.open("/sdcard/sample.m4a", std::ios::binary);
|
||||
if (!file) {
|
||||
std::cout << "please, push the sample.m4a file in /sdcard/ folder" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
riffWaveParser->parseHeader(file);
|
||||
EXPECT_FALSE(riffWaveParser->isValid());
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, RiffWavParserIsValidSuccess) {
|
||||
file.open("/sdcard/sample.wav", std::ios::binary);
|
||||
if (!file) {
|
||||
std::cout << "please, push the sample.wav file in /sdcard/ folder" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
riffWaveParser->parseHeader(file);
|
||||
EXPECT_TRUE(riffWaveParser->isValid());
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, ChunkParserParseHeaderSuccess) {
|
||||
ChunkFormat chunkFormat;
|
||||
|
||||
file.open("/sdcard/sample.wav", std::ios::binary);
|
||||
if (!file) {
|
||||
std::cout << "please, push the sample.wav file in /sdcard/ folder" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
riffWaveParser->parseHeader(file);
|
||||
EXPECT_EQ(true, riffWaveParser->isValid());
|
||||
|
||||
chunkParser->parseHeader(file);
|
||||
chunkFormat = chunkParser->getFormat();
|
||||
EXPECT_EQ(1, chunkFormat.audio_format);
|
||||
EXPECT_EQ(2, chunkFormat.num_channels);
|
||||
EXPECT_EQ(48000, chunkFormat.sample_rate);
|
||||
EXPECT_EQ(192000, chunkFormat.byte_rate);
|
||||
EXPECT_EQ(4, chunkFormat.block_align);
|
||||
EXPECT_EQ(16, chunkFormat.bits_per_sample);
|
||||
file.close();
|
||||
}
|
||||
|
||||
class PlaybackCommandParserTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
command = new char*[30];
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (command) {
|
||||
delete[] command;
|
||||
command = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void makeTestCommand() {
|
||||
memset(command, 0, sizeof(command));
|
||||
command[0] = "agmplay";
|
||||
command[1] = "/sdcard/48.wav";
|
||||
command[2] = "-d";
|
||||
command[3] = "100";
|
||||
command[4] = "-D";
|
||||
command[5] = "100";
|
||||
command[6] = "-num_intf";
|
||||
command[7] = "1";
|
||||
command[8] = "-i";
|
||||
command[9] = "TDM-LPAIF-RX-PRIMARY";
|
||||
command[10] = "-h";
|
||||
command[11] = "false";
|
||||
command[12] = "-dkv";
|
||||
command[13] = "0xA2000001";
|
||||
command[14] = "-skv";
|
||||
command[15] = "0";
|
||||
command[16] = "-ikv";
|
||||
command[17] = "1";
|
||||
command[18] = "-dppkv";
|
||||
command[19] = "0xAC000002";
|
||||
command[20] = "-is_24_LE";
|
||||
command[21] = "false";
|
||||
command[22] = "-c";
|
||||
command[23] = "2";
|
||||
command[24] = "-r";
|
||||
command[25] = "48000";
|
||||
command[26] = "-b";
|
||||
command[27] = "16";
|
||||
command[28] = "-usb_d";
|
||||
command[29] = "1";
|
||||
}
|
||||
|
||||
PlaybackCommandParser parser;
|
||||
char** command = nullptr;
|
||||
char **interfaceName = nullptr;
|
||||
unsigned int *device_kv = nullptr;
|
||||
unsigned int *devicepp_kv = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(PlaybackCommandParserTest, TestParseCommandLine) {
|
||||
makeTestCommand();
|
||||
parser.parseCommandLine(command);
|
||||
|
||||
device_kv = parser.getPlaybackCommand().getDeviceKeyVector();
|
||||
devicepp_kv = parser.getPlaybackCommand().getDeviceppKeyVector();
|
||||
interfaceName = parser.getPlaybackCommand().getInterfaceName();
|
||||
|
||||
EXPECT_EQ(100, parser.getPlaybackCommand().getCard());
|
||||
EXPECT_EQ(100, parser.getPlaybackCommand().getDevice());
|
||||
EXPECT_EQ(1, parser.getPlaybackCommand().getInterfaceNumber());
|
||||
EXPECT_STREQ("TDM-LPAIF-RX-PRIMARY", interfaceName[0]);
|
||||
EXPECT_FALSE(parser.getPlaybackCommand().getHaptics() );
|
||||
EXPECT_EQ(0xA2000001, *device_kv);
|
||||
EXPECT_EQ(0, parser.getPlaybackCommand().getStreamKeyVector());
|
||||
EXPECT_EQ(1, parser.getPlaybackCommand().getInstanceKeyVector());
|
||||
EXPECT_EQ(0xAC000002, *devicepp_kv);
|
||||
EXPECT_FALSE(parser.getPlaybackCommand().is24LE());
|
||||
EXPECT_EQ(2, parser.getPlaybackCommand().getChannel());
|
||||
EXPECT_EQ(48000, parser.getPlaybackCommand().getSampleRate());
|
||||
EXPECT_EQ(16, parser.getPlaybackCommand().getBitWidth());
|
||||
EXPECT_EQ(1, parser.getPlaybackCommand().getUsbDevice());
|
||||
}
|
||||
|
||||
class AgmPlayTestFixture : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
riffWaveParser = new RiffWaveParser();
|
||||
chunkParser = new ChunkParser();
|
||||
command = new char*[30];
|
||||
|
||||
file.open("/sdcard/sample.wav", std::ios::binary);
|
||||
if (!file) {
|
||||
std::cout << "please, push the sample.wav file in /sdcard/ folder" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
riffWaveParser->parseHeader(file);
|
||||
if (!riffWaveParser->isValid()) {
|
||||
std::cout << "It is not a riff/wave file" << std::endl;
|
||||
file.close();
|
||||
exit(1);
|
||||
}
|
||||
chunkParser->parseHeader(file);
|
||||
makeTestCommand();
|
||||
parser.parseCommandLine(command);
|
||||
agmPlayer = new AgmPlayer(&mockAgmMixer, &mockAgmPcm);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
delete agmPlayer;
|
||||
delete riffWaveParser;
|
||||
delete chunkParser;
|
||||
if (command) {
|
||||
delete[] command;
|
||||
command == nullptr;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void makeTestCommand() {
|
||||
memset(command, 0, sizeof(command));
|
||||
command[0] = "agmplay";
|
||||
command[1] = "/sdcard/48.wav";
|
||||
command[2] = "-d";
|
||||
command[3] = "100";
|
||||
command[4] = "-D";
|
||||
command[5] = "100";
|
||||
command[6] = "-i";
|
||||
command[7] = "TDM-LPAIF-RX-PRIMARY";
|
||||
command[8] = "-dkv";
|
||||
command[9] = "0xA2000001";
|
||||
}
|
||||
|
||||
char** command = nullptr;
|
||||
std::ifstream file;
|
||||
HeaderParser* riffWaveParser;
|
||||
HeaderParser* chunkParser;
|
||||
PlaybackCommandParser parser;
|
||||
AgmPlayer *agmPlayer;
|
||||
MockAgmMixerWrapper mockAgmMixer;
|
||||
MockAgmPcmWrapper mockAgmPcm;
|
||||
};
|
||||
|
||||
TEST_F(AgmPlayTestFixture, openMixerFail) {
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, setDeviceMediaConfigFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, setAudioInterfaceMetadataFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, setStreamConfigFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, setStreamDeviceMetadataFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, connectAudioInterfaceToStreamFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, configureMFCFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, configureMFC(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, setGroupConfigFail) {
|
||||
struct device_config deviceConfig;
|
||||
struct group_config groupConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, configureMFC(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getGroupConfig(testing::_))
|
||||
.WillOnce(testing::Return(groupConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setGroupConfig(testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, pcmOpenFail) {
|
||||
struct device_config deviceConfig;
|
||||
struct group_config groupConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, configureMFC(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getGroupConfig(testing::_))
|
||||
.WillOnce(testing::Return(groupConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setGroupConfig(testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmOpen(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, pcmStartFail) {
|
||||
struct device_config deviceConfig;
|
||||
struct group_config groupConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, configureMFC(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getGroupConfig(testing::_))
|
||||
.WillOnce(testing::Return(groupConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setGroupConfig(testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmOpen(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmFramesToBytes())
|
||||
.WillOnce(testing::Return(16384));
|
||||
EXPECT_CALL(mockAgmPcm, pcmStart())
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, pcmWriteFail) {
|
||||
struct device_config deviceConfig;
|
||||
struct group_config groupConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, configureMFC(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getGroupConfig(testing::_))
|
||||
.WillOnce(testing::Return(groupConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setGroupConfig(testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmOpen(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmFramesToBytes())
|
||||
.WillOnce(testing::Return(16384));
|
||||
EXPECT_CALL(mockAgmPcm, pcmStart())
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmWrite(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayTestFixture, playSampleSuccess) {
|
||||
struct device_config deviceConfig;
|
||||
struct group_config groupConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(deviceConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, connectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, configureMFC(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, getGroupConfig(testing::_))
|
||||
.WillOnce(testing::Return(groupConfig));
|
||||
EXPECT_CALL(mockAgmMixer, setGroupConfig(testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmOpen(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmFramesToBytes())
|
||||
.WillOnce(testing::Return(16384));
|
||||
EXPECT_CALL(mockAgmPcm, pcmStart())
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmWrite(testing::_, testing::_))
|
||||
.WillRepeatedly(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmStop())
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, disconnectAudioInterfaceToStream(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmPcm, pcmClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(0, agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
class AgmPlayUSBTestFixture : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
riffWaveParser = new RiffWaveParser();
|
||||
chunkParser = new ChunkParser();
|
||||
command = new char*[30];
|
||||
|
||||
file.open("/sdcard/sample.wav", std::ios::binary);
|
||||
if (!file) {
|
||||
std::cout << "please, push the sample.wav file in /sdcard/ folder" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
riffWaveParser->parseHeader(file);
|
||||
if (!riffWaveParser->isValid()) {
|
||||
std::cout << "It is not a riff/wave file" << std::endl;
|
||||
file.close();
|
||||
exit(1);
|
||||
}
|
||||
chunkParser->parseHeader(file);
|
||||
|
||||
makeTestCommand();
|
||||
parser.parseCommandLine(command);
|
||||
|
||||
agmPlayer = new AgmPlayer(&mockAgmMixer, &mockAgmPcm);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
delete agmPlayer;
|
||||
delete riffWaveParser;
|
||||
delete chunkParser;
|
||||
if (command) {
|
||||
delete[] command;
|
||||
command == nullptr;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void makeTestCommand() {
|
||||
memset(command, 0, sizeof(command));
|
||||
command[0] = "agmplay";
|
||||
command[1] = "/sdcard/48.wav";
|
||||
command[2] = "-d";
|
||||
command[3] = "100";
|
||||
command[4] = "-D";
|
||||
command[5] = "100";
|
||||
command[6] = "-i";
|
||||
command[7] = "USB_AUDIO-RX";
|
||||
command[8] = "-dkv";
|
||||
command[9] = "0xA2000001";
|
||||
}
|
||||
|
||||
char** command = nullptr;
|
||||
std::ifstream file;
|
||||
HeaderParser* riffWaveParser;
|
||||
HeaderParser* chunkParser;
|
||||
PlaybackCommandParser parser;
|
||||
AgmPlayer *agmPlayer;
|
||||
MockAgmMixerWrapper mockAgmMixer;
|
||||
MockAgmPcmWrapper mockAgmPcm;
|
||||
};
|
||||
|
||||
TEST_F(AgmPlayUSBTestFixture, setUSBDeviceMediaConfigFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
||||
|
||||
TEST_F(AgmPlayUSBTestFixture, setDeviceCustomPayloadFail) {
|
||||
struct device_config deviceConfig;
|
||||
ChunkFormat format = chunkParser->getFormat();
|
||||
PlaybackCommand command = parser.getPlaybackCommand();
|
||||
|
||||
EXPECT_CALL(mockAgmMixer, mixerOpen(testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceMediaConfig(testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setAudioInterfaceMetadata(testing::_, testing::_, testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamMetadata(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setStreamDeviceMetadata(testing::_, testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(0));
|
||||
EXPECT_CALL(mockAgmMixer, setDeviceCustomPayload(testing::_, testing::_, testing::_))
|
||||
.WillOnce(testing::Return(-1));
|
||||
EXPECT_CALL(mockAgmMixer, mixerClose())
|
||||
.WillOnce(testing::Return(0));
|
||||
|
||||
EXPECT_EQ(-1 , agmPlayer->playSample(file, format, command));
|
||||
}
|
Reference in New Issue
Block a user