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