Skip to content

Commit 89f4299

Browse files
tinycompress: Add application for accel operation
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>
1 parent f4f26f5 commit 89f4299

4 files changed

Lines changed: 354 additions & 1 deletion

File tree

src/utils/Makefile.am

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
bin_PROGRAMS = cplay crecord
1+
bin_PROGRAMS = cplay crecord caccel
22

33
cplay_SOURCES = cplay.c wave.c
44
crecord_SOURCES = crecord.c wave.c
5+
caccel_SOURCES = caccel.c wave.c alsa_wrap.c
56

67
cplay_CFLAGS = -I$(top_srcdir)/include
78
crecord_CFLAGS = -I$(top_srcdir)/include
9+
caccel_CFLAGS = -I$(top_srcdir)/include
810

911

1012
cplay_LDADD = $(top_builddir)/src/lib/libtinycompress.la
1113
crecord_LDADD = $(top_builddir)/src/lib/libtinycompress.la
14+
caccel_LDADD = $(top_builddir)/src/lib/libtinycompress.la -lasound

src/utils/alsa_wrap.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause)
2+
3+
#include <alsa/asoundlib.h>
4+
5+
snd_pcm_format_t alsa_snd_pcm_format_value(const char *name)
6+
{
7+
return snd_pcm_format_value(name);
8+
}
9+
10+
int alsa_snd_pcm_format_physical_width(snd_pcm_format_t format)
11+
{
12+
return snd_pcm_format_physical_width(format);
13+
}
14+
15+
int alsa_snd_pcm_format_width(snd_pcm_format_t format)
16+
{
17+
return snd_pcm_format_width(format);
18+
}
19+
20+
int alsa_snd_pcm_format_linear(snd_pcm_format_t format)
21+
{
22+
return snd_pcm_format_linear(format);
23+
}
24+
25+
int alsa_snd_pcm_format_signed(snd_pcm_format_t format)
26+
{
27+
return snd_pcm_format_signed(format);
28+
}

src/utils/alsa_wrap.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause) */
2+
3+
#ifndef __ALSA_WRAP_API_H
4+
#define __ALSA_WRAP_API_H
5+
6+
snd_pcm_format_t alsa_snd_pcm_format_value(const char *name);
7+
int alsa_snd_pcm_format_physical_width(snd_pcm_format_t format);
8+
int alsa_snd_pcm_format_width(snd_pcm_format_t format);
9+
int alsa_snd_pcm_format_linear(snd_pcm_format_t format);
10+
int alsa_snd_pcm_format_signed(snd_pcm_format_t format);
11+
#endif
12+

src/utils/caccel.c

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
// SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause)
2+
/*
3+
* Copyright 2024 NXP
4+
*/
5+
6+
#include <errno.h>
7+
#include <fcntl.h>
8+
#include <getopt.h>
9+
#include <unistd.h>
10+
#include <stdint.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <sys/ioctl.h>
15+
#include <sys/mman.h>
16+
#include <sys/types.h>
17+
#include <unistd.h>
18+
19+
#include "sound/compress_params.h"
20+
#include "sound/compress_offload.h"
21+
#include "tinycompress/tinywave.h"
22+
23+
#include "alsa_wrap.h"
24+
25+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
26+
#define DMA_BUF_SIZE 4096
27+
#define MAP_BUF_SIZE (512 * 1024)
28+
29+
static int verbose;
30+
31+
struct audio_info {
32+
unsigned int card;
33+
unsigned int device;
34+
char *infile;
35+
char *outfile;
36+
unsigned int channels;
37+
unsigned int in_rate;
38+
unsigned short in_samplebits;
39+
unsigned short in_blockalign;
40+
unsigned int out_rate;
41+
unsigned short out_samplebits;
42+
unsigned short out_blockalign;
43+
snd_pcm_format_t in_format;
44+
snd_pcm_format_t out_format;
45+
unsigned int in_dmabuf_size;
46+
};
47+
48+
static void usage(void)
49+
{
50+
fprintf(stderr, "usage: caccel [OPTIONS]\n"
51+
"-c\tcard number\n"
52+
"-d\tdevice node\n"
53+
"-i\tinput wave file\n"
54+
"-o\toutput wave file\n"
55+
"-r\toutput rate\n"
56+
"-f\toutput format\n"
57+
"-b\tbuffer size\n"
58+
"-v\tverbose mode\n"
59+
"-h\tPrints this help list\n\n"
60+
"Example:\n"
61+
"\tcmemtomem -c 1 -d 2 -i input.wav -o output.wav\n"
62+
"Valid codec: SRC\n");
63+
}
64+
65+
static int parse_arguments(int argc, const char *argv[], struct audio_info *info)
66+
{
67+
int c, option_index;
68+
static const char short_options[] = "hvc:d:r:i:o:f:";
69+
static const struct option long_options[] = {
70+
{"help", 0, 0, 'h'},
71+
{"verbose", 0, 0, 'v'},
72+
{"card", 1, 0, 'c'},
73+
{"device", 1, 0, 'd'},
74+
{"inFile", 1, 0, 'i'},
75+
{"outFile", 1, 0, 'o'},
76+
{"outRate", 1, 0, 'r'},
77+
{"outFormat", 1, 0, 'f'},
78+
{0, 0, 0, 0}
79+
};
80+
81+
if (argc < 3)
82+
usage();
83+
84+
while ((c = getopt_long(argc, (char * const*)argv, short_options,
85+
long_options, &option_index)) != -1) {
86+
switch (c) {
87+
case 'c':
88+
info->card = strtol(optarg, NULL, 0);
89+
break;
90+
case 'd':
91+
info->device = strtol(optarg, NULL, 0);
92+
break;
93+
case 'i':
94+
info->infile = optarg;
95+
break;
96+
case 'o':
97+
info->outfile = optarg;
98+
break;
99+
case 'r':
100+
info->out_rate = strtol(optarg, NULL, 0);
101+
break;
102+
case 'f':
103+
info->out_format = alsa_snd_pcm_format_value(optarg);
104+
break;
105+
case 'h':
106+
usage();
107+
exit(EXIT_FAILURE);
108+
case 'v':
109+
verbose = 1;
110+
break;
111+
default:
112+
fprintf(stderr, "Unknown Command -%c\n", c);
113+
exit(EXIT_FAILURE);
114+
}
115+
}
116+
117+
return 0;
118+
}
119+
120+
int main(int argc, const char *argv[])
121+
{
122+
struct wave_header in_header;
123+
struct wave_header out_header;
124+
struct audio_info info;
125+
size_t read, written;
126+
struct snd_compr_caps caps;
127+
struct snd_compr_codec_caps codec_caps = {};
128+
struct snd_compr_params params;
129+
struct snd_compr_task task = {};
130+
struct snd_compr_task_status status = {};
131+
FILE *fd_dst = NULL;
132+
FILE *fd_src = NULL;
133+
void *bufin_start;
134+
void *bufout_start;
135+
char fn[256];
136+
int fd_accel;
137+
int length = 0;
138+
int err = 0;
139+
140+
verbose = 0;
141+
memset(&info, 0, sizeof(struct audio_info));
142+
143+
if (parse_arguments(argc, argv, &info) != 0)
144+
return -1;
145+
146+
if (info.out_rate == 0) {
147+
fprintf(stderr, "invalid output rate %d\n", info.out_rate);
148+
return -1;
149+
}
150+
151+
snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", info.card, info.device);
152+
153+
fd_accel = open(fn, O_RDWR);
154+
if (fd_accel < 0) {
155+
fprintf(stderr, "Unable to open device %d\n", fd_accel);
156+
return -1;
157+
}
158+
159+
fd_dst = fopen(info.outfile, "wb+");
160+
if (fd_dst <= 0) {
161+
fprintf(stderr, "output file not found\n");
162+
goto err_dst_not_found;
163+
}
164+
165+
fd_src = fopen(info.infile, "r");
166+
if (fd_src <= 0) {
167+
fprintf(stderr, "input file not found\n");
168+
goto err_src_not_found;
169+
}
170+
171+
read = fread(&in_header, 1, sizeof(in_header), fd_src);
172+
if (read != sizeof(in_header)) {
173+
fprintf(stderr, "Unable to read header\n");
174+
goto end_header_read;
175+
}
176+
177+
if (parse_wave_header(&in_header, &info.channels, &info.in_rate,
178+
(unsigned int *)&info.in_format) == -1) {
179+
fprintf(stderr, "Unable to parse header\n");
180+
goto end_header_read;
181+
}
182+
183+
info.in_blockalign = info.channels * in_header.fmt.samplebits / 8;
184+
info.in_dmabuf_size = (DMA_BUF_SIZE / info.in_blockalign) * info.in_blockalign;
185+
186+
if (info.out_format == 0)
187+
info.out_format = SNDRV_PCM_FORMAT_S16_LE;
188+
189+
info.out_samplebits = alsa_snd_pcm_format_width(info.out_format);
190+
init_wave_header(&out_header, info.channels, info.out_rate, info.out_samplebits);
191+
192+
written = fwrite(&out_header, 1, sizeof(out_header), fd_dst);
193+
if (written != sizeof(out_header)) {
194+
fprintf(stderr, "Error writing output file header: %s\n",
195+
strerror(errno));
196+
goto end_header_read;
197+
}
198+
199+
err = ioctl(fd_accel, SNDRV_COMPRESS_GET_CAPS, &caps);
200+
if (err < 0) {
201+
fprintf(stderr, "Error getting caps %d\n", err);
202+
goto end_header_read;
203+
}
204+
205+
codec_caps.codec = SND_AUDIOCODEC_PCM;
206+
err = ioctl(fd_accel, SNDRV_COMPRESS_GET_CODEC_CAPS, &codec_caps);
207+
if (err < 0) {
208+
fprintf(stderr, "Error getting codec caps %d\n", err);
209+
goto end_header_read;
210+
}
211+
212+
params.buffer.fragment_size = DMA_BUF_SIZE;
213+
params.buffer.fragments = 1;
214+
params.codec.id = SND_AUDIOCODEC_PCM;
215+
params.codec.ch_in = info.channels;
216+
params.codec.ch_out = info.channels;
217+
params.codec.format = info.in_format;
218+
params.codec.sample_rate = info.in_rate;
219+
params.codec.pcm_format = info.out_format;
220+
params.codec.options.src_d.out_sample_rate = info.out_rate;
221+
222+
err = ioctl(fd_accel, SNDRV_COMPRESS_SET_PARAMS, &params);
223+
if (err < 0) {
224+
fprintf(stderr, "Error setting params %d\n", err);
225+
goto end_header_read;
226+
}
227+
228+
err = ioctl(fd_accel, SNDRV_COMPRESS_TASK_CREATE, &task);
229+
if (err < 0) {
230+
fprintf(stderr, "Error creating task %d\n", err);
231+
goto end_header_read;
232+
}
233+
234+
bufin_start = mmap(NULL, MAP_BUF_SIZE, PROT_READ | PROT_WRITE,
235+
MAP_SHARED, task.input_fd, 0);
236+
if (bufin_start == MAP_FAILED) {
237+
fprintf(stderr, "Error mapping input buffer\n");
238+
goto end_mmap_in;
239+
}
240+
memset(bufin_start, 0, MAP_BUF_SIZE);
241+
242+
bufout_start = mmap(NULL, MAP_BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
243+
task.output_fd, 0);
244+
if (bufout_start == MAP_FAILED) {
245+
fprintf(stderr, "Error mapping output buffer\n");
246+
goto end_mmap_out;
247+
}
248+
memset(bufout_start, 0, MAP_BUF_SIZE);
249+
250+
if (verbose)
251+
printf("conversion is started\n");
252+
253+
status.seqno = task.seqno;
254+
255+
do {
256+
257+
read = fread(bufin_start, 1, info.in_dmabuf_size, fd_src);
258+
if (read <= 0)
259+
break;
260+
261+
task.input_size = read;
262+
263+
if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_START, &task) < 0) {
264+
fprintf(stderr, "Error starting task\n");
265+
goto end_process_err;
266+
}
267+
268+
if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_STOP, &task.seqno) < 0) {
269+
fprintf(stderr, "Error stopping task\n");
270+
goto end_process_err;
271+
}
272+
273+
if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_STATUS, &status) < 0) {
274+
fprintf(stderr, "Error getting task status\n");
275+
goto end_process_err;
276+
}
277+
278+
written = fwrite(bufout_start, 1, status.output_size, fd_dst);
279+
if (written != (size_t)status.output_size) {
280+
fprintf(stderr, "Error writing output file: %s\n",
281+
strerror(errno));
282+
goto end_process_err;
283+
}
284+
285+
} while (read > 0);
286+
287+
fseek(fd_dst, 0L, SEEK_END);
288+
length = ftell(fd_dst);
289+
size_wave_header(&out_header, length - sizeof(out_header));
290+
fseek(fd_dst, 0L, SEEK_SET);
291+
fwrite(&out_header, 1, sizeof(out_header), fd_dst);
292+
293+
if (verbose)
294+
printf("Conversion is finished\n");
295+
296+
end_process_err:
297+
munmap(bufout_start, MAP_BUF_SIZE);
298+
end_mmap_out:
299+
munmap(bufin_start, MAP_BUF_SIZE);
300+
end_mmap_in:
301+
if (ioctl(fd_accel, SNDRV_COMPRESS_TASK_FREE, &task.seqno) < 0)
302+
fprintf(stderr, "Error freeing task\n");
303+
end_header_read:
304+
fclose(fd_src);
305+
err_src_not_found:
306+
fclose(fd_dst);
307+
err_dst_not_found:
308+
close(fd_accel);
309+
return err;
310+
}

0 commit comments

Comments
 (0)