Skip to content

Commit

Permalink
tinycompress: Add application for accel operation
Browse files Browse the repository at this point in the history
This 'caccel' applicaton is a demo to show how to
call the new introduced accel interface.

The kernel patch is:
ALSA: compress_offload: introduce accel operation mode

As there is conflict when using the API of alsa-lib,
add alsa_wrap file to separate the header files:
alsa/asoundlib.h
sound/asound.h

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
  • Loading branch information
TE-N-ShengjiuWang committed Oct 24, 2024
1 parent f4f26f5 commit 89f4299
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/utils/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
bin_PROGRAMS = cplay crecord
bin_PROGRAMS = cplay crecord caccel

cplay_SOURCES = cplay.c wave.c
crecord_SOURCES = crecord.c wave.c
caccel_SOURCES = caccel.c wave.c alsa_wrap.c

cplay_CFLAGS = -I$(top_srcdir)/include
crecord_CFLAGS = -I$(top_srcdir)/include
caccel_CFLAGS = -I$(top_srcdir)/include


cplay_LDADD = $(top_builddir)/src/lib/libtinycompress.la
crecord_LDADD = $(top_builddir)/src/lib/libtinycompress.la
caccel_LDADD = $(top_builddir)/src/lib/libtinycompress.la -lasound
28 changes: 28 additions & 0 deletions src/utils/alsa_wrap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause)

#include <alsa/asoundlib.h>

snd_pcm_format_t alsa_snd_pcm_format_value(const char *name)
{
return snd_pcm_format_value(name);
}

int alsa_snd_pcm_format_physical_width(snd_pcm_format_t format)
{
return snd_pcm_format_physical_width(format);
}

int alsa_snd_pcm_format_width(snd_pcm_format_t format)
{
return snd_pcm_format_width(format);
}

int alsa_snd_pcm_format_linear(snd_pcm_format_t format)
{
return snd_pcm_format_linear(format);
}

int alsa_snd_pcm_format_signed(snd_pcm_format_t format)
{
return snd_pcm_format_signed(format);
}
12 changes: 12 additions & 0 deletions src/utils/alsa_wrap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause) */

#ifndef __ALSA_WRAP_API_H
#define __ALSA_WRAP_API_H

snd_pcm_format_t alsa_snd_pcm_format_value(const char *name);
int alsa_snd_pcm_format_physical_width(snd_pcm_format_t format);
int alsa_snd_pcm_format_width(snd_pcm_format_t format);
int alsa_snd_pcm_format_linear(snd_pcm_format_t format);
int alsa_snd_pcm_format_signed(snd_pcm_format_t format);
#endif

310 changes: 310 additions & 0 deletions src/utils/caccel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
// SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause)
/*
* Copyright 2024 NXP
*/

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

#include "sound/compress_params.h"
#include "sound/compress_offload.h"
#include "tinycompress/tinywave.h"

#include "alsa_wrap.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define DMA_BUF_SIZE 4096
#define MAP_BUF_SIZE (512 * 1024)

static int verbose;

struct audio_info {
unsigned int card;
unsigned int device;
char *infile;
char *outfile;
unsigned int channels;
unsigned int in_rate;
unsigned short in_samplebits;
unsigned short in_blockalign;
unsigned int out_rate;
unsigned short out_samplebits;
unsigned short out_blockalign;
snd_pcm_format_t in_format;
snd_pcm_format_t out_format;
unsigned int in_dmabuf_size;
};

static void usage(void)
{
fprintf(stderr, "usage: caccel [OPTIONS]\n"
"-c\tcard number\n"
"-d\tdevice node\n"
"-i\tinput wave file\n"
"-o\toutput wave file\n"
"-r\toutput rate\n"
"-f\toutput format\n"
"-b\tbuffer size\n"
"-v\tverbose mode\n"
"-h\tPrints this help list\n\n"
"Example:\n"
"\tcmemtomem -c 1 -d 2 -i input.wav -o output.wav\n"
"Valid codec: SRC\n");
}

static int parse_arguments(int argc, const char *argv[], struct audio_info *info)
{
int c, option_index;
static const char short_options[] = "hvc:d:r:i:o:f:";
static const struct option long_options[] = {
{"help", 0, 0, 'h'},
{"verbose", 0, 0, 'v'},
{"card", 1, 0, 'c'},
{"device", 1, 0, 'd'},
{"inFile", 1, 0, 'i'},
{"outFile", 1, 0, 'o'},
{"outRate", 1, 0, 'r'},
{"outFormat", 1, 0, 'f'},
{0, 0, 0, 0}
};

if (argc < 3)
usage();

while ((c = getopt_long(argc, (char * const*)argv, short_options,
long_options, &option_index)) != -1) {
switch (c) {
case 'c':
info->card = strtol(optarg, NULL, 0);
break;
case 'd':
info->device = strtol(optarg, NULL, 0);
break;
case 'i':
info->infile = optarg;
break;
case 'o':
info->outfile = optarg;
break;
case 'r':
info->out_rate = strtol(optarg, NULL, 0);
break;
case 'f':
info->out_format = alsa_snd_pcm_format_value(optarg);
break;
case 'h':
usage();
exit(EXIT_FAILURE);
case 'v':
verbose = 1;
break;
default:
fprintf(stderr, "Unknown Command -%c\n", c);
exit(EXIT_FAILURE);
}
}

return 0;
}

int main(int argc, const char *argv[])
{
struct wave_header in_header;
struct wave_header out_header;
struct audio_info info;
size_t read, written;
struct snd_compr_caps caps;
struct snd_compr_codec_caps codec_caps = {};
struct snd_compr_params params;
struct snd_compr_task task = {};
struct snd_compr_task_status status = {};
FILE *fd_dst = NULL;
FILE *fd_src = NULL;
void *bufin_start;
void *bufout_start;
char fn[256];
int fd_accel;
int length = 0;
int err = 0;

verbose = 0;
memset(&info, 0, sizeof(struct audio_info));

if (parse_arguments(argc, argv, &info) != 0)
return -1;

if (info.out_rate == 0) {
fprintf(stderr, "invalid output rate %d\n", info.out_rate);
return -1;
}

snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", info.card, info.device);

fd_accel = open(fn, O_RDWR);
if (fd_accel < 0) {
fprintf(stderr, "Unable to open device %d\n", fd_accel);
return -1;
}

fd_dst = fopen(info.outfile, "wb+");
if (fd_dst <= 0) {
fprintf(stderr, "output file not found\n");
goto err_dst_not_found;
}

fd_src = fopen(info.infile, "r");
if (fd_src <= 0) {
fprintf(stderr, "input file not found\n");
goto err_src_not_found;
}

read = fread(&in_header, 1, sizeof(in_header), fd_src);
if (read != sizeof(in_header)) {
fprintf(stderr, "Unable to read header\n");
goto end_header_read;
}

if (parse_wave_header(&in_header, &info.channels, &info.in_rate,
(unsigned int *)&info.in_format) == -1) {
fprintf(stderr, "Unable to parse header\n");
goto end_header_read;
}

info.in_blockalign = info.channels * in_header.fmt.samplebits / 8;
info.in_dmabuf_size = (DMA_BUF_SIZE / info.in_blockalign) * info.in_blockalign;

if (info.out_format == 0)
info.out_format = SNDRV_PCM_FORMAT_S16_LE;

info.out_samplebits = alsa_snd_pcm_format_width(info.out_format);
init_wave_header(&out_header, info.channels, info.out_rate, info.out_samplebits);

written = fwrite(&out_header, 1, sizeof(out_header), fd_dst);
if (written != sizeof(out_header)) {
fprintf(stderr, "Error writing output file header: %s\n",
strerror(errno));
goto end_header_read;
}

err = ioctl(fd_accel, SNDRV_COMPRESS_GET_CAPS, &caps);
if (err < 0) {
fprintf(stderr, "Error getting caps %d\n", err);
goto end_header_read;
}

codec_caps.codec = SND_AUDIOCODEC_PCM;
err = ioctl(fd_accel, SNDRV_COMPRESS_GET_CODEC_CAPS, &codec_caps);
if (err < 0) {
fprintf(stderr, "Error getting codec caps %d\n", err);
goto end_header_read;
}

params.buffer.fragment_size = DMA_BUF_SIZE;
params.buffer.fragments = 1;
params.codec.id = SND_AUDIOCODEC_PCM;
params.codec.ch_in = info.channels;
params.codec.ch_out = info.channels;
params.codec.format = info.in_format;
params.codec.sample_rate = info.in_rate;
params.codec.pcm_format = info.out_format;
params.codec.options.src_d.out_sample_rate = info.out_rate;

err = ioctl(fd_accel, SNDRV_COMPRESS_SET_PARAMS, &params);
if (err < 0) {
fprintf(stderr, "Error setting params %d\n", err);
goto end_header_read;
}

err = ioctl(fd_accel, SNDRV_COMPRESS_TASK_CREATE, &task);
if (err < 0) {
fprintf(stderr, "Error creating task %d\n", err);
goto end_header_read;
}

bufin_start = mmap(NULL, MAP_BUF_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, task.input_fd, 0);
if (bufin_start == MAP_FAILED) {
fprintf(stderr, "Error mapping input buffer\n");
goto end_mmap_in;
}
memset(bufin_start, 0, MAP_BUF_SIZE);

bufout_start = mmap(NULL, MAP_BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
task.output_fd, 0);
if (bufout_start == MAP_FAILED) {
fprintf(stderr, "Error mapping output buffer\n");
goto end_mmap_out;
}
memset(bufout_start, 0, MAP_BUF_SIZE);

if (verbose)
printf("conversion is started\n");

status.seqno = task.seqno;

do {

read = fread(bufin_start, 1, info.in_dmabuf_size, fd_src);
if (read <= 0)
break;

task.input_size = read;

if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_START, &task) < 0) {
fprintf(stderr, "Error starting task\n");
goto end_process_err;
}

if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_STOP, &task.seqno) < 0) {
fprintf(stderr, "Error stopping task\n");
goto end_process_err;
}

if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_STATUS, &status) < 0) {
fprintf(stderr, "Error getting task status\n");
goto end_process_err;
}

written = fwrite(bufout_start, 1, status.output_size, fd_dst);
if (written != (size_t)status.output_size) {
fprintf(stderr, "Error writing output file: %s\n",
strerror(errno));
goto end_process_err;
}

} while (read > 0);

fseek(fd_dst, 0L, SEEK_END);
length = ftell(fd_dst);
size_wave_header(&out_header, length - sizeof(out_header));
fseek(fd_dst, 0L, SEEK_SET);
fwrite(&out_header, 1, sizeof(out_header), fd_dst);

if (verbose)
printf("Conversion is finished\n");

end_process_err:
munmap(bufout_start, MAP_BUF_SIZE);
end_mmap_out:
munmap(bufin_start, MAP_BUF_SIZE);
end_mmap_in:
if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_FREE, &task.seqno) < 0)
fprintf(stderr, "Error freeing task\n");
end_header_read:
fclose(fd_src);
err_src_not_found:
fclose(fd_dst);
err_dst_not_found:
close(fd_accel);
return err;
}

0 comments on commit 89f4299

Please sign in to comment.