1 /*
2 * Copyright (C) 2018 Knowles Electronics
3 *
4 * 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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * 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.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <signal.h>
21 #include <stdbool.h>
22 #include <time.h>
23 #include <errno.h>
24 #include <unistd.h>
25
26 #define LOG_TAG "ia_tunneling_hal_test"
27
28 #include <log/log.h>
29 #include "tunnel.h"
30 #include "conversion_routines.h"
31 #include <linux/mfd/adnc/iaxxx-system-identifiers.h>
32 #include <linux/mfd/adnc/iaxxx-tunnel-intf.h>
33
34
35
36 #define MAX_TUNNELS 32
37 #define BUF_SIZE 32768
38 #define MAX_FILE_PATH 256
39
40 #define DEFAULT_PATH "/data/data"
41 #define FILE_PREFIX "/tnl_op"
42 #define UNPARSED_OUTPUT_FILE "/unparsed_output"
43
44 struct raf_format_type {
45 uint16_t frameSizeInBytes; /*!< Frame length in bytes */
46 uint8_t encoding; /*!< Encoding */
47 uint8_t sampleRate; /*!< Sample rate */
48 };
49
50 struct raf_frame_type {
51 uint64_t timeStamp; /*!< Timestamp of the frame */
52 uint32_t seqNo; /*!< Optional sequence number of the frame */
53
54 struct raf_format_type format; /*!< Format information for the frame */
55 uint32_t data[0]; /*!< Start of the variable size payload.
56 It must start at 128 bit aligned address for all the frames */
57 };
58
59 volatile int capturing = 1;
60
sigint_handler(int sig __unused)61 void sigint_handler(int sig __unused) {
62 ALOGE("Interrupted, setting the exit condition");
63 capturing = 0;
64 }
65
66
parse_audio_tunnel_data(FILE * out_fp,unsigned char * buf_itr,int frame_sz_in_bytes)67 void parse_audio_tunnel_data(FILE *out_fp, unsigned char *buf_itr, int frame_sz_in_bytes) {
68 char q16_buf[BUF_SIZE]; // This can be smaller but by how much?
69 int frameSizeInWords = (frame_sz_in_bytes + 3) >> 2;
70
71 if (NULL == buf_itr || NULL == out_fp) {
72 ALOGE("%s: Buffer or file pointer is NULL", __func__);
73 return;
74 }
75
76 kst_float_to_q15_vector(q16_buf, buf_itr, frameSizeInWords);
77
78 fwrite(q16_buf, (frameSizeInWords * 2), 1, out_fp);
79 fflush(out_fp);
80 }
81
main(int argc,char * argv[])82 int main(int argc, char *argv[]) {
83 struct ia_tunneling_hal *thdl = NULL;
84 int err = 0;
85 FILE *out_fp[MAX_TUNNELS] = { NULL };
86 FILE *unp_out_fp = NULL;
87 int bytes_avail = 0, bytes_rem = 0;
88 int bytes_read = 0;
89 void *buf = NULL;
90 // The magic number is ROME in ASCII reversed. So we are looking for EMOR in the byte stream
91 const unsigned char magic_num[4] = {0x45, 0x4D, 0x4F, 0x52};
92 int i = 0;
93 bool valid_frame = true;
94 char filepath[MAX_FILE_PATH];
95 char filename[MAX_FILE_PATH];
96 int num_of_tunnels = 0;
97 int num_tunnel_params;
98 float timer_signal = 0;
99 timer_t timer_id;
100 int tunnel_src[MAX_TUNNELS] = { 0 };
101 int tunnel_mode[MAX_TUNNELS] = { 0 };
102 int tunnel_encode[MAX_TUNNELS];
103 int lastSeqNum[MAX_TUNNELS] = { 0 };
104 int notFirstFrame[MAX_TUNNELS] = { 0 };
105 int frameDropCount[MAX_TUNNELS] = { 0 };
106 uint64_t tunnel_time_stamps[MAX_TUNNELS] = { 0 };
107 unsigned char *frame_start, *buf_itr;
108 // Minimum bytes required is the magic number + tunnel id + reserved and crc + raf struct
109 int min_bytes_req = 4 + 2 + 6 + sizeof(struct raf_frame_type);
110 int instance;
111
112 if (argc < 5) {
113 ALOGE("USAGE: %s <instance number> <Number of tunnels> <Time in seconds> <Source End pt 1> <tnl mode> <encode fmt> <Source End pt 2> <tnl mode> <encode fmt>... <output path>", argv[0]);
114 return -EINVAL;
115 }
116
117 instance = strtol(argv[1], NULL, 0);
118 ALOGD("instance %d", instance);
119
120 num_of_tunnels = strtol(argv[2], NULL, 0);
121 ALOGD("Number of tunnels %d", num_of_tunnels);
122
123 timer_signal = strtof(argv[3], NULL);
124 ALOGD("tunnel out timer based req %f", timer_signal);
125 err = timer_create(CLOCK_MONOTONIC, NULL, &timer_id);
126 if (err != 0) {
127 ALOGE("Couldn't create timer: %s", strerror(errno));
128 return -EINVAL;
129 }
130
131 num_tunnel_params = num_of_tunnels * 3 + 4;
132 #ifdef FILENAME_ASSIGN
133 char filename_str_format[256] = {0};
134 bool is_specified_name = false;
135 bool is_specified_path= false;
136 for (int i = 0; i < argc ; i++) {
137 if (strncmp(argv[i], "-f", sizeof(char)*2) == 0) {
138 if ((i+1) < argc) {
139 snprintf(filename_str_format, sizeof(filename_str_format), "%s", argv[i+1]);
140 ALOGE("specify a output file name %s, argc i = %d, argv[%d] = %s", filename_str_format, i, i+1, argv[i+1]);
141 is_specified_name = true;
142 }
143 }
144 if (strncmp(argv[i], "-p", sizeof(char)*2) == 0) {
145 if ((i+1) < argc) {
146 snprintf(filepath, sizeof(filepath), "%s", argv[i+1]);
147 ALOGE("specify a output file path %s, argc i = %d, argv[%d] = %s", filepath, i, i+1, argv[i+1]);
148 is_specified_path = true;
149 }
150 }
151 }
152
153 if (is_specified_name || is_specified_path) {
154 int spec_number = 2 * ((int) is_specified_name + (int) is_specified_path);
155
156 if (argc != (num_tunnel_params + spec_number)) {
157 ALOGE("USAGE: %s <instance number> <Number of tunnels> <Sync Tunnel req> <Source End pt 1> <tnl mode> <encode fmt> <Source End pt 2> <tnl mode> <encode fmt>... [-f filename] [-p filepath]", argv[0]);
158 return -EINVAL;
159 }
160 else {
161 ALOGE("is_specified_name = TRUE");
162 }
163 } else {
164 if (argc != num_tunnel_params && argc != num_tunnel_params + 1) {
165 ALOGE("USAGE: %s <instance number> <Number of tunnels> <Sync Tunnel req> <Source End pt 1> <tnl mode> <encode fmt> <Source End pt 2> <tnl mode> <encode fmt>...", argv[0]);
166 return -EINVAL;
167 }
168 }
169 #else
170 if (argc != num_tunnel_params && argc != num_tunnel_params + 1) {
171 ALOGE("USAGE: %s <instance number> <Number of tunnels> <Sync Tunnel req> <Source End pt 1> <tnl mode> <encode fmt> <Source End pt 2> <tnl mode> <encode fmt>...", argv[0]);
172 return -EINVAL;
173 }
174 #endif /* FILENAME_ASSIGN */
175
176
177 for (i = 0; i < num_of_tunnels; i++) {
178 tunnel_src[i] = strtol(argv[i*3+4], NULL, 0);
179 tunnel_mode[i] = strtol(argv[i*3+5], NULL, 0);
180 tunnel_encode[i] = strtol(argv[i*3+6], NULL, 0);
181 ALOGD("Tunnel source 0x%x Tunnel mode %d Tunnel encode %d", tunnel_src[i], tunnel_mode[i], tunnel_encode[i]);
182 }
183
184 #ifdef FILENAME_ASSIGN
185 if (!is_specified_path) {
186 strcpy(filepath, DEFAULT_PATH);
187 }
188 #else
189 if (argc == num_tunnel_params) {
190 strcpy(filepath, DEFAULT_PATH);
191 } else {
192 strcpy(filepath, argv[argc-1]);
193 }
194 #endif
195 ALOGE("Output path %s", filepath);
196
197 thdl = ia_start_tunneling(0);
198 if (NULL == thdl) {
199 ALOGE("Failed to start tunneling");
200 goto exit;
201 }
202
203 for (i = 0; i < num_of_tunnels; i++) {
204 err = ia_enable_tunneling_source(thdl, tunnel_src[i], tunnel_mode[i], tunnel_encode[i]);
205 if (0 != err) {
206 ALOGE("Failed to enable tunneling for src_id %u mode %u encode %u", tunnel_src[i], tunnel_mode[i], tunnel_encode[i]);
207 goto exit;
208 }
209 }
210
211 buf = malloc(BUF_SIZE * 2);
212 if (NULL == buf) {
213 ALOGE("Failed to allocate memory to read buffer");
214 goto exit;
215 }
216
217 snprintf(filename, MAX_FILE_PATH, "%s%s", filepath, UNPARSED_OUTPUT_FILE);
218 unp_out_fp = fopen(filename, "wb");
219 if (NULL == unp_out_fp) {
220 ALOGE("Failed to open the file %s", filename);
221 goto exit;
222 }
223
224 signal(SIGINT, sigint_handler);
225
226 if (num_of_tunnels && timer_signal) {
227 struct itimerspec timer_spec;
228 uint64_t timer_ns = timer_signal * NS_PER_SEC;
229
230 signal(SIGALRM, sigint_handler);
231
232 memset(&timer_spec, 0, sizeof(timer_spec));
233 timer_spec.it_value.tv_sec = timer_ns / NS_PER_SEC;
234 timer_spec.it_value.tv_nsec = timer_ns % NS_PER_SEC;
235 timer_settime(timer_id, 0, &timer_spec, NULL);
236 ALOGD("timer_settime %ld %ld",
237 timer_spec.it_value.tv_sec,
238 timer_spec.it_value.tv_nsec);
239 }
240
241 unsigned short int tunnel_id;
242 unsigned short int tunl_src;
243 while (1) {
244 read_again:
245 if (0 == capturing) {
246 ALOGE("Time to bail from here");
247 break;
248 }
249
250 if (0 != bytes_avail) {
251 if (bytes_avail < 0) {
252 bytes_rem = 0;
253 } else {
254 bytes_rem = bytes_avail;
255 ALOGD("bytes_avail is %d", bytes_rem);
256 memcpy(buf, buf_itr, bytes_rem);
257 }
258 } else {
259 bytes_rem = 0;
260 }
261
262 // Ensure that we read BUF_SIZE always otherwise the kernel read will hang
263 bytes_avail = ia_read_tunnel_data (thdl,
264 (void *)((unsigned char *)buf + bytes_rem),
265 BUF_SIZE);
266 if (bytes_avail <= 0) {
267 ALOGE("Failed to read data from the tunnel :%d", bytes_avail);
268 break;
269 }
270
271 fwrite((void *)((unsigned char *)buf + bytes_rem), bytes_avail, 1, unp_out_fp);
272 fflush(unp_out_fp);
273
274 bytes_avail += bytes_rem; // update the available bytes with the previous reminder if any
275 ALOGD("bytes_avail is after read %d", bytes_avail);
276 buf_itr = (unsigned char *)buf;
277
278 do {
279 // Check for MagicNumber 0x454D4F52
280 if (buf_itr[0] != magic_num[0] || buf_itr[1] != magic_num[1] ||
281 buf_itr[2] != magic_num[2] || buf_itr[3] != magic_num[3]) {
282 ALOGE("Could not find the magic number, reading again");
283 ALOGE("buf_itr[0] %x buf_itr[1] %x buf_itr[2] %x buf_itr[3] %x ",
284 buf_itr[0], buf_itr[1], buf_itr[2], buf_itr[3]);
285 goto exit;
286 }
287 ALOGD("bytes_avail is after magic %d: prev :%d", bytes_avail, bytes_avail + 540);
288 // Bookmark the start of the frame
289 frame_start = buf_itr;
290
291 // Skip the magic number
292 buf_itr += 4;
293 bytes_avail -= 4;
294
295 // Read the tunnelID
296 tunnel_id = ((unsigned char) (buf_itr[0]) |
297 (unsigned char) (buf_itr[1]) << 8);
298
299 // Skip tunnelID
300 buf_itr += 2;
301 bytes_avail -= 2;
302
303 tunl_src = ((unsigned char) (buf_itr[0]) |
304 (unsigned char) (buf_itr[1]) << 8);
305
306 // Skip src id field and CRC - 6 bytes in total
307 buf_itr += 6;
308 bytes_avail -= 6;
309
310 valid_frame = true;
311 if (tunnel_id > MAX_TUNNELS) {
312 ALOGE("Invalid tunnel id %d", tunnel_id);
313 valid_frame = false;
314 }
315
316 struct raf_frame_type rft;
317 memcpy(&rft, buf_itr, sizeof(struct raf_frame_type));
318 if (true == valid_frame) {
319 if (NULL == out_fp[tunnel_id]) {
320 #ifdef FILENAME_ASSIGN
321 if (is_specified_name) {
322 snprintf(filename, 256, "%s/%s", filepath, filename_str_format);
323 } else if (TNL_ENC_OPAQUE == rft.format.encoding) {
324 #else
325 if (TNL_ENC_OPAQUE == rft.format.encoding) {
326 #endif /* FILENAME_ASSIGN */
327 snprintf(filename, MAX_FILE_PATH, "%s%sid%d-src0x%x-enc0x%x_client%d.raw", filepath, FILE_PREFIX, tunnel_id, tunl_src, rft.format.encoding, instance);
328 } else {
329 snprintf(filename, MAX_FILE_PATH, "%s%sid%d-src0x%x-enc0x%x_client%d.pcm", filepath, FILE_PREFIX, tunnel_id, tunl_src, rft.format.encoding, instance);
330 }
331 // Open the file to dump
332 out_fp[tunnel_id] = fopen(filename, "wb");
333 if (NULL == out_fp[tunnel_id]) {
334 ALOGE("ERROR: Failed to open the file %s", filename);
335 goto exit;
336 }
337 }
338 }
339
340 ALOGD("Tunnel id %d timestamp %llu", tunnel_id, rft.timeStamp);
341 tunnel_time_stamps[tunnel_id] = rft.timeStamp;
342
343 // Skip the raf_frame_type
344 buf_itr += sizeof(struct raf_frame_type);
345 bytes_avail -= sizeof(struct raf_frame_type);
346
347 if (bytes_avail < rft.format.frameSizeInBytes) {
348 ALOGD("Incomplete frame received bytes_avail %d framesize %d", bytes_avail, rft.format.frameSizeInBytes);
349 buf_itr = frame_start;
350 bytes_avail += min_bytes_req;
351 goto read_again;
352 }
353
354 if (true == valid_frame) {
355 ALOGD("@@@Tunnel id %d encoding %d", tunnel_id, rft.format.encoding);
356 if (TNL_ENC_AFLOAT == rft.format.encoding) {
357 parse_audio_tunnel_data(out_fp[tunnel_id], buf_itr, rft.format.frameSizeInBytes);
358 } else {
359 fwrite(buf_itr, rft.format.frameSizeInBytes, 1, out_fp[tunnel_id]);
360 }
361 }
362
363 /* Calculate the frame drop count */
364 if (notFirstFrame[tunnel_id]) {
365 frameDropCount[tunnel_id] += (rft.seqNo - lastSeqNum[tunnel_id] - 1);
366 }
367 lastSeqNum[tunnel_id] = rft.seqNo;
368 notFirstFrame[tunnel_id] = 1;
369 // Skip the data
370 buf_itr += rft.format.frameSizeInBytes;
371 bytes_avail -= rft.format.frameSizeInBytes;
372 /* For debugging the tunnel read errors or wrong magic numbers or bus errors*/
373 bytes_read += rft.format.frameSizeInBytes + min_bytes_req;
374 } while (bytes_avail > min_bytes_req);
375 }
376
377 exit:
378 for (i = 0; i < MAX_TUNNELS; i++) {
379 if (notFirstFrame[i]) {
380 ALOGE("drop count tunnel id %u: %u", i, frameDropCount[i]);
381 }
382 }
383 ALOGE("bytes_read so far %d", bytes_read);
384 if (buf) {
385 free(buf);
386 buf = NULL;
387 }
388
389 if (unp_out_fp) {
390 fflush(unp_out_fp);
391 fclose(unp_out_fp);
392 }
393
394 for (i = 0; i < MAX_TUNNELS; i++) {
395 if (out_fp[i]) {
396 fflush(out_fp[i]);
397 fclose(out_fp[i]);
398 }
399 }
400
401 for (i = 0; i < num_of_tunnels; i++) {
402 err = ia_disable_tunneling_source(thdl, tunnel_src[i], tunnel_mode[i], tunnel_encode[i]);
403 if (0 != err) {
404 ALOGE("Failed to disable tunneling for tunl_id %u src_id %u", i, tunnel_src[i]);
405 }
406 }
407
408 err = ia_stop_tunneling(thdl);
409 if (0 != err) {
410 ALOGE("Failed to stop tunneling");
411 }
412
413 timer_delete(timer_id);
414
415 return 0;
416 }
417