blob: 248d336da034878028adb23ee87a1ce34bab6803 [file] [log] [blame]
Tim Yao5351d702020-01-20 16:56:42 -08001/*
wei.du2be69bd2023-02-25 22:53:29 +08002 * Copyright (C) 2021 Amlogic Corporation.
Tim Yao5351d702020-01-20 16:56:42 -08003 *
wei.du2be69bd2023-02-25 22:53:29 +08004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Tim Yao5351d702020-01-20 16:56:42 -08007 *
wei.du2be69bd2023-02-25 22:53:29 +08008 * http://www.apache.org/licenses/LICENSE-2.0
Tim Yao5351d702020-01-20 16:56:42 -08009 *
wei.du2be69bd2023-02-25 22:53:29 +080010 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Tim Yao5351d702020-01-20 16:56:42 -080015 */
16
wei.du2be69bd2023-02-25 22:53:29 +080017
Tim Yao5351d702020-01-20 16:56:42 -080018#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/mman.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <unistd.h>
25#include "audio_if.h"
jing.zhang1ac869f2022-01-17 16:20:38 +080026#include <signal.h>
Tim Yao5351d702020-01-20 16:56:42 -080027
28#define min(a, b) ((a) < (b) ? (a) : (b))
29#define WRITE_UNIT 4096
30
shu.zhang0d999582021-07-19 07:51:13 -040031enum audio_format {
32 FORMAT_PCM16 = 0,
33 FORMAT_PCM32,
34 FORMAT_DD,
35 FORMAT_MAT,
36 FORMAT_IEC61937,
37 FORMAT_AC4 = 5,
38 FORMAT_MP3,
39 FORMAT_AAC,
40 FORMAT_OGG,
41 FORMAT_FLAC,
wei.wang1476a9fa2023-07-17 06:20:31 +000042 FORMAT_TRUE_HD,
shu.zhang0d999582021-07-19 07:51:13 -040043 FORMAT_MAX
44};
Tim Yao5351d702020-01-20 16:56:42 -080045
shu.zhang0d999582021-07-19 07:51:13 -040046static int format_tab[] = {
47 AUDIO_FORMAT_PCM_16_BIT,
48 AUDIO_FORMAT_PCM_32_BIT,
49 AUDIO_FORMAT_AC3,
50 AUDIO_FORMAT_MAT,
51 AUDIO_FORMAT_IEC61937,
52 AUDIO_FORMAT_AC4,
53 AUDIO_FORMAT_MP3,
54 AUDIO_FORMAT_AAC,
55 AUDIO_FORMAT_VORBIS,
wei.wang1476a9fa2023-07-17 06:20:31 +000056 AUDIO_FORMAT_FLAC,
57 AUDIO_FORMAT_DOLBY_TRUEHD
shu.zhang0d999582021-07-19 07:51:13 -040058};
59
Tim Yao5351d702020-01-20 16:56:42 -080060static const char *format_str[] = {
shu.zhang0d999582021-07-19 07:51:13 -040061 "PCM_16",
62 "PCM_32",
63 "DOLBY DD/DD+",
64 "DOLBY MAT",
65 "IEC_61937",
66 "AC4",
67 "MP3",
68 "AAC",
69 "OGG",
wei.wang1476a9fa2023-07-17 06:20:31 +000070 "FLAC",
71 "TRUE_HD"
Tim Yao5351d702020-01-20 16:56:42 -080072};
73
74static int format_is_pcm(int format)
75{
76 return (format == FORMAT_PCM16) || (format == FORMAT_PCM32);
77}
78
79static unsigned char *fmap(const char *fn, int *size, int *fd)
80{
81 int fd_r, r;
82 struct stat st;
83 unsigned char *p;
84
85 fd_r = open(fn, O_RDWR);
86
87 if (fd_r < 0)
88 return NULL;
89
90 *fd = fd_r;
91 r = fstat(fd_r, &st);
92 *size = st.st_size;
93 return mmap(0, st.st_size, PROT_READ|PROT_EXEC, MAP_SHARED, fd_r, 0);
94}
95
96static void funmap(unsigned char *p, int size, int fd)
97{
98 if (p && size > 0)
99 munmap(p, size);
100 if (fd >= 0)
101 close(fd);
102}
103
haiyang.rene4f993c2024-02-23 07:57:56 +0000104int debug = 0;
105static void get_buffer_size(struct audio_stream_out *stream)
106{
107 int buffer_size = 0;
108 int buffer_latency = 0;
109 if (debug) {
110 buffer_size = stream->common.get_buffer_size(&(stream->common));
111 buffer_latency = stream->get_latency(stream);
112 printf("buffer_size: %d, buffer_latency: %d.", buffer_size, buffer_latency);
113 }
114}
115
jing.zhang1ac869f2022-01-17 16:20:38 +0800116int isstop = 0;
Tim Yao5351d702020-01-20 16:56:42 -0800117static int test_stream(struct audio_stream_out *stream, unsigned char *buf, int size)
118{
119 int ret;
120 int len = size;
121 unsigned char *data = buf;
122
123 ret = stream->common.standby(&stream->common);
124 if (ret) {
125 fprintf(stderr, "%s %d, ret:%x\n",
126 __func__, __LINE__, ret);
127 return -1;
128 }
129
130 ret = stream->set_volume(stream, 1.0f, 1.0f);
131 if (ret) {
132 fprintf(stderr, "%s %d, ret:%x\n", __func__, __LINE__, ret);
133 return -1;
134 }
135
136 while (len > 0) {
137 ssize_t s = stream->write(stream, data, min(len, WRITE_UNIT));
138 if (s < 0) {
139 fprintf(stderr, "stream writing error %d\n", s);
140 break;
141 }
jing.zhang1ac869f2022-01-17 16:20:38 +0800142 if (isstop) {
143 break;
144 }
145 printf("stream writing %d \n", s);
Tim Yao5351d702020-01-20 16:56:42 -0800146 len -= s;
147 data += s;
haiyang.rene4f993c2024-02-23 07:57:56 +0000148
149 get_buffer_size(stream);
Tim Yao5351d702020-01-20 16:56:42 -0800150 }
jing.zhang1ac869f2022-01-17 16:20:38 +0800151 isstop = 0;
Tim Yao5351d702020-01-20 16:56:42 -0800152 return 0;
153}
154
155static void test_output_stream(audio_hw_device_t *device, unsigned char *buf, int size, struct audio_config *config)
156{
157 struct audio_stream_out *stream;
158 int ret;
159
160 printf("open output speaker...\n");
161 ret = device->open_output_stream(device,
162 0, AUDIO_DEVICE_OUT_SPEAKER,
163 AUDIO_OUTPUT_FLAG_PRIMARY, config,
164 &stream, NULL);
165 if (ret) {
166 printf("fail\n");
167 return;
168 } else {
169 printf("success\n");
170 }
171
172 test_stream(stream, buf, size);
173
174 printf("close output speaker...\n");
175 device->close_output_stream(device, stream);
176}
jing.zhang1ac869f2022-01-17 16:20:38 +0800177void handler_halplay(int sig)
178{
179 isstop=1;
180 while (isstop != 1);
181 printf("\n handler_halplay...\n");
182}
Tim Yao5351d702020-01-20 16:56:42 -0800183int main(int argc, char **argv)
184{
185 audio_hw_device_t *device;
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800186 int ret, c = -1, format = FORMAT_MAX, ch = 0, sr = 0, help = 0;
Tim Yao5351d702020-01-20 16:56:42 -0800187 struct audio_config config;
188 const char *fn = NULL;
189 int size = 0;
190 unsigned char *buf;
191 int fd = -1;
192
193 if (argc == 1) {
haiyang.rene4f993c2024-02-23 07:57:56 +0000194 printf("Usage: halplay -f <format> -c <channel number> -r <sample rate> -d <debug flag> <filename> \n");
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800195 printf("more param Info: halplay -h\n");
Tim Yao5351d702020-01-20 16:56:42 -0800196 return 0;
197 }
198
haiyang.rene4f993c2024-02-23 07:57:56 +0000199 while ((c = getopt(argc, argv, "f:c:r:d:h")) != -1) {
Tim Yao5351d702020-01-20 16:56:42 -0800200 switch (c) {
201 case 'f':
202 format = atoi(optarg);
203 break;
204 case 'c':
205 ch = atoi(optarg);
206 break;
207 case 'r':
208 sr = atoi(optarg);
209 break;
haiyang.rene4f993c2024-02-23 07:57:56 +0000210 case 'd':
211 debug = atoi(optarg);
212 break;
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800213 case 'h':
214 help = 1;
215 break;
Tim Yao5351d702020-01-20 16:56:42 -0800216 case '?':
217 fprintf(stderr, "Error in an argument.\n");
218 return -1;
219 default:
220 return -1;
221 }
222 }
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800223 if (help == 1) {
haiyang.rene4f993c2024-02-23 07:57:56 +0000224 printf("Usage: halplay -f <format> -c <channel number> -r <sample rate> -d <debug flag> <filename>\n");
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800225 printf("\n-h, help\n");
226 printf("-f, sample format\n");
227 printf("-c, channels\n");
228 printf("-r, sample rate\n");
wei.wang1476a9fa2023-07-17 06:20:31 +0000229 printf("Recognized sample formats are: 0:PCM16 1:PCM32 2:DD 3:MAT 4:IEC61937 5:AC4 6:MP3 7:AAC 8:OGG 9:FLAC 10:true-hd\n");
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800230 printf("Some of these may not be available on selected format\n");
231 printf("the available params for PCM16 and PCM32 are:\n");
232 printf("-c 1,2,6,8\n");
233 printf("-r 32000,44100,48000\n");
haiyang.rene4f993c2024-02-23 07:57:56 +0000234 printf("-d debug flag: 1/0\n");
zhaopeng.yanb37dff62022-04-28 11:04:30 +0800235 return 0;
236 }
Tim Yao5351d702020-01-20 16:56:42 -0800237 if (optind < argc) {
238 fn = argv[optind];
239 }
240
241 if (!fn) {
242 fprintf(stderr, "No file name specified\n");
243 return -1;
244 }
245
246 if ((format < 0) || (format >= FORMAT_MAX)) {
247 int i;
248 fprintf(stderr, "Wrong format, valid format:\n");
249 for (i = 0; i < FORMAT_MAX; i++)
250 fprintf(stderr, "\t%d: %s\n", i, format_str[i]);
251 return -1;
252 }
253
254 if (format_is_pcm(format)) {
255 if ((ch < 1) || (ch > 8)) {
256 fprintf(stderr, "Wrong channel number, valid range [1-8]\n");
257 return -1;
258 }
259 if ((sr != 32000) && (sr != 44100) && (sr != 48000)) {
260 fprintf(stderr, "Invalid sample rate, valid options [32000, 44100, 48000]\n");
261 return -1;
262 }
263 if ((ch != 1) && (ch != 2) && (ch != 6) && (ch != 8)) {
264 fprintf(stderr, "Invalid channel number, valid options [1, 2, 6, 8]\n");
265 return -1;
266 }
267 }
268
269 ret = audio_hw_load_interface(&device);
270 if (ret) {
271 fprintf(stderr, "%s %d error:%d\n", __func__, __LINE__, ret);
272 return ret;
273 }
274 printf("hw version: %x\n", device->common.version);
275 printf("hal api version: %x\n", device->common.module->hal_api_version);
276 printf("module id: %s\n", device->common.module->id);
277 printf("module name: %s\n", device->common.module->name);
278
279 if (device->get_supported_devices) {
280 uint32_t support_dev = 0;
281 support_dev = device->get_supported_devices(device);
282 printf("supported device: %x\n", support_dev);
283 }
284
285 int inited = device->init_check(device);
286 if (inited) {
287 printf("device not inited, quit\n");
288 goto exit;
289 }
290
291 buf = fmap(fn, &size, &fd);
292 if (!buf) {
293 fprintf(stderr, "Error, cannot open input file\n");
294 goto exit;
295 }
296
297 /* set audio config */
298 memset(&config, 0, sizeof(config));
299
shu.zhang0d999582021-07-19 07:51:13 -0400300 switch (format) {
301 case FORMAT_PCM16:
302 case FORMAT_PCM32:
303 config.sample_rate = sr;
304 switch (ch) {
305 case 1:
306 config.channel_mask = AUDIO_CHANNEL_OUT_MONO;
307 break;
308 case 2:
309 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
310 break;
311 case 6:
312 config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
313 break;
314 case 8:
315 config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
316 break;
317 default:
318 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
319 break;
320 }
321 break;
322
323 case FORMAT_DD:
324 case FORMAT_MAT:
325 case FORMAT_IEC61937:
326 case FORMAT_AC4:
327 config.sample_rate = 48000;
328 config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
329 break;
330
331 case FORMAT_MP3:
332 case FORMAT_AAC:
333 case FORMAT_OGG:
334 case FORMAT_FLAC:
335 config.sample_rate = sr;
336 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
337 break;
wei.wang1476a9fa2023-07-17 06:20:31 +0000338 case FORMAT_TRUE_HD:
339 config.sample_rate = sr;
340 switch (ch) {
341 case 8:
342 config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
343 break;
344 default:
345 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
346 break;
347 }
348 break;
shu.zhang0d999582021-07-19 07:51:13 -0400349
350 default:
351 break;
Tim Yao5351d702020-01-20 16:56:42 -0800352 }
shu.zhang0d999582021-07-19 07:51:13 -0400353
Tim Yao5351d702020-01-20 16:56:42 -0800354 config.format = format_tab[format];
jing.zhang1ac869f2022-01-17 16:20:38 +0800355 signal(SIGINT, handler_halplay);
Tim Yao5351d702020-01-20 16:56:42 -0800356 test_output_stream(device, buf, size, &config);
357
358 funmap(buf, size, fd);
359
360exit:
361 audio_hw_unload_interface(device);
362 return 0;
363}