Files
2026-08-24 10:03:24 +08:00

322 lines
9.7 KiB
C

/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in below
* which is part of this source code package.
*
* Description: hdmisrc: Amlsrc Implementation
*/
// Copyright (C) 2019 Amlogic, Inc. All rights reserved.
//
// All information contained herein is Amlogic confidential.
//
// This software is provided to you pursuant to Software License
// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
// used only in accordance with the terms of this agreement.
//
// Redistribution and use in source and binary forms, with or without
// modification is strictly prohibited without prior written permission
// from Amlogic.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "mediactrl_common.h"
#include "mediactrl_log.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <ctype.h>
#include <pthread.h>
#include <signal.h>
#include <time.h>
#include "TvClientWrapper.h"
#define _GNU_SOURCE
#define HDMIRX_SERVER_SOCKET "/tmp/hdmi-rx0"
typedef struct {
int connect_socker_fd;
int listen_fd;
pthread_t t_socket_thread;
bool b_svctx_enable;
bool b_tv_released;
pthread_mutex_t tvclient_mutex;
bool b_tv_fake_stable;
}hdmi_rx_svc_t;
tv_source_input_t e_currentsource ;
static hdmi_rx_svc_t *g_t_svctx =NULL;
static int client_sockfd = -1;
static void _send_signal_stable()
{
char send_buffer[32] = {0};
strcpy(send_buffer, "sigstable");
log_debug("send_buffer: %s, errno %d [%d]", send_buffer, errno, ECONNRESET);
if (errno != ECONNRESET || g_t_svctx->b_tv_fake_stable == false) {
int ret = TEMP_FAILURE_RETRY(send(g_t_svctx->connect_socker_fd, send_buffer, strlen(send_buffer), 0));
if (ret < 0) {
log_debug("send sigstable fail");
}
g_t_svctx->b_tv_fake_stable = true;
}
}
static void _hdmi_rc_svctx_release()
{
if (!g_t_svctx) {
log_debug("g_t_svctx null");
return;
}
if (!g_t_svctx->b_tv_released) {
StopTv(e_currentsource);
log_debug("stoptv is ok");
}
g_t_svctx->b_tv_released = true;
close(g_t_svctx->connect_socker_fd);
close(g_t_svctx->listen_fd);
unlink(HDMIRX_SERVER_SOCKET);
g_t_svctx->b_svctx_enable = false;
log_debug("exit _hdmi_rc_svctx_release");
}
static void TvEventCallback(event_type_t eventType, void *eventData)
{
if (eventType == TV_EVENT_TYPE_SIGNAL_DETECT) {
SignalDetectCallback_t *signalDetectEvent = (SignalDetectCallback_t *)(eventData);
log_debug("source: %d, signalFmt: %d, transFmt: %d, status: %d, isDVI: %d, Hdrinfo: %ud",
signalDetectEvent->SourceInput,
signalDetectEvent->SignalFmt,
signalDetectEvent->TransFmt,
signalDetectEvent->SignalStatus,
signalDetectEvent->isDviSignal,
signalDetectEvent->Hdrinfo);
if (TVIN_SIG_STATUS_STABLE == signalDetectEvent->SignalStatus) {
log_debug("SignalStatus is stable");
_send_signal_stable();
}
} else if (eventType == TV_EVENT_TYPE_SOURCE_CONNECT) {
SourceConnectCallback_t *sourceConnectEvent = (SourceConnectCallback_t *)(eventData);
log_debug("source: %d, connectStatus: %d",
sourceConnectEvent->SourceInput, sourceConnectEvent->ConnectionState);
} else {
log_debug("invalid event %d.", eventType);
}
}
static void *process_socket_thread(void *arg)
{
log_debug("enter");
int r;
char recv_buffer[32] = {0};
char *hdmirxsrc;
hdmirxsrc = getenv("HDMISRC");
log_debug("hdmirxsrc is %s",hdmirxsrc);
if (NULL == hdmirxsrc) {
e_currentsource = SOURCE_HDMI1;
free(hdmirxsrc);
log_debug("HDMISRC is hdmi1");
}
else if (0 == memcmp("hdmi1",hdmirxsrc,5)) {
e_currentsource = SOURCE_HDMI1;
log_debug("HDMISRC is hdmi1");
}
else if (0 == memcmp("hdmi2",hdmirxsrc,5)) {
e_currentsource = SOURCE_HDMI2;
log_debug("HDMISRC is hdmi2");
}
else if (0 == memcmp("hdmi3",hdmirxsrc,5)) {
e_currentsource = SOURCE_HDMI3;
log_debug("HDMISRC is hdmi3");
}
else{
log_debug("invalid HDMISRC");
}
log_debug("e_currentsource = %d",e_currentsource);
hdmi_rx_svc_t *g_t_svctx = (hdmi_rx_svc_t *)(arg);
while (g_t_svctx->b_svctx_enable) {
log_debug("loop wait recv cmd");
r = TEMP_FAILURE_RETRY(recv(g_t_svctx->connect_socker_fd, recv_buffer, sizeof(recv_buffer), 0));
log_debug("recv_buffer = %s ",recv_buffer);
log_debug("r = %d errno = %d",r, errno);
if (!g_t_svctx->b_svctx_enable) {
log_debug("exit thread");
break;
}
if ((r == 0) || (r == -1L) || (strcmp("disconnect", recv_buffer) == 0)) {
_hdmi_rc_svctx_release();
break;
} else if (strcmp("connect", recv_buffer) == 0) {
log_debug("Enter connect_hdmi");
pthread_mutex_lock(&g_t_svctx->tvclient_mutex);
StartTv(e_currentsource);
log_debug("Exit connect_hdmi");
g_t_svctx->b_tv_released = false;
pthread_mutex_unlock(&g_t_svctx->tvclient_mutex);
log_debug("startv is ok");
} else {
log_debug("[%s] not supported message ...", __FUNCTION__);
continue;
}
}
log_debug("exit");
return NULL;
}
static void hdmi_rx_svctx_perform_connect(hdmi_rx_svc_t *g_t_svctx)
{
log_debug("enter");
struct sockaddr_un server_unix, client_unix;
socklen_t client_unix_len;
int listen_fd, connfd, size;
if (!g_t_svctx) {
log_debug("g_t_svctx null");
return;
}
unlink(HDMIRX_SERVER_SOCKET);
if ((listen_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket error");
exit(1);
}
g_t_svctx->listen_fd = listen_fd;
memset(&server_unix, 0, sizeof(server_unix));
server_unix.sun_family = AF_UNIX;
strcpy(server_unix.sun_path, HDMIRX_SERVER_SOCKET);
size = offsetof(struct sockaddr_un, sun_path) + strlen(server_unix.sun_path);
if (bind(listen_fd, (struct sockaddr *)&server_unix, size) < 0) {
perror("bind error");
exit(1);
}
struct timespec currentTime;
clock_gettime(CLOCK_REALTIME, &currentTime);
log_debug("[%ld]UNIX domain socket (%s) bound", currentTime.tv_nsec, server_unix.sun_path);
if (listen(listen_fd, 16) < 0) {
perror("listen error");
exit(1);
}
client_unix_len = sizeof(client_unix);
clock_gettime(CLOCK_REALTIME, &currentTime);
log_debug("[%ld]Accepting connections,get the client_unix_len: %d",currentTime.tv_nsec, client_unix_len);
if ((connfd = accept(listen_fd, (struct sockaddr *)&client_unix, &client_unix_len)) < 0) {
perror("accept error");
return;//add
}
// show network status
system("netstat -an | grep hdmi-rx");
log_debug("g_t_svctx prepare get the connect_socker_fd %d", connfd);
g_t_svctx->connect_socker_fd = connfd;
log_debug("exit");
}
static hdmi_rx_svc_t *hdmi_rx_svctx_init()
{
log_debug("enter");
hdmi_rx_svc_t *g_t_svctx = (hdmi_rx_svc_t*) malloc(sizeof(hdmi_rx_svc_t));
if (!g_t_svctx) {
log_debug("malloc hdmi svctx failed");
return NULL;
}
g_t_svctx->b_tv_fake_stable = false;
log_debug("go hdmi_rx_svctx_perform_connect");
hdmi_rx_svctx_perform_connect(g_t_svctx);
g_t_svctx->b_svctx_enable = true;
g_t_svctx->b_tv_released = false;
pthread_mutex_init(&g_t_svctx->tvclient_mutex, NULL);
log_debug("exit");
return g_t_svctx;
}
static void Signalhandler(int sig)
{
log_debug("enter hdmictrl Signalhandler: %d",sig);
//Send Fake signal stable to unlock start() wait.
if (g_t_svctx->b_tv_fake_stable == false) {
_send_signal_stable();
}
//Wait for the client's thread to exit
pthread_join(g_t_svctx->t_socket_thread, NULL);
exit(0);
}
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
signal(SIGINT, SIG_IGN); // Ignore the SIGINT signal
signal(SIGTERM, Signalhandler);
log_debug("enter, prepare enter hdmi_rx_svctx_init");
g_t_svctx = hdmi_rx_svctx_init();
if (!g_t_svctx) {
log_debug("g_t_svctx init fail");
return -1;
}
log_debug("prepare enter setTvEventCallback");
setTvEventCallback(TvEventCallback);
log_debug("prepare enter process_socket_thread");
int err = 0;
err = pthread_create(&g_t_svctx->t_socket_thread, NULL, &process_socket_thread, g_t_svctx);
if (err != 0) {
log_debug("create process_socket_thread failed %d", err);
exit(1);
}
pthread_join(g_t_svctx->t_socket_thread, NULL);
log_debug("exit process_socket_thread");
if (g_t_svctx) {
free(g_t_svctx);
}
log_debug("exit");
return 0;
}