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