diff --git a/internal/native/cgo/video.c b/internal/native/cgo/video.c index 203cef13..97caaea6 100644 --- a/internal/native/cgo/video.c +++ b/internal/native/cgo/video.c @@ -333,11 +333,29 @@ static void *venc_read_stream(void *arg) } uint32_t detected_width, detected_height; -bool detected_signal = false, streaming_flag = false; +bool detected_signal = false, streaming_flag = false, streaming_stopped = true; pthread_t *streaming_thread = NULL; pthread_mutex_t streaming_mutex = PTHREAD_MUTEX_INITIALIZER; +bool get_streaming_flag() +{ + log_info("getting streaming flag"); + pthread_mutex_lock(&streaming_mutex); + bool flag = streaming_flag; + pthread_mutex_unlock(&streaming_mutex); + return flag; +} + +void set_streaming_flag(bool flag) +{ + log_info("setting streaming flag to %d", flag); + + pthread_mutex_lock(&streaming_mutex); + streaming_flag = flag; + pthread_mutex_unlock(&streaming_mutex); +} + void write_buffer_to_file(const uint8_t *buffer, size_t length, const char *filename) { FILE *file = fopen(filename, "wb"); @@ -351,6 +369,8 @@ void *run_video_stream(void *arg) log_info("running video stream"); + streaming_stopped = false; + while (streaming_flag) { if (detected_signal == false) @@ -583,8 +603,11 @@ void *run_video_stream(void *arg) log_info("closing video capture device %s", VIDEO_DEV); close(video_dev_fd); } - + log_info("video stream thread exiting"); + + streaming_stopped = true; + return NULL; } @@ -614,56 +637,75 @@ void video_shutdown() log_info("Destroyed streaming mutex"); } - void video_start_streaming() { - pthread_mutex_lock(&streaming_mutex); + log_info("starting video streaming"); if (streaming_thread != NULL) { + if (streaming_stopped == true) { + log_error("video streaming already stopped but streaming_thread is not NULL"); + assert(streaming_stopped == true); + } log_warn("video streaming already started"); - goto cleanup; + return; } pthread_t *new_thread = malloc(sizeof(pthread_t)); if (new_thread == NULL) { log_error("Failed to allocate memory for streaming thread"); - goto cleanup; + return; } - streaming_flag = true; + set_streaming_flag(true); int result = pthread_create(new_thread, NULL, run_video_stream, NULL); if (result != 0) { log_error("Failed to create streaming thread: %s", strerror(result)); - streaming_flag = false; + set_streaming_flag(false); free(new_thread); - goto cleanup; + return; } - // Only set streaming_thread after successful creation, and before unlocking the mutex + // Only set streaming_thread after successful creation streaming_thread = new_thread; -cleanup: - pthread_mutex_unlock(&streaming_mutex); - return; } void video_stop_streaming() { - pthread_mutex_lock(&streaming_mutex); - if (streaming_thread != NULL) - { - streaming_flag = false; - log_info("stopping video streaming"); - // wait 100ms for the thread to exit - usleep(1000000); - log_info("waiting for video streaming thread to exit"); - pthread_join(*streaming_thread, NULL); - free(streaming_thread); - streaming_thread = NULL; - log_info("video streaming stopped"); + if (streaming_thread == NULL) { + log_info("video streaming already stopped"); + return; } - pthread_mutex_unlock(&streaming_mutex); + + log_info("stopping video streaming"); + set_streaming_flag(false); + + log_info("waiting for video streaming thread to exit"); + int attempts = 0; + while (!streaming_stopped && attempts < 30) { + usleep(100000); // 100ms + attempts++; + } + if (!streaming_stopped) { + log_error("video streaming thread did not exit after 30s"); + } + + pthread_join(*streaming_thread, NULL); + free(streaming_thread); + streaming_thread = NULL; + + log_info("video streaming stopped"); +} + +void video_restart_streaming() +{ + if (get_streaming_flag() == true) + { + log_info("restarting video streaming"); + video_stop_streaming(); + } + video_start_streaming(); } void *run_detect_format(void *arg) @@ -727,18 +769,8 @@ void *run_detect_format(void *arg) detected_height = dv_timings.bt.height; detected_signal = true; video_report_format(true, NULL, detected_width, detected_height, frames_per_second); - pthread_mutex_lock(&streaming_mutex); - if (streaming_flag == true) - { - pthread_mutex_unlock(&streaming_mutex); - log_info("restarting on going video streaming"); - video_stop_streaming(); - video_start_streaming(); - } - else - { - pthread_mutex_unlock(&streaming_mutex); - } + + video_restart_streaming(); } memset(&ev, 0, sizeof(ev)); @@ -765,19 +797,7 @@ void video_set_quality_factor(float factor) quality_factor = factor; // TODO: update venc bitrate without stopping streaming - - pthread_mutex_lock(&streaming_mutex); - if (streaming_flag == true) - { - pthread_mutex_unlock(&streaming_mutex); - log_info("restarting on going video streaming due to quality factor change"); - video_stop_streaming(); - video_start_streaming(); - } - else - { - pthread_mutex_unlock(&streaming_mutex); - } + video_restart_streaming(); } float video_get_quality_factor() { diff --git a/internal/native/video.go b/internal/native/video.go index d5008756..bc5ebaf8 100644 --- a/internal/native/video.go +++ b/internal/native/video.go @@ -6,6 +6,9 @@ import ( const sleepModeFile = "/sys/devices/platform/ff470000.i2c/i2c-4/4-000f/sleep_mode" +// DefaultEDID is the default EDID for the video stream. +const DefaultEDID = "00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b" + // VideoState is the state of the video stream. type VideoState struct { Ready bool `json:"ready"` @@ -87,6 +90,10 @@ func (n *Native) VideoSetEDID(edid string) error { n.videoLock.Lock() defer n.videoLock.Unlock() + if edid == "" { + edid = DefaultEDID + } + return videoSetEDID(edid) } diff --git a/jsonrpc.go b/jsonrpc.go index d2d3f401..2c06f12b 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -243,7 +243,6 @@ func rpcGetEDID() (string, error) { func rpcSetEDID(edid string) error { if edid == "" { logger.Info().Msg("Restoring EDID to default") - edid = "00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b" } else { logger.Info().Str("edid", edid).Msg("Setting EDID") } diff --git a/native.go b/native.go index 4268bf2c..a703bb5a 100644 --- a/native.go +++ b/native.go @@ -58,7 +58,9 @@ func initNative(systemVersion *semver.Version, appVersion *semver.Version) { } }, }) + nativeInstance.Start() + nativeInstance.VideoSetEDID(config.EdidString) if os.Getenv("JETKVM_CRASH_TESTING") == "1" { nativeInstance.DoNotUseThisIsForCrashTestingOnly()