blob: 7bcadcabef9eec07870f5fffec81c1d8dc041988 [file] [log] [blame]
Tim Yao14cb94e2020-05-12 10:28:05 -07001
2#include <string.h>
3#include <fcntl.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <pthread.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <sys/stat.h>
13#include <sys/ioctl.h>
14#include <sys/poll.h>
15#include <sys/time.h>
16
17//#include</linux/amlogic/cec_common.h>
18#include "hdmi_tx_cec_20.h"
19#include "data.h"
20#include "audio_if.h"
21
22
23#define DEV_CEC "/dev/cec"
24static int Cec_fd = 0;
25#define HDR 0
26#define OPCODE 1
27#define OPERAND 2
28
29#define CEC_MSG_HDR_BROADCAST 0x0F
30#define CEC_MSG_HDR 0x05
31#define INITIATE_ARC 0XC0
32#define REPORT_ARC_INITIATED 0XC1
33#define REPORT_ARC_TERMINATED 0XC2
34#define REQUEST_ARC_INITIATION 0XC3
35#define REQUEST_ARC_TERMINATION 0XC4
36#define TERMINATE_ARC 0XC5
37char CEC_MSG_ARC_INITIATED[]={CEC_MSG_HDR,REPORT_ARC_INITIATED};
38
39static pthread_t CEC_Event_Thread;
40struct pollfd polling;
41static bool arc_not_initialised = true;
42static char cecmsg[16] ;
43static int stop =0;
44static char msg_to_send[16];
45
46/* Audio stuffs */
47
48
49#define TV_AUDIO_OUTPUT
50
51#ifdef TV_AUDIO_OUTPUT
52static struct audio_port_config source_;
53static struct audio_port_config sink_;
54static audio_patch_handle_t patch_h_;
55
56static void test_patch(audio_hw_device_t *device)
57{
58 int ret;
59 /* create mixer to device patch */
60 source_.id = 1;
61 source_.role = AUDIO_PORT_ROLE_SOURCE;
62 source_.type = AUDIO_PORT_TYPE_MIX;
63 source_.config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE |
64 AUDIO_PORT_CONFIG_FORMAT;
65 source_.sample_rate = 48000;
66 source_.format = AUDIO_FORMAT_PCM_16_BIT;
67
68 sink_.id = 2;
69 sink_.role = AUDIO_PORT_ROLE_SINK;
70 sink_.type = AUDIO_PORT_TYPE_DEVICE;
71 sink_.config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE |
72 AUDIO_PORT_CONFIG_FORMAT;
73 sink_.sample_rate = 48000;
74 sink_.format = AUDIO_FORMAT_PCM_16_BIT;
75 sink_.ext.device.type = AUDIO_DEVICE_OUT_HDMI_ARC;
76
77 printf("create mix --> ARC patch...");
78 ret = device->create_audio_patch(device, 1, &source_, 1, &sink_, &patch_h_);
79 if (ret) {
80 printf("fail ret:%d\n",ret);
81 } else {
82 printf("success\n");
83 }
84}
85
86static void destroy_patch(audio_hw_device_t *device)
87{
88 if (patch_h_) {
89 int ret;
90 printf("destroy patch...");
91 ret = device->release_audio_patch(device, patch_h_);
92 if (ret) {
93 printf("fail ret:%d\n",ret);
94 } else {
95 printf("success\n");
96 }
97 }
98}
99#endif
100static void test_vol(audio_hw_device_t *device, int gain)
101{
102 int ret;
103 float vol = 0;
104 ret = device->get_master_volume(device, &vol);
105 if (ret) {
106 printf("get_master_volume fail\n");
107 } else {
108 printf("cur master vol:%f\n", vol);
109 }
110 ret = device->set_master_volume(device, 0.5f);
111 if (ret) {
112 printf("set_master_volume fail\n");
113 } else {
114 printf("set master vol 0.5\n");
115 device->set_master_volume(device, vol);
116 }
117
118#ifdef TV_AUDIO_OUTPUT
119 {
120 struct audio_port_config config;
121
122 memset(&config, 0, sizeof(config));
123 config.id = 2;
124 config.role = AUDIO_PORT_ROLE_SINK;
125 config.type = AUDIO_PORT_TYPE_DEVICE;
126 config.config_mask = AUDIO_PORT_CONFIG_GAIN;
127 /* audio_hal use dB * 100 to keep the accuracy */
128 config.gain.values[0] = gain * 100;
129 printf("set gain to %ddB...\n", gain);
130 ret = device->set_audio_port_config(device, &config);
131 if (ret) {
132 printf("fail\n");
133 } else {
134 printf("success\n");
135 }
136 }
137#endif
138}
139
140#define WRITE_UNIT 4096
141#define min(a, b) ((a) < (b) ? (a) : (b))
142static int test_stream(struct audio_stream_out *stream)
143{
144 int i, ret;
145 int len;
146 unsigned char *data;
147
148 ret = stream->set_volume(stream, 1.0f, 1.0f);
149 if (ret) {
150 fprintf(stderr, "%s %d, ret:%x\n", __func__, __LINE__, ret);
151 return -1;
152 }
153
154 printf("Start output to audio HAL\n");
155 for (i = 0; i < 10; i++) {
156 data = wav_data;
157 len = sizeof(wav_data);
158 while (len > 0) {
159 ssize_t s = stream->write(stream, data, min(len, WRITE_UNIT));
160 if (s < 0) {
161 fprintf(stderr, "stream writing error %d\n", s);
162 break;
163 }
164
165 len -= s;
166 data += s;
167 }
168 }
169
170 return 0;
171}
172
173#define HDMI_ARC_OUTPUT_DD
174
175static void test_output_stream(audio_hw_device_t *device)
176{
177 int ret;
178 struct audio_config config;
179 struct audio_stream_out *stream;
180 char cmd[32];
181
182 memset(&config, 0, sizeof(config));
183 config.sample_rate = 48000;
184 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
185 config.format = AUDIO_FORMAT_PCM_16_BIT;
186
187 printf("Tell audio HAL HDMI ARC is connected\n");
188 ret = device->set_parameters(device, "connect=0x40000");
189 if (ret) {
190 fprintf(stderr, "set_parameters HDMI connected failed\n");
191 }
192
193#ifdef HDMI_ARC_OUTPUT_DD
194 printf("Set HDMI ARC output format to AC3\n");
195 ret = device->set_parameters(device, "hdmi_format=4");
196 if (ret) {
197 fprintf(stderr, "set_parameters failed\n");
198 }
199#else
200 printf("Set HDMI ARC output format to PCM\n");
201 ret = device->set_parameters(device, "hdmi_format=0");
202 if (ret) {
203 fprintf(stderr, "set_parameters failed\n");
204 }
205#endif
206
207#ifdef HDMI_ARC_OUTPUT_DD
208 /*
209 * The following set_parameters calling sequence is needed
210 * to meet the audio HAL internal checking for ARC output:
211 * 1. "HDMI ARC Switch" key is used for UI control switch to enable
212 * ARC output.
213 * 2. "connect" key is used to tell audio HAL the connection status
214 * 3. "speaker_mute" is also checked to make sure ARC output is
215 * effective.
216 */
217 printf("Report UI settings for HDMI ARC enabled\n");
218 ret = device->set_parameters(device, "HDMI ARC Switch=1");
219 if (ret) {
220 fprintf(stderr, "set_parameters failed\n");
221 }
222
223 printf("Report HDMI ARC is connected\n");
224 snprintf(cmd, sizeof(cmd), "connect=%d", AUDIO_DEVICE_OUT_HDMI_ARC);
225 ret = device->set_parameters(device, cmd);
226 if (ret) {
227 fprintf(stderr, "set_parameters failed\n");
228 }
229
230 printf("Mute speaker output\n");
231 ret = device->set_parameters(device, "speaker_mute=1");
232 if (ret) {
233 fprintf(stderr, "set_parameters failed\n");
234 }
235#endif
236
237 printf("open output to HDMI_ARC with direct mode...\n");
238 ret = device->open_output_stream(device,
239 0, AUDIO_DEVICE_OUT_HDMI_ARC,
240 AUDIO_OUTPUT_FLAG_PRIMARY | AUDIO_OUTPUT_FLAG_DIRECT, &config,
241 &stream, NULL);
242 if (ret) {
243 printf("fail\n");
244 return;
245 } else {
246 printf("success\n");
247 }
248
249 test_stream(stream);
250
251 printf("close output speaker...\n");
252 device->close_output_stream(device, stream);
253}
254
255void process_cec_msg(char * cec_msg,int len)
256{
257 int i=0;
258
259 switch (cec_msg[OPCODE]) {
260 case INITIATE_ARC :
261 printf("Got the Initiate ARC message Amplifeir requesting to start ARC\n");
262 arc_not_initialised = false;
263 write(Cec_fd,CEC_MSG_ARC_INITIATED,2);
264 printf("Sending the ARC initiated message to the Amplifier\n");
265 stop =1;
266 break;
267
268 case CEC_OC_GIVE_PHYSICAL_ADDRESS :
269 printf("CEC_OC_GIVE_PHYSICAL_ADDRESS\n");
270 msg_to_send[0] = CEC_MSG_HDR_BROADCAST;
271 msg_to_send[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS;
272 msg_to_send[2] = 0x00;
273 msg_to_send[3] = 0x00;
274 msg_to_send[4] = 0x00;
275 write(Cec_fd,msg_to_send,5);
276 printf("Sending CEC_OC_REPORT_PHYSICAL_ADDRESS\n");
277 break;
278 default:
279 {
280 printf("CEC msg is ");
281 for(i=0;i< len;i++) {
282 printf(" 0x%x ",cec_msg[i]);
283 }
284 }
285 printf("\n###################");
286 break;
287 }
288}
289
290void* CEC_event_read_fn (void *data)
291{
292 int timeout = -1;
293 unsigned int mask = 0;
294 int read_len =0;
295
296 polling.fd= Cec_fd;
297 polling.events = POLLIN;
298
299 while (!stop) {
300 mask = poll(&polling,1,timeout);
301
302 if (mask & POLLIN || mask & POLLRDNORM) {
303 read_len= read(Cec_fd, &cecmsg, 1);
304 process_cec_msg(cecmsg,read_len);
305 }
306 }
307}
308
309static void sighandler(int sig)
310{
311 printf("Interrupted by signal %d\n", sig);
312 stop= 1;
313 printf("sighandler! Done\n");
314}
315
316int main(int argc, char *argv[])
317{
318 char msg[16];
319 int ret=0;
320 audio_hw_device_t *device;
321 int test_earc = 0;
322
323 if (argc > 1) {
324 test_earc = atoi(argv[1]);
325 if (test_earc) {
326 printf("Test EARC output, CEC communicatin will be skipped\n");
327 }
328 }
329
330 if (!test_earc) {
331 Cec_fd = open (DEV_CEC, O_RDWR);
332
333 if (Cec_fd < 0) {
334 printf ("%s CEC_device opening returned %d",DEV_CEC);
335 return -1;
336 }
337
338 ret = pthread_create(&CEC_Event_Thread, NULL, CEC_event_read_fn, NULL);
339 if (ret) {
340 printf("Unable to create decoder event thread\n");
341 }
342
343 /* setup the signal handler for CTRL-C */
344 signal(SIGINT, sighandler);
345 /*kill -USR1 pid */
346 signal(SIGUSR1, sighandler);
347
348 ioctl(Cec_fd, CEC_IOC_SET_OPTION_SYS_CTRL, 0x8);
349
350 ioctl(Cec_fd, CEC_IOC_ADD_LOGICAL_ADDR, 0x0);
351 msg[HDR]=CEC_MSG_HDR;
352 msg[OPCODE]=REQUEST_ARC_INITIATION;
353 write(Cec_fd,msg,2);
354 printf("sending ARC initialisation \n");
355 }
356
357 ret = audio_hw_load_interface(&device);
358 if (ret) {
359 printf("%s %d error:%d\n", __func__, __LINE__, ret);
360 return ret;
361 }
362 printf("hw version: %x\n", device->common.version);
363 printf("hal api version: %x\n", device->common.module->hal_api_version);
364 printf("module id: %s\n", device->common.module->id);
365 printf("module name: %s\n", device->common.module->name);
366
367 if (device->get_supported_devices) {
368 uint32_t support_dev = 0;
369 support_dev = device->get_supported_devices(device);
370 printf("supported device: %x\n", support_dev);
371 }
372
373 int inited = device->init_check(device);
374 if (inited) {
375 printf("device not inited, quit\n");
376 goto exit;
377 }
378
379 if (!test_earc) {
380 while (!stop) {
381 if (arc_not_initialised) {
382 printf("TV sending Request ARC initialisation to Amplifier \n");
383 write(Cec_fd,msg,2);
384 }
385 sleep(1);
386 }
387 }
388
389 sleep(2);
390
391 #ifdef TV_AUDIO_OUTPUT
392 test_patch(device);
393 #endif
394
395 test_output_stream(device);
396
397 if (!test_earc) {
398 ret = pthread_join(CEC_Event_Thread, NULL);
399 if (ret != 0) {
400 printf("CEC_Event_Thread returned error\n");
401 }
402
403 ioctl(Cec_fd, CEC_IOC_CLR_LOGICAL_ADDR, 0x0);
404 ioctl(Cec_fd, CEC_IOC_SET_OPTION_SYS_CTRL, 0x0);
405
406 close(Cec_fd);
407 }
408
409 /* Audio clean up */
410#ifdef TV_AUDIO_OUTPUT
411 destroy_patch(device);
412#endif
413
414exit:
415 device->common.close(&device->common);
416 audio_hw_unload_interface(device);
417 return 0;
418
419}
420
421
422