From 89093582db2b4cf98c26b9ce63beffc4fb944dc4 Mon Sep 17 00:00:00 2001 From: Lars-Erik Stenholm Date: Sat, 22 Aug 2026 21:05:51 +0200 Subject: [PATCH 1/4] Add video snapshot API Adds a GET /snapshot endpoint that returns a single JPEG frame of the current video feed. A second Rockchip VENC channel is created alongside the existing H.264/H.265 channel to encode on-demand JPEG snapshots from the already-captured raw frame, plumbed up through the native gRPC service into a plain authenticated REST route. Returns 503 when no viewer session is active, since video capture only runs while a WebRTC session is connected. Co-Authored-By: Claude Sonnet 5 --- internal/native/cgo/ctrl.c | 8 + internal/native/cgo/ctrl.h | 3 + internal/native/cgo/video.c | 250 +++++++++++++ internal/native/cgo/video.h | 24 ++ internal/native/cgo_linux.go | 19 + internal/native/cgo_notlinux.go | 5 + internal/native/empty.go | 4 + internal/native/grpc_clientmethods.go | 14 + internal/native/grpc_servermethods.go | 12 + internal/native/interface.go | 1 + internal/native/proto/native.pb.go | 454 +++++++++++++----------- internal/native/proto/native.proto | 5 + internal/native/proto/native_grpc.pb.go | 42 ++- internal/native/proxy.go | 12 +- internal/native/video.go | 15 + video.go | 20 ++ web.go | 1 + 17 files changed, 683 insertions(+), 206 deletions(-) diff --git a/internal/native/cgo/ctrl.c b/internal/native/cgo/ctrl.c index 7d64ab83a..4ad8c2a57 100644 --- a/internal/native/cgo/ctrl.c +++ b/internal/native/cgo/ctrl.c @@ -429,6 +429,14 @@ char *jetkvm_video_log_status() { return (char *)videoc_log_status(); } +int jetkvm_video_get_snapshot(uint8_t **out_buf, size_t *out_len) { + return video_get_snapshot(out_buf, out_len); +} + +void jetkvm_video_free_snapshot(uint8_t *buf) { + video_free_snapshot(buf); +} + int jetkvm_video_init(float factor) { return video_init(factor); } diff --git a/internal/native/cgo/ctrl.h b/internal/native/cgo/ctrl.h index ab0a08818..a434e3a14 100644 --- a/internal/native/cgo/ctrl.h +++ b/internal/native/cgo/ctrl.h @@ -2,6 +2,7 @@ #define VIDEO_DAEMON_CTRL_H #include +#include #include #include @@ -66,6 +67,8 @@ int jetkvm_video_set_edid(const char *edid_hex); char *jetkvm_video_get_edid_hex(); char *jetkvm_video_log_status(); jetkvm_video_state_t *jetkvm_video_get_status(); +int jetkvm_video_get_snapshot(uint8_t **out_buf, size_t *out_len); +void jetkvm_video_free_snapshot(uint8_t *buf); void video_report_format(bool ready, const char *error, u_int16_t width, u_int16_t height, double frame_per_second); void video_send_format_report(); diff --git a/internal/native/cgo/video.c b/internal/native/cgo/video.c index 3ede30a9a..5e936559d 100644 --- a/internal/native/cgo/video.c +++ b/internal/native/cgo/video.c @@ -38,6 +38,7 @@ int sub_dev_fd = -1; #define VENC_CHANNEL 0 +#define VENC_CHANNEL_JPEG 1 // second encoder channel, used only for on-demand snapshots MB_POOL memPool = MB_INVALID_POOLID; bool sleep_mode_available = false; @@ -46,6 +47,8 @@ float quality_factor = 1.0f; int codec_type = 0; static void *venc_read_stream(void *arg); +static int32_t venc_jpeg_start(int32_t width, int32_t height); +static void venc_jpeg_stop(void); RK_U64 get_us() { @@ -288,6 +291,14 @@ static int32_t venc_start(int32_t bitrate, int32_t max_bitrate, int32_t width, i return ret; } + // Snapshot support is best-effort: if the JPEG channel fails to start, + // keep streaming the primary H.264/H.265 channel without it. + int32_t jpeg_ret = venc_jpeg_start(width, height); + if (jpeg_ret != RK_SUCCESS) + { + log_warn("failed to start JPEG snapshot channel: %#x", jpeg_ret); + } + venc_running = true; venc_read_thread = malloc(sizeof(pthread_t)); if (pthread_create(venc_read_thread, NULL, venc_read_stream, NULL) != 0) @@ -303,6 +314,8 @@ static int32_t venc_stop() { venc_running = false; + venc_jpeg_stop(); + int32_t ret; ret = RK_MPI_VENC_StopRecvFrame(VENC_CHANNEL); if (ret != RK_SUCCESS) @@ -328,6 +341,235 @@ static int32_t venc_stop() return RK_SUCCESS; } +// --- On-demand JPEG snapshot channel ----------------------------------- +// +// A second VENC channel, created/destroyed alongside VENC_CHANNEL so it +// always matches the current capture resolution. It receives frames +// continuously (like VENC_CHANNEL) but produces no output unless +// run_video_stream() explicitly feeds it a frame, which only happens while +// a video_get_snapshot() call is pending. + +static pthread_mutex_t snapshot_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t snapshot_cond = PTHREAD_COND_INITIALIZER; +static bool venc_jpeg_running = false; +static bool snapshot_requested = false; +static bool snapshot_ready = false; +static uint8_t *snapshot_buf = NULL; +static size_t snapshot_len = 0; +static int snapshot_result = 0; + +static void populate_venc_jpeg_attr(VENC_CHN_ATTR_S *stAttr, RK_U32 width, RK_U32 height) +{ + memset(stAttr, 0, sizeof(VENC_CHN_ATTR_S)); + + stAttr->stVencAttr.enType = RK_VIDEO_ID_JPEG; + stAttr->stVencAttr.enPixelFormat = RK_FMT_YUV422_YUYV; + stAttr->stVencAttr.u32PicWidth = width; + stAttr->stVencAttr.u32PicHeight = height; + stAttr->stVencAttr.u32VirWidth = RK_ALIGN_16(width); + stAttr->stVencAttr.u32VirHeight = RK_ALIGN_16(height); + stAttr->stVencAttr.u32StreamBufCnt = 2; + stAttr->stVencAttr.u32BufSize = width * height * 3 / 2; + stAttr->stVencAttr.enMirror = MIRROR_NONE; +} + +static int32_t venc_jpeg_start(int32_t width, int32_t height) +{ + VENC_CHN_ATTR_S stAttr; + populate_venc_jpeg_attr(&stAttr, (RK_U32)width, (RK_U32)height); + + int32_t ret = RK_MPI_VENC_CreateChn(VENC_CHANNEL_JPEG, &stAttr); + if (ret != RK_SUCCESS) + { + return ret; + } + + VENC_JPEG_PARAM_S stJpegParam; + memset(&stJpegParam, 0, sizeof(stJpegParam)); + stJpegParam.u32Qfactor = 90; + ret = RK_MPI_VENC_SetJpegParam(VENC_CHANNEL_JPEG, &stJpegParam); + if (ret != RK_SUCCESS) + { + log_warn("RK_MPI_VENC_SetJpegParam failed: %#x, using encoder default quality", ret); + } + + VENC_RECV_PIC_PARAM_S stRecvParam; + memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S)); + stRecvParam.s32RecvPicNum = -1; + ret = RK_MPI_VENC_StartRecvFrame(VENC_CHANNEL_JPEG, &stRecvParam); + if (ret != RK_SUCCESS) + { + RK_MPI_VENC_DestroyChn(VENC_CHANNEL_JPEG); + return ret; + } + + pthread_mutex_lock(&snapshot_mutex); + venc_jpeg_running = true; + pthread_mutex_unlock(&snapshot_mutex); + + return RK_SUCCESS; +} + +static void venc_jpeg_stop(void) +{ + pthread_mutex_lock(&snapshot_mutex); + if (!venc_jpeg_running) + { + pthread_mutex_unlock(&snapshot_mutex); + return; + } + venc_jpeg_running = false; + + // Wake up a snapshot request that's still waiting; the channel is going away. + if (snapshot_requested) + { + snapshot_requested = false; + snapshot_result = VIDEO_SNAPSHOT_ERR_NOT_STREAMING; + snapshot_ready = true; + pthread_cond_broadcast(&snapshot_cond); + } + pthread_mutex_unlock(&snapshot_mutex); + + RK_MPI_VENC_StopRecvFrame(VENC_CHANNEL_JPEG); + RK_MPI_VENC_DestroyChn(VENC_CHANNEL_JPEG); +} + +// Delivers a snapshot result to the (single) waiting video_get_snapshot() +// call and wakes it up. Takes ownership of buf (may be NULL on error). +static void complete_snapshot_request(uint8_t *buf, size_t len, int result) +{ + pthread_mutex_lock(&snapshot_mutex); + snapshot_requested = false; + free(snapshot_buf); // defensive; should already be NULL here + snapshot_buf = buf; + snapshot_len = len; + snapshot_result = result; + snapshot_ready = true; + pthread_cond_broadcast(&snapshot_cond); + pthread_mutex_unlock(&snapshot_mutex); +} + +// Runs on the video capture thread. pFrame is the just-captured raw frame +// that was already handed to VENC_CHANNEL; reusing it here avoids capturing +// a second frame off V4L2 just for the snapshot. +static void handle_snapshot_request(VIDEO_FRAME_INFO_S *pFrame) +{ + bool retried = false; +retry_send_jpeg_frame: + if (RK_MPI_VENC_SendFrame(VENC_CHANNEL_JPEG, pFrame, 2000) != RK_SUCCESS) + { + if (!retried) + { + retried = true; + usleep(1000llu); + goto retry_send_jpeg_frame; + } + log_error("snapshot: RK_MPI_VENC_SendFrame(JPEG) failed"); + complete_snapshot_request(NULL, 0, VIDEO_SNAPSHOT_ERR_ENCODE); + return; + } + + VENC_STREAM_S stJpegStream; + memset(&stJpegStream, 0, sizeof(stJpegStream)); + stJpegStream.pstPack = malloc(sizeof(VENC_PACK_S)); + if (stJpegStream.pstPack == NULL) + { + complete_snapshot_request(NULL, 0, VIDEO_SNAPSHOT_ERR_NOMEM); + return; + } + + int32_t ret = RK_MPI_VENC_GetStream(VENC_CHANNEL_JPEG, &stJpegStream, 200); + if (ret != RK_SUCCESS) + { + log_error("snapshot: RK_MPI_VENC_GetStream(JPEG) failed %#x", ret); + free(stJpegStream.pstPack); + complete_snapshot_request(NULL, 0, VIDEO_SNAPSHOT_ERR_ENCODE); + return; + } + + void *pData = RK_MPI_MB_Handle2VirAddr(stJpegStream.pstPack->pMbBlk); + size_t len = (size_t)stJpegStream.pstPack->u32Len; + uint8_t *copy = malloc(len); + if (copy == NULL) + { + RK_MPI_VENC_ReleaseStream(VENC_CHANNEL_JPEG, &stJpegStream); + free(stJpegStream.pstPack); + complete_snapshot_request(NULL, 0, VIDEO_SNAPSHOT_ERR_NOMEM); + return; + } + memcpy(copy, pData, len); + + RK_MPI_VENC_ReleaseStream(VENC_CHANNEL_JPEG, &stJpegStream); + free(stJpegStream.pstPack); + + complete_snapshot_request(copy, len, 0); +} + +int video_get_snapshot(uint8_t **out_buf, size_t *out_len) +{ + if (!get_streaming_flag() || get_streaming_stopped()) + { + return VIDEO_SNAPSHOT_ERR_NOT_STREAMING; + } + + pthread_mutex_lock(&snapshot_mutex); + + if (!venc_jpeg_running) + { + pthread_mutex_unlock(&snapshot_mutex); + return VIDEO_SNAPSHOT_ERR_NOT_STREAMING; + } + + snapshot_requested = true; + snapshot_ready = false; + free(snapshot_buf); + snapshot_buf = NULL; + snapshot_len = 0; + snapshot_result = 0; + + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += 500000000L; // 500ms deadline: one frame period plus JPEG encode headroom + if (ts.tv_nsec >= 1000000000L) + { + ts.tv_sec += 1; + ts.tv_nsec -= 1000000000L; + } + + int wait_rc = 0; + while (!snapshot_ready && wait_rc == 0) + { + wait_rc = pthread_cond_timedwait(&snapshot_cond, &snapshot_mutex, &ts); + } + + int result; + if (!snapshot_ready) + { + snapshot_requested = false; + result = VIDEO_SNAPSHOT_ERR_TIMEOUT; + } + else if (snapshot_result != 0 || snapshot_buf == NULL) + { + result = (snapshot_result != 0) ? snapshot_result : VIDEO_SNAPSHOT_ERR_ENCODE; + } + else + { + *out_buf = snapshot_buf; + *out_len = snapshot_len; + snapshot_buf = NULL; + snapshot_len = 0; + result = 0; + } + + pthread_mutex_unlock(&snapshot_mutex); + return result; +} + +void video_free_snapshot(uint8_t *buf) +{ + free(buf); +} + struct buffer { struct v4l2_plane plane_buffer; @@ -751,6 +993,14 @@ void *run_video_stream(void *arg) num++; + pthread_mutex_lock(&snapshot_mutex); + bool want_snapshot = venc_jpeg_running && snapshot_requested; + pthread_mutex_unlock(&snapshot_mutex); + if (want_snapshot) + { + handle_snapshot_request(&stFrame); + } + if (ioctl(video_dev_fd, VIDIOC_QBUF, &buf) < 0) log_error("failure VIDIOC_QBUF: %s", strerror(errno)); } diff --git a/internal/native/cgo/video.h b/internal/native/cgo/video.h index c3b382660..4cc4ca04a 100644 --- a/internal/native/cgo/video.h +++ b/internal/native/cgo/video.h @@ -1,6 +1,9 @@ #ifndef VIDEO_DAEMON_VIDEO_H #define VIDEO_DAEMON_VIDEO_H +#include +#include + /** * @brief Initialize the video subsystem * @@ -62,4 +65,25 @@ void video_set_codec_type(int type); */ int video_get_codec_type(); +#define VIDEO_SNAPSHOT_ERR_NOT_STREAMING (-1) // no active video stream to snapshot +#define VIDEO_SNAPSHOT_ERR_TIMEOUT (-2) // no frame captured within the deadline +#define VIDEO_SNAPSHOT_ERR_ENCODE (-3) // JPEG encoder failed +#define VIDEO_SNAPSHOT_ERR_NOMEM (-4) // failed to allocate the output buffer + +/** + * @brief Capture a single JPEG-encoded snapshot of the current video frame. + * + * Blocks until the next captured frame has been JPEG-encoded, or until an + * internal deadline expires. On success, *out_buf is a malloc'd buffer of + * *out_len bytes that the caller must release with video_free_snapshot(). + * + * @return 0 on success, a negative VIDEO_SNAPSHOT_ERR_* code on failure + */ +int video_get_snapshot(uint8_t **out_buf, size_t *out_len); + +/** + * @brief Free a buffer returned by video_get_snapshot() + */ +void video_free_snapshot(uint8_t *buf); + #endif //VIDEO_DAEMON_VIDEO_H diff --git a/internal/native/cgo_linux.go b/internal/native/cgo_linux.go index df30404a2..bf6f8d952 100644 --- a/internal/native/cgo_linux.go +++ b/internal/native/cgo_linux.go @@ -178,6 +178,25 @@ func videoGetStreamingStatus() VideoStreamingStatus { return VideoStreamingStatus(isStreaming) } +func videoGetSnapshot() ([]byte, error) { + cgoLock.Lock() + defer cgoLock.Unlock() + + var buf *C.uint8_t + var length C.size_t + + ret := C.jetkvm_video_get_snapshot(&buf, &length) + if ret != 0 { + if ret == -1 { + return nil, ErrVideoNotStreaming + } + return nil, fmt.Errorf("failed to capture video snapshot: %d", int(ret)) + } + defer C.jetkvm_video_free_snapshot(buf) + + return C.GoBytes(unsafe.Pointer(buf), C.int(length)), nil +} + func videoLogStatus() string { cgoLock.Lock() defer cgoLock.Unlock() diff --git a/internal/native/cgo_notlinux.go b/internal/native/cgo_notlinux.go index 383f99297..c18f539d7 100644 --- a/internal/native/cgo_notlinux.go +++ b/internal/native/cgo_notlinux.go @@ -123,6 +123,11 @@ func videoLogStatus() string { return "" } +func videoGetSnapshot() ([]byte, error) { + panicPlatformNotSupported() + return nil, nil +} + func videoGetEDID() (string, error) { panicPlatformNotSupported() return "", nil diff --git a/internal/native/empty.go b/internal/native/empty.go index 25b3e3dfa..6667404c3 100644 --- a/internal/native/empty.go +++ b/internal/native/empty.go @@ -41,6 +41,10 @@ func (e *EmptyNativeInterface) VideoLogStatus() (string, error) { return "", nil } +func (e *EmptyNativeInterface) VideoGetSnapshot() ([]byte, error) { + return nil, ErrVideoNotStreaming +} + func (e *EmptyNativeInterface) VideoStop() error { return nil } diff --git a/internal/native/grpc_clientmethods.go b/internal/native/grpc_clientmethods.go index bfd00c54c..b63b6f777 100644 --- a/internal/native/grpc_clientmethods.go +++ b/internal/native/grpc_clientmethods.go @@ -3,6 +3,9 @@ package native import ( "context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + pb "github.com/jetkvm/kvm/internal/native/proto" ) @@ -77,6 +80,17 @@ func (c *GRPCClient) VideoLogStatus() (string, error) { return resp.Status, nil } +func (c *GRPCClient) VideoGetSnapshot() ([]byte, error) { + resp, err := c.client.VideoGetSnapshot(context.Background(), &pb.Empty{}) + if err != nil { + if status.Code(err) == codes.FailedPrecondition { + return nil, ErrVideoNotStreaming + } + return nil, err + } + return resp.Jpeg, nil +} + func (c *GRPCClient) VideoStop() error { _, err := c.client.VideoStop(context.Background(), &pb.Empty{}) return err diff --git a/internal/native/grpc_servermethods.go b/internal/native/grpc_servermethods.go index 439ab0038..b1f6ad422 100644 --- a/internal/native/grpc_servermethods.go +++ b/internal/native/grpc_servermethods.go @@ -2,6 +2,7 @@ package native import ( "context" + "errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -84,6 +85,17 @@ func (s *grpcServer) VideoLogStatus(ctx context.Context, req *pb.Empty) (*pb.Vid return &pb.VideoLogStatusResponse{Status: logStatus}, nil } +func (s *grpcServer) VideoGetSnapshot(ctx context.Context, req *pb.Empty) (*pb.VideoGetSnapshotResponse, error) { + jpeg, err := s.native.VideoGetSnapshot() + if err != nil { + if errors.Is(err, ErrVideoNotStreaming) { + return nil, status.Error(codes.FailedPrecondition, err.Error()) + } + return nil, status.Error(codes.Internal, err.Error()) + } + return &pb.VideoGetSnapshotResponse{Jpeg: jpeg}, nil +} + func (s *grpcServer) VideoStop(ctx context.Context, req *pb.Empty) (*pb.Empty, error) { if err := s.native.VideoStop(); err != nil { return nil, status.Error(codes.Internal, err.Error()) diff --git a/internal/native/interface.go b/internal/native/interface.go index 2f3392001..d91e6c573 100644 --- a/internal/native/interface.go +++ b/internal/native/interface.go @@ -13,6 +13,7 @@ type NativeInterface interface { VideoSetEDID(edid string) error VideoGetEDID() (string, error) VideoLogStatus() (string, error) + VideoGetSnapshot() ([]byte, error) VideoStop() error VideoStart() error GetLVGLVersion() (string, error) diff --git a/internal/native/proto/native.pb.go b/internal/native/proto/native.pb.go index af2bc57ae..91b555e69 100644 --- a/internal/native/proto/native.pb.go +++ b/internal/native/proto/native.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 -// protoc v3.21.12 +// protoc-gen-go v1.36.12 +// protoc v5.29.3 // source: internal/native/proto/native.proto package proto @@ -670,6 +670,50 @@ func (x *VideoLogStatusResponse) GetStatus() string { return "" } +type VideoGetSnapshotResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Jpeg []byte `protobuf:"bytes,1,opt,name=jpeg,proto3" json:"jpeg,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VideoGetSnapshotResponse) Reset() { + *x = VideoGetSnapshotResponse{} + mi := &file_internal_native_proto_native_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VideoGetSnapshotResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VideoGetSnapshotResponse) ProtoMessage() {} + +func (x *VideoGetSnapshotResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_native_proto_native_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VideoGetSnapshotResponse.ProtoReflect.Descriptor instead. +func (*VideoGetSnapshotResponse) Descriptor() ([]byte, []int) { + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{14} +} + +func (x *VideoGetSnapshotResponse) GetJpeg() []byte { + if x != nil { + return x.Jpeg + } + return nil +} + type GetLVGLVersionResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` @@ -679,7 +723,7 @@ type GetLVGLVersionResponse struct { func (x *GetLVGLVersionResponse) Reset() { *x = GetLVGLVersionResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[14] + mi := &file_internal_native_proto_native_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -691,7 +735,7 @@ func (x *GetLVGLVersionResponse) String() string { func (*GetLVGLVersionResponse) ProtoMessage() {} func (x *GetLVGLVersionResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[14] + mi := &file_internal_native_proto_native_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -704,7 +748,7 @@ func (x *GetLVGLVersionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLVGLVersionResponse.ProtoReflect.Descriptor instead. func (*GetLVGLVersionResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{14} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{15} } func (x *GetLVGLVersionResponse) GetVersion() string { @@ -723,7 +767,7 @@ type UIObjHideRequest struct { func (x *UIObjHideRequest) Reset() { *x = UIObjHideRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[15] + mi := &file_internal_native_proto_native_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -735,7 +779,7 @@ func (x *UIObjHideRequest) String() string { func (*UIObjHideRequest) ProtoMessage() {} func (x *UIObjHideRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[15] + mi := &file_internal_native_proto_native_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -748,7 +792,7 @@ func (x *UIObjHideRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjHideRequest.ProtoReflect.Descriptor instead. func (*UIObjHideRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{15} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{16} } func (x *UIObjHideRequest) GetObjName() string { @@ -767,7 +811,7 @@ type UIObjHideResponse struct { func (x *UIObjHideResponse) Reset() { *x = UIObjHideResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[16] + mi := &file_internal_native_proto_native_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -779,7 +823,7 @@ func (x *UIObjHideResponse) String() string { func (*UIObjHideResponse) ProtoMessage() {} func (x *UIObjHideResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[16] + mi := &file_internal_native_proto_native_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -792,7 +836,7 @@ func (x *UIObjHideResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjHideResponse.ProtoReflect.Descriptor instead. func (*UIObjHideResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{16} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{17} } func (x *UIObjHideResponse) GetSuccess() bool { @@ -811,7 +855,7 @@ type UIObjShowRequest struct { func (x *UIObjShowRequest) Reset() { *x = UIObjShowRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[17] + mi := &file_internal_native_proto_native_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -823,7 +867,7 @@ func (x *UIObjShowRequest) String() string { func (*UIObjShowRequest) ProtoMessage() {} func (x *UIObjShowRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[17] + mi := &file_internal_native_proto_native_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -836,7 +880,7 @@ func (x *UIObjShowRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjShowRequest.ProtoReflect.Descriptor instead. func (*UIObjShowRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{17} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{18} } func (x *UIObjShowRequest) GetObjName() string { @@ -855,7 +899,7 @@ type UIObjShowResponse struct { func (x *UIObjShowResponse) Reset() { *x = UIObjShowResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[18] + mi := &file_internal_native_proto_native_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -867,7 +911,7 @@ func (x *UIObjShowResponse) String() string { func (*UIObjShowResponse) ProtoMessage() {} func (x *UIObjShowResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[18] + mi := &file_internal_native_proto_native_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -880,7 +924,7 @@ func (x *UIObjShowResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjShowResponse.ProtoReflect.Descriptor instead. func (*UIObjShowResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{18} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{19} } func (x *UIObjShowResponse) GetSuccess() bool { @@ -900,7 +944,7 @@ type UISetVarRequest struct { func (x *UISetVarRequest) Reset() { *x = UISetVarRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[19] + mi := &file_internal_native_proto_native_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -912,7 +956,7 @@ func (x *UISetVarRequest) String() string { func (*UISetVarRequest) ProtoMessage() {} func (x *UISetVarRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[19] + mi := &file_internal_native_proto_native_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -925,7 +969,7 @@ func (x *UISetVarRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UISetVarRequest.ProtoReflect.Descriptor instead. func (*UISetVarRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{19} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{20} } func (x *UISetVarRequest) GetName() string { @@ -951,7 +995,7 @@ type UIGetVarRequest struct { func (x *UIGetVarRequest) Reset() { *x = UIGetVarRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[20] + mi := &file_internal_native_proto_native_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -963,7 +1007,7 @@ func (x *UIGetVarRequest) String() string { func (*UIGetVarRequest) ProtoMessage() {} func (x *UIGetVarRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[20] + mi := &file_internal_native_proto_native_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -976,7 +1020,7 @@ func (x *UIGetVarRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIGetVarRequest.ProtoReflect.Descriptor instead. func (*UIGetVarRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{20} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{21} } func (x *UIGetVarRequest) GetName() string { @@ -995,7 +1039,7 @@ type UIGetVarResponse struct { func (x *UIGetVarResponse) Reset() { *x = UIGetVarResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[21] + mi := &file_internal_native_proto_native_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1007,7 +1051,7 @@ func (x *UIGetVarResponse) String() string { func (*UIGetVarResponse) ProtoMessage() {} func (x *UIGetVarResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[21] + mi := &file_internal_native_proto_native_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1020,7 +1064,7 @@ func (x *UIGetVarResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIGetVarResponse.ProtoReflect.Descriptor instead. func (*UIGetVarResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{21} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{22} } func (x *UIGetVarResponse) GetValue() string { @@ -1040,7 +1084,7 @@ type UIObjAddStateRequest struct { func (x *UIObjAddStateRequest) Reset() { *x = UIObjAddStateRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[22] + mi := &file_internal_native_proto_native_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1052,7 +1096,7 @@ func (x *UIObjAddStateRequest) String() string { func (*UIObjAddStateRequest) ProtoMessage() {} func (x *UIObjAddStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[22] + mi := &file_internal_native_proto_native_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1065,7 +1109,7 @@ func (x *UIObjAddStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjAddStateRequest.ProtoReflect.Descriptor instead. func (*UIObjAddStateRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{22} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{23} } func (x *UIObjAddStateRequest) GetObjName() string { @@ -1091,7 +1135,7 @@ type UIObjAddStateResponse struct { func (x *UIObjAddStateResponse) Reset() { *x = UIObjAddStateResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[23] + mi := &file_internal_native_proto_native_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1103,7 +1147,7 @@ func (x *UIObjAddStateResponse) String() string { func (*UIObjAddStateResponse) ProtoMessage() {} func (x *UIObjAddStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[23] + mi := &file_internal_native_proto_native_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1116,7 +1160,7 @@ func (x *UIObjAddStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjAddStateResponse.ProtoReflect.Descriptor instead. func (*UIObjAddStateResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{23} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{24} } func (x *UIObjAddStateResponse) GetSuccess() bool { @@ -1136,7 +1180,7 @@ type UIObjClearStateRequest struct { func (x *UIObjClearStateRequest) Reset() { *x = UIObjClearStateRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[24] + mi := &file_internal_native_proto_native_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1148,7 +1192,7 @@ func (x *UIObjClearStateRequest) String() string { func (*UIObjClearStateRequest) ProtoMessage() {} func (x *UIObjClearStateRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[24] + mi := &file_internal_native_proto_native_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1161,7 +1205,7 @@ func (x *UIObjClearStateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjClearStateRequest.ProtoReflect.Descriptor instead. func (*UIObjClearStateRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{24} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{25} } func (x *UIObjClearStateRequest) GetObjName() string { @@ -1187,7 +1231,7 @@ type UIObjClearStateResponse struct { func (x *UIObjClearStateResponse) Reset() { *x = UIObjClearStateResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[25] + mi := &file_internal_native_proto_native_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1199,7 +1243,7 @@ func (x *UIObjClearStateResponse) String() string { func (*UIObjClearStateResponse) ProtoMessage() {} func (x *UIObjClearStateResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[25] + mi := &file_internal_native_proto_native_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1212,7 +1256,7 @@ func (x *UIObjClearStateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjClearStateResponse.ProtoReflect.Descriptor instead. func (*UIObjClearStateResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{25} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{26} } func (x *UIObjClearStateResponse) GetSuccess() bool { @@ -1232,7 +1276,7 @@ type UIObjAddFlagRequest struct { func (x *UIObjAddFlagRequest) Reset() { *x = UIObjAddFlagRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[26] + mi := &file_internal_native_proto_native_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1244,7 +1288,7 @@ func (x *UIObjAddFlagRequest) String() string { func (*UIObjAddFlagRequest) ProtoMessage() {} func (x *UIObjAddFlagRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[26] + mi := &file_internal_native_proto_native_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1257,7 +1301,7 @@ func (x *UIObjAddFlagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjAddFlagRequest.ProtoReflect.Descriptor instead. func (*UIObjAddFlagRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{26} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{27} } func (x *UIObjAddFlagRequest) GetObjName() string { @@ -1283,7 +1327,7 @@ type UIObjAddFlagResponse struct { func (x *UIObjAddFlagResponse) Reset() { *x = UIObjAddFlagResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[27] + mi := &file_internal_native_proto_native_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1295,7 +1339,7 @@ func (x *UIObjAddFlagResponse) String() string { func (*UIObjAddFlagResponse) ProtoMessage() {} func (x *UIObjAddFlagResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[27] + mi := &file_internal_native_proto_native_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1308,7 +1352,7 @@ func (x *UIObjAddFlagResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjAddFlagResponse.ProtoReflect.Descriptor instead. func (*UIObjAddFlagResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{27} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{28} } func (x *UIObjAddFlagResponse) GetSuccess() bool { @@ -1328,7 +1372,7 @@ type UIObjClearFlagRequest struct { func (x *UIObjClearFlagRequest) Reset() { *x = UIObjClearFlagRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[28] + mi := &file_internal_native_proto_native_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1340,7 +1384,7 @@ func (x *UIObjClearFlagRequest) String() string { func (*UIObjClearFlagRequest) ProtoMessage() {} func (x *UIObjClearFlagRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[28] + mi := &file_internal_native_proto_native_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1353,7 +1397,7 @@ func (x *UIObjClearFlagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjClearFlagRequest.ProtoReflect.Descriptor instead. func (*UIObjClearFlagRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{28} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{29} } func (x *UIObjClearFlagRequest) GetObjName() string { @@ -1379,7 +1423,7 @@ type UIObjClearFlagResponse struct { func (x *UIObjClearFlagResponse) Reset() { *x = UIObjClearFlagResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[29] + mi := &file_internal_native_proto_native_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1391,7 +1435,7 @@ func (x *UIObjClearFlagResponse) String() string { func (*UIObjClearFlagResponse) ProtoMessage() {} func (x *UIObjClearFlagResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[29] + mi := &file_internal_native_proto_native_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1404,7 +1448,7 @@ func (x *UIObjClearFlagResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjClearFlagResponse.ProtoReflect.Descriptor instead. func (*UIObjClearFlagResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{29} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{30} } func (x *UIObjClearFlagResponse) GetSuccess() bool { @@ -1424,7 +1468,7 @@ type UIObjSetOpacityRequest struct { func (x *UIObjSetOpacityRequest) Reset() { *x = UIObjSetOpacityRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[30] + mi := &file_internal_native_proto_native_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1436,7 +1480,7 @@ func (x *UIObjSetOpacityRequest) String() string { func (*UIObjSetOpacityRequest) ProtoMessage() {} func (x *UIObjSetOpacityRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[30] + mi := &file_internal_native_proto_native_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1449,7 +1493,7 @@ func (x *UIObjSetOpacityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjSetOpacityRequest.ProtoReflect.Descriptor instead. func (*UIObjSetOpacityRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{30} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{31} } func (x *UIObjSetOpacityRequest) GetObjName() string { @@ -1475,7 +1519,7 @@ type UIObjSetOpacityResponse struct { func (x *UIObjSetOpacityResponse) Reset() { *x = UIObjSetOpacityResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[31] + mi := &file_internal_native_proto_native_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1487,7 +1531,7 @@ func (x *UIObjSetOpacityResponse) String() string { func (*UIObjSetOpacityResponse) ProtoMessage() {} func (x *UIObjSetOpacityResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[31] + mi := &file_internal_native_proto_native_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1500,7 +1544,7 @@ func (x *UIObjSetOpacityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjSetOpacityResponse.ProtoReflect.Descriptor instead. func (*UIObjSetOpacityResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{31} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{32} } func (x *UIObjSetOpacityResponse) GetSuccess() bool { @@ -1520,7 +1564,7 @@ type UIObjFadeInRequest struct { func (x *UIObjFadeInRequest) Reset() { *x = UIObjFadeInRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[32] + mi := &file_internal_native_proto_native_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1532,7 +1576,7 @@ func (x *UIObjFadeInRequest) String() string { func (*UIObjFadeInRequest) ProtoMessage() {} func (x *UIObjFadeInRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[32] + mi := &file_internal_native_proto_native_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1545,7 +1589,7 @@ func (x *UIObjFadeInRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjFadeInRequest.ProtoReflect.Descriptor instead. func (*UIObjFadeInRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{32} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{33} } func (x *UIObjFadeInRequest) GetObjName() string { @@ -1571,7 +1615,7 @@ type UIObjFadeInResponse struct { func (x *UIObjFadeInResponse) Reset() { *x = UIObjFadeInResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[33] + mi := &file_internal_native_proto_native_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1583,7 +1627,7 @@ func (x *UIObjFadeInResponse) String() string { func (*UIObjFadeInResponse) ProtoMessage() {} func (x *UIObjFadeInResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[33] + mi := &file_internal_native_proto_native_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1596,7 +1640,7 @@ func (x *UIObjFadeInResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjFadeInResponse.ProtoReflect.Descriptor instead. func (*UIObjFadeInResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{33} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{34} } func (x *UIObjFadeInResponse) GetSuccess() bool { @@ -1616,7 +1660,7 @@ type UIObjFadeOutRequest struct { func (x *UIObjFadeOutRequest) Reset() { *x = UIObjFadeOutRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[34] + mi := &file_internal_native_proto_native_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1628,7 +1672,7 @@ func (x *UIObjFadeOutRequest) String() string { func (*UIObjFadeOutRequest) ProtoMessage() {} func (x *UIObjFadeOutRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[34] + mi := &file_internal_native_proto_native_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1641,7 +1685,7 @@ func (x *UIObjFadeOutRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjFadeOutRequest.ProtoReflect.Descriptor instead. func (*UIObjFadeOutRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{34} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{35} } func (x *UIObjFadeOutRequest) GetObjName() string { @@ -1667,7 +1711,7 @@ type UIObjFadeOutResponse struct { func (x *UIObjFadeOutResponse) Reset() { *x = UIObjFadeOutResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[35] + mi := &file_internal_native_proto_native_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1679,7 +1723,7 @@ func (x *UIObjFadeOutResponse) String() string { func (*UIObjFadeOutResponse) ProtoMessage() {} func (x *UIObjFadeOutResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[35] + mi := &file_internal_native_proto_native_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1692,7 +1736,7 @@ func (x *UIObjFadeOutResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjFadeOutResponse.ProtoReflect.Descriptor instead. func (*UIObjFadeOutResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{35} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{36} } func (x *UIObjFadeOutResponse) GetSuccess() bool { @@ -1712,7 +1756,7 @@ type UIObjSetLabelTextRequest struct { func (x *UIObjSetLabelTextRequest) Reset() { *x = UIObjSetLabelTextRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[36] + mi := &file_internal_native_proto_native_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1724,7 +1768,7 @@ func (x *UIObjSetLabelTextRequest) String() string { func (*UIObjSetLabelTextRequest) ProtoMessage() {} func (x *UIObjSetLabelTextRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[36] + mi := &file_internal_native_proto_native_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1737,7 +1781,7 @@ func (x *UIObjSetLabelTextRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjSetLabelTextRequest.ProtoReflect.Descriptor instead. func (*UIObjSetLabelTextRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{36} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{37} } func (x *UIObjSetLabelTextRequest) GetObjName() string { @@ -1763,7 +1807,7 @@ type UIObjSetLabelTextResponse struct { func (x *UIObjSetLabelTextResponse) Reset() { *x = UIObjSetLabelTextResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[37] + mi := &file_internal_native_proto_native_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1775,7 +1819,7 @@ func (x *UIObjSetLabelTextResponse) String() string { func (*UIObjSetLabelTextResponse) ProtoMessage() {} func (x *UIObjSetLabelTextResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[37] + mi := &file_internal_native_proto_native_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1788,7 +1832,7 @@ func (x *UIObjSetLabelTextResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjSetLabelTextResponse.ProtoReflect.Descriptor instead. func (*UIObjSetLabelTextResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{37} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{38} } func (x *UIObjSetLabelTextResponse) GetSuccess() bool { @@ -1808,7 +1852,7 @@ type UIObjSetImageSrcRequest struct { func (x *UIObjSetImageSrcRequest) Reset() { *x = UIObjSetImageSrcRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[38] + mi := &file_internal_native_proto_native_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1820,7 +1864,7 @@ func (x *UIObjSetImageSrcRequest) String() string { func (*UIObjSetImageSrcRequest) ProtoMessage() {} func (x *UIObjSetImageSrcRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[38] + mi := &file_internal_native_proto_native_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1833,7 +1877,7 @@ func (x *UIObjSetImageSrcRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjSetImageSrcRequest.ProtoReflect.Descriptor instead. func (*UIObjSetImageSrcRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{38} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{39} } func (x *UIObjSetImageSrcRequest) GetObjName() string { @@ -1859,7 +1903,7 @@ type UIObjSetImageSrcResponse struct { func (x *UIObjSetImageSrcResponse) Reset() { *x = UIObjSetImageSrcResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[39] + mi := &file_internal_native_proto_native_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1871,7 +1915,7 @@ func (x *UIObjSetImageSrcResponse) String() string { func (*UIObjSetImageSrcResponse) ProtoMessage() {} func (x *UIObjSetImageSrcResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[39] + mi := &file_internal_native_proto_native_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1884,7 +1928,7 @@ func (x *UIObjSetImageSrcResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UIObjSetImageSrcResponse.ProtoReflect.Descriptor instead. func (*UIObjSetImageSrcResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{39} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{40} } func (x *UIObjSetImageSrcResponse) GetSuccess() bool { @@ -1903,7 +1947,7 @@ type DisplaySetRotationRequest struct { func (x *DisplaySetRotationRequest) Reset() { *x = DisplaySetRotationRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[40] + mi := &file_internal_native_proto_native_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1915,7 +1959,7 @@ func (x *DisplaySetRotationRequest) String() string { func (*DisplaySetRotationRequest) ProtoMessage() {} func (x *DisplaySetRotationRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[40] + mi := &file_internal_native_proto_native_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1928,7 +1972,7 @@ func (x *DisplaySetRotationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DisplaySetRotationRequest.ProtoReflect.Descriptor instead. func (*DisplaySetRotationRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{40} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{41} } func (x *DisplaySetRotationRequest) GetRotation() uint32 { @@ -1947,7 +1991,7 @@ type DisplaySetRotationResponse struct { func (x *DisplaySetRotationResponse) Reset() { *x = DisplaySetRotationResponse{} - mi := &file_internal_native_proto_native_proto_msgTypes[41] + mi := &file_internal_native_proto_native_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1959,7 +2003,7 @@ func (x *DisplaySetRotationResponse) String() string { func (*DisplaySetRotationResponse) ProtoMessage() {} func (x *DisplaySetRotationResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[41] + mi := &file_internal_native_proto_native_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1972,7 +2016,7 @@ func (x *DisplaySetRotationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DisplaySetRotationResponse.ProtoReflect.Descriptor instead. func (*DisplaySetRotationResponse) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{41} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{42} } func (x *DisplaySetRotationResponse) GetSuccess() bool { @@ -1992,7 +2036,7 @@ type UpdateLabelIfChangedRequest struct { func (x *UpdateLabelIfChangedRequest) Reset() { *x = UpdateLabelIfChangedRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[42] + mi := &file_internal_native_proto_native_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2004,7 +2048,7 @@ func (x *UpdateLabelIfChangedRequest) String() string { func (*UpdateLabelIfChangedRequest) ProtoMessage() {} func (x *UpdateLabelIfChangedRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[42] + mi := &file_internal_native_proto_native_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2017,7 +2061,7 @@ func (x *UpdateLabelIfChangedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateLabelIfChangedRequest.ProtoReflect.Descriptor instead. func (*UpdateLabelIfChangedRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{42} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{43} } func (x *UpdateLabelIfChangedRequest) GetObjName() string { @@ -2044,7 +2088,7 @@ type UpdateLabelAndChangeVisibilityRequest struct { func (x *UpdateLabelAndChangeVisibilityRequest) Reset() { *x = UpdateLabelAndChangeVisibilityRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[43] + mi := &file_internal_native_proto_native_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2056,7 +2100,7 @@ func (x *UpdateLabelAndChangeVisibilityRequest) String() string { func (*UpdateLabelAndChangeVisibilityRequest) ProtoMessage() {} func (x *UpdateLabelAndChangeVisibilityRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[43] + mi := &file_internal_native_proto_native_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2069,7 +2113,7 @@ func (x *UpdateLabelAndChangeVisibilityRequest) ProtoReflect() protoreflect.Mess // Deprecated: Use UpdateLabelAndChangeVisibilityRequest.ProtoReflect.Descriptor instead. func (*UpdateLabelAndChangeVisibilityRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{43} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{44} } func (x *UpdateLabelAndChangeVisibilityRequest) GetObjName() string { @@ -2096,7 +2140,7 @@ type SwitchToScreenIfRequest struct { func (x *SwitchToScreenIfRequest) Reset() { *x = SwitchToScreenIfRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[44] + mi := &file_internal_native_proto_native_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2108,7 +2152,7 @@ func (x *SwitchToScreenIfRequest) String() string { func (*SwitchToScreenIfRequest) ProtoMessage() {} func (x *SwitchToScreenIfRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[44] + mi := &file_internal_native_proto_native_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2121,7 +2165,7 @@ func (x *SwitchToScreenIfRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SwitchToScreenIfRequest.ProtoReflect.Descriptor instead. func (*SwitchToScreenIfRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{44} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{45} } func (x *SwitchToScreenIfRequest) GetScreenName() string { @@ -2147,7 +2191,7 @@ type SwitchToScreenIfDifferentRequest struct { func (x *SwitchToScreenIfDifferentRequest) Reset() { *x = SwitchToScreenIfDifferentRequest{} - mi := &file_internal_native_proto_native_proto_msgTypes[45] + mi := &file_internal_native_proto_native_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2159,7 +2203,7 @@ func (x *SwitchToScreenIfDifferentRequest) String() string { func (*SwitchToScreenIfDifferentRequest) ProtoMessage() {} func (x *SwitchToScreenIfDifferentRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[45] + mi := &file_internal_native_proto_native_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2172,7 +2216,7 @@ func (x *SwitchToScreenIfDifferentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SwitchToScreenIfDifferentRequest.ProtoReflect.Descriptor instead. func (*SwitchToScreenIfDifferentRequest) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{45} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{46} } func (x *SwitchToScreenIfDifferentRequest) GetScreenName() string { @@ -2198,7 +2242,7 @@ type Event struct { func (x *Event) Reset() { *x = Event{} - mi := &file_internal_native_proto_native_proto_msgTypes[46] + mi := &file_internal_native_proto_native_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2210,7 +2254,7 @@ func (x *Event) String() string { func (*Event) ProtoMessage() {} func (x *Event) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[46] + mi := &file_internal_native_proto_native_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2223,7 +2267,7 @@ func (x *Event) ProtoReflect() protoreflect.Message { // Deprecated: Use Event.ProtoReflect.Descriptor instead. func (*Event) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{46} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{47} } func (x *Event) GetType() string { @@ -2314,7 +2358,7 @@ type VideoFrame struct { func (x *VideoFrame) Reset() { *x = VideoFrame{} - mi := &file_internal_native_proto_native_proto_msgTypes[47] + mi := &file_internal_native_proto_native_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2326,7 +2370,7 @@ func (x *VideoFrame) String() string { func (*VideoFrame) ProtoMessage() {} func (x *VideoFrame) ProtoReflect() protoreflect.Message { - mi := &file_internal_native_proto_native_proto_msgTypes[47] + mi := &file_internal_native_proto_native_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2339,7 +2383,7 @@ func (x *VideoFrame) ProtoReflect() protoreflect.Message { // Deprecated: Use VideoFrame.ProtoReflect.Descriptor instead. func (*VideoFrame) Descriptor() ([]byte, []int) { - return file_internal_native_proto_native_proto_rawDescGZIP(), []int{47} + return file_internal_native_proto_native_proto_rawDescGZIP(), []int{48} } func (x *VideoFrame) GetFrame() []byte { @@ -2396,7 +2440,9 @@ const file_internal_native_proto_native_proto_rawDesc = "" + "\x14VideoGetEDIDResponse\x12\x12\n" + "\x04edid\x18\x01 \x01(\tR\x04edid\"0\n" + "\x16VideoLogStatusResponse\x12\x16\n" + - "\x06status\x18\x01 \x01(\tR\x06status\"2\n" + + "\x06status\x18\x01 \x01(\tR\x06status\".\n" + + "\x18VideoGetSnapshotResponse\x12\x12\n" + + "\x04jpeg\x18\x01 \x01(\fR\x04jpeg\"2\n" + "\x16GetLVGLVersionResponse\x12\x18\n" + "\aversion\x18\x01 \x01(\tR\aversion\"-\n" + "\x10UIObjHideRequest\x12\x19\n" + @@ -2490,7 +2536,7 @@ const file_internal_native_proto_native_proto_rawDesc = "" + "VideoFrame\x12\x14\n" + "\x05frame\x18\x01 \x01(\fR\x05frame\x12\x1f\n" + "\vduration_ns\x18\x02 \x01(\x03R\n" + - "durationNs2\x8a\x13\n" + + "durationNs2\xcf\x13\n" + "\rNativeService\x12:\n" + "\aIsReady\x12\x16.native.IsReadyRequest\x1a\x17.native.IsReadyResponse\x12D\n" + "\x11VideoSetSleepMode\x12 .native.VideoSetSleepModeRequest\x1a\r.native.Empty\x12E\n" + @@ -2505,7 +2551,8 @@ const file_internal_native_proto_native_proto_rawDesc = "" + "\x0eVideoLogStatus\x12\r.native.Empty\x1a\x1e.native.VideoLogStatusResponse\x12)\n" + "\tVideoStop\x12\r.native.Empty\x1a\r.native.Empty\x12*\n" + "\n" + - "VideoStart\x12\r.native.Empty\x1a\r.native.Empty\x12?\n" + + "VideoStart\x12\r.native.Empty\x1a\r.native.Empty\x12C\n" + + "\x10VideoGetSnapshot\x12\r.native.Empty\x1a .native.VideoGetSnapshotResponse\x12?\n" + "\x0eGetLVGLVersion\x12\r.native.Empty\x1a\x1e.native.GetLVGLVersionResponse\x12@\n" + "\tUIObjHide\x12\x18.native.UIObjHideRequest\x1a\x19.native.UIObjHideResponse\x12@\n" + "\tUIObjShow\x12\x18.native.UIObjShowRequest\x1a\x19.native.UIObjShowResponse\x122\n" + @@ -2540,7 +2587,7 @@ func file_internal_native_proto_native_proto_rawDescGZIP() []byte { return file_internal_native_proto_native_proto_rawDescData } -var file_internal_native_proto_native_proto_msgTypes = make([]protoimpl.MessageInfo, 48) +var file_internal_native_proto_native_proto_msgTypes = make([]protoimpl.MessageInfo, 49) var file_internal_native_proto_native_proto_goTypes = []any{ (*Empty)(nil), // 0: native.Empty (*IsReadyRequest)(nil), // 1: native.IsReadyRequest @@ -2556,44 +2603,45 @@ var file_internal_native_proto_native_proto_goTypes = []any{ (*VideoSetEDIDRequest)(nil), // 11: native.VideoSetEDIDRequest (*VideoGetEDIDResponse)(nil), // 12: native.VideoGetEDIDResponse (*VideoLogStatusResponse)(nil), // 13: native.VideoLogStatusResponse - (*GetLVGLVersionResponse)(nil), // 14: native.GetLVGLVersionResponse - (*UIObjHideRequest)(nil), // 15: native.UIObjHideRequest - (*UIObjHideResponse)(nil), // 16: native.UIObjHideResponse - (*UIObjShowRequest)(nil), // 17: native.UIObjShowRequest - (*UIObjShowResponse)(nil), // 18: native.UIObjShowResponse - (*UISetVarRequest)(nil), // 19: native.UISetVarRequest - (*UIGetVarRequest)(nil), // 20: native.UIGetVarRequest - (*UIGetVarResponse)(nil), // 21: native.UIGetVarResponse - (*UIObjAddStateRequest)(nil), // 22: native.UIObjAddStateRequest - (*UIObjAddStateResponse)(nil), // 23: native.UIObjAddStateResponse - (*UIObjClearStateRequest)(nil), // 24: native.UIObjClearStateRequest - (*UIObjClearStateResponse)(nil), // 25: native.UIObjClearStateResponse - (*UIObjAddFlagRequest)(nil), // 26: native.UIObjAddFlagRequest - (*UIObjAddFlagResponse)(nil), // 27: native.UIObjAddFlagResponse - (*UIObjClearFlagRequest)(nil), // 28: native.UIObjClearFlagRequest - (*UIObjClearFlagResponse)(nil), // 29: native.UIObjClearFlagResponse - (*UIObjSetOpacityRequest)(nil), // 30: native.UIObjSetOpacityRequest - (*UIObjSetOpacityResponse)(nil), // 31: native.UIObjSetOpacityResponse - (*UIObjFadeInRequest)(nil), // 32: native.UIObjFadeInRequest - (*UIObjFadeInResponse)(nil), // 33: native.UIObjFadeInResponse - (*UIObjFadeOutRequest)(nil), // 34: native.UIObjFadeOutRequest - (*UIObjFadeOutResponse)(nil), // 35: native.UIObjFadeOutResponse - (*UIObjSetLabelTextRequest)(nil), // 36: native.UIObjSetLabelTextRequest - (*UIObjSetLabelTextResponse)(nil), // 37: native.UIObjSetLabelTextResponse - (*UIObjSetImageSrcRequest)(nil), // 38: native.UIObjSetImageSrcRequest - (*UIObjSetImageSrcResponse)(nil), // 39: native.UIObjSetImageSrcResponse - (*DisplaySetRotationRequest)(nil), // 40: native.DisplaySetRotationRequest - (*DisplaySetRotationResponse)(nil), // 41: native.DisplaySetRotationResponse - (*UpdateLabelIfChangedRequest)(nil), // 42: native.UpdateLabelIfChangedRequest - (*UpdateLabelAndChangeVisibilityRequest)(nil), // 43: native.UpdateLabelAndChangeVisibilityRequest - (*SwitchToScreenIfRequest)(nil), // 44: native.SwitchToScreenIfRequest - (*SwitchToScreenIfDifferentRequest)(nil), // 45: native.SwitchToScreenIfDifferentRequest - (*Event)(nil), // 46: native.Event - (*VideoFrame)(nil), // 47: native.VideoFrame + (*VideoGetSnapshotResponse)(nil), // 14: native.VideoGetSnapshotResponse + (*GetLVGLVersionResponse)(nil), // 15: native.GetLVGLVersionResponse + (*UIObjHideRequest)(nil), // 16: native.UIObjHideRequest + (*UIObjHideResponse)(nil), // 17: native.UIObjHideResponse + (*UIObjShowRequest)(nil), // 18: native.UIObjShowRequest + (*UIObjShowResponse)(nil), // 19: native.UIObjShowResponse + (*UISetVarRequest)(nil), // 20: native.UISetVarRequest + (*UIGetVarRequest)(nil), // 21: native.UIGetVarRequest + (*UIGetVarResponse)(nil), // 22: native.UIGetVarResponse + (*UIObjAddStateRequest)(nil), // 23: native.UIObjAddStateRequest + (*UIObjAddStateResponse)(nil), // 24: native.UIObjAddStateResponse + (*UIObjClearStateRequest)(nil), // 25: native.UIObjClearStateRequest + (*UIObjClearStateResponse)(nil), // 26: native.UIObjClearStateResponse + (*UIObjAddFlagRequest)(nil), // 27: native.UIObjAddFlagRequest + (*UIObjAddFlagResponse)(nil), // 28: native.UIObjAddFlagResponse + (*UIObjClearFlagRequest)(nil), // 29: native.UIObjClearFlagRequest + (*UIObjClearFlagResponse)(nil), // 30: native.UIObjClearFlagResponse + (*UIObjSetOpacityRequest)(nil), // 31: native.UIObjSetOpacityRequest + (*UIObjSetOpacityResponse)(nil), // 32: native.UIObjSetOpacityResponse + (*UIObjFadeInRequest)(nil), // 33: native.UIObjFadeInRequest + (*UIObjFadeInResponse)(nil), // 34: native.UIObjFadeInResponse + (*UIObjFadeOutRequest)(nil), // 35: native.UIObjFadeOutRequest + (*UIObjFadeOutResponse)(nil), // 36: native.UIObjFadeOutResponse + (*UIObjSetLabelTextRequest)(nil), // 37: native.UIObjSetLabelTextRequest + (*UIObjSetLabelTextResponse)(nil), // 38: native.UIObjSetLabelTextResponse + (*UIObjSetImageSrcRequest)(nil), // 39: native.UIObjSetImageSrcRequest + (*UIObjSetImageSrcResponse)(nil), // 40: native.UIObjSetImageSrcResponse + (*DisplaySetRotationRequest)(nil), // 41: native.DisplaySetRotationRequest + (*DisplaySetRotationResponse)(nil), // 42: native.DisplaySetRotationResponse + (*UpdateLabelIfChangedRequest)(nil), // 43: native.UpdateLabelIfChangedRequest + (*UpdateLabelAndChangeVisibilityRequest)(nil), // 44: native.UpdateLabelAndChangeVisibilityRequest + (*SwitchToScreenIfRequest)(nil), // 45: native.SwitchToScreenIfRequest + (*SwitchToScreenIfDifferentRequest)(nil), // 46: native.SwitchToScreenIfDifferentRequest + (*Event)(nil), // 47: native.Event + (*VideoFrame)(nil), // 48: native.VideoFrame } var file_internal_native_proto_native_proto_depIdxs = []int32{ 3, // 0: native.Event.video_state:type_name -> native.VideoState - 47, // 1: native.Event.video_frame:type_name -> native.VideoFrame + 48, // 1: native.Event.video_frame:type_name -> native.VideoFrame 1, // 2: native.NativeService.IsReady:input_type -> native.IsReadyRequest 4, // 3: native.NativeService.VideoSetSleepMode:input_type -> native.VideoSetSleepModeRequest 0, // 4: native.NativeService.VideoGetSleepMode:input_type -> native.Empty @@ -2607,63 +2655,65 @@ var file_internal_native_proto_native_proto_depIdxs = []int32{ 0, // 12: native.NativeService.VideoLogStatus:input_type -> native.Empty 0, // 13: native.NativeService.VideoStop:input_type -> native.Empty 0, // 14: native.NativeService.VideoStart:input_type -> native.Empty - 0, // 15: native.NativeService.GetLVGLVersion:input_type -> native.Empty - 15, // 16: native.NativeService.UIObjHide:input_type -> native.UIObjHideRequest - 17, // 17: native.NativeService.UIObjShow:input_type -> native.UIObjShowRequest - 19, // 18: native.NativeService.UISetVar:input_type -> native.UISetVarRequest - 20, // 19: native.NativeService.UIGetVar:input_type -> native.UIGetVarRequest - 22, // 20: native.NativeService.UIObjAddState:input_type -> native.UIObjAddStateRequest - 24, // 21: native.NativeService.UIObjClearState:input_type -> native.UIObjClearStateRequest - 26, // 22: native.NativeService.UIObjAddFlag:input_type -> native.UIObjAddFlagRequest - 28, // 23: native.NativeService.UIObjClearFlag:input_type -> native.UIObjClearFlagRequest - 30, // 24: native.NativeService.UIObjSetOpacity:input_type -> native.UIObjSetOpacityRequest - 32, // 25: native.NativeService.UIObjFadeIn:input_type -> native.UIObjFadeInRequest - 34, // 26: native.NativeService.UIObjFadeOut:input_type -> native.UIObjFadeOutRequest - 36, // 27: native.NativeService.UIObjSetLabelText:input_type -> native.UIObjSetLabelTextRequest - 38, // 28: native.NativeService.UIObjSetImageSrc:input_type -> native.UIObjSetImageSrcRequest - 40, // 29: native.NativeService.DisplaySetRotation:input_type -> native.DisplaySetRotationRequest - 42, // 30: native.NativeService.UpdateLabelIfChanged:input_type -> native.UpdateLabelIfChangedRequest - 43, // 31: native.NativeService.UpdateLabelAndChangeVisibility:input_type -> native.UpdateLabelAndChangeVisibilityRequest - 44, // 32: native.NativeService.SwitchToScreenIf:input_type -> native.SwitchToScreenIfRequest - 45, // 33: native.NativeService.SwitchToScreenIfDifferent:input_type -> native.SwitchToScreenIfDifferentRequest - 0, // 34: native.NativeService.DoNotUseThisIsForCrashTestingOnly:input_type -> native.Empty - 0, // 35: native.NativeService.StreamEvents:input_type -> native.Empty - 2, // 36: native.NativeService.IsReady:output_type -> native.IsReadyResponse - 0, // 37: native.NativeService.VideoSetSleepMode:output_type -> native.Empty - 5, // 38: native.NativeService.VideoGetSleepMode:output_type -> native.VideoGetSleepModeResponse - 6, // 39: native.NativeService.VideoSleepModeSupported:output_type -> native.VideoSleepModeSupportedResponse - 0, // 40: native.NativeService.VideoSetQualityFactor:output_type -> native.Empty - 8, // 41: native.NativeService.VideoGetQualityFactor:output_type -> native.VideoGetQualityFactorResponse - 0, // 42: native.NativeService.VideoSetCodecType:output_type -> native.Empty - 10, // 43: native.NativeService.VideoGetCodecType:output_type -> native.VideoGetCodecTypeResponse - 0, // 44: native.NativeService.VideoSetEDID:output_type -> native.Empty - 12, // 45: native.NativeService.VideoGetEDID:output_type -> native.VideoGetEDIDResponse - 13, // 46: native.NativeService.VideoLogStatus:output_type -> native.VideoLogStatusResponse - 0, // 47: native.NativeService.VideoStop:output_type -> native.Empty - 0, // 48: native.NativeService.VideoStart:output_type -> native.Empty - 14, // 49: native.NativeService.GetLVGLVersion:output_type -> native.GetLVGLVersionResponse - 16, // 50: native.NativeService.UIObjHide:output_type -> native.UIObjHideResponse - 18, // 51: native.NativeService.UIObjShow:output_type -> native.UIObjShowResponse - 0, // 52: native.NativeService.UISetVar:output_type -> native.Empty - 21, // 53: native.NativeService.UIGetVar:output_type -> native.UIGetVarResponse - 23, // 54: native.NativeService.UIObjAddState:output_type -> native.UIObjAddStateResponse - 25, // 55: native.NativeService.UIObjClearState:output_type -> native.UIObjClearStateResponse - 27, // 56: native.NativeService.UIObjAddFlag:output_type -> native.UIObjAddFlagResponse - 29, // 57: native.NativeService.UIObjClearFlag:output_type -> native.UIObjClearFlagResponse - 31, // 58: native.NativeService.UIObjSetOpacity:output_type -> native.UIObjSetOpacityResponse - 33, // 59: native.NativeService.UIObjFadeIn:output_type -> native.UIObjFadeInResponse - 35, // 60: native.NativeService.UIObjFadeOut:output_type -> native.UIObjFadeOutResponse - 37, // 61: native.NativeService.UIObjSetLabelText:output_type -> native.UIObjSetLabelTextResponse - 39, // 62: native.NativeService.UIObjSetImageSrc:output_type -> native.UIObjSetImageSrcResponse - 41, // 63: native.NativeService.DisplaySetRotation:output_type -> native.DisplaySetRotationResponse - 0, // 64: native.NativeService.UpdateLabelIfChanged:output_type -> native.Empty - 0, // 65: native.NativeService.UpdateLabelAndChangeVisibility:output_type -> native.Empty - 0, // 66: native.NativeService.SwitchToScreenIf:output_type -> native.Empty - 0, // 67: native.NativeService.SwitchToScreenIfDifferent:output_type -> native.Empty - 0, // 68: native.NativeService.DoNotUseThisIsForCrashTestingOnly:output_type -> native.Empty - 46, // 69: native.NativeService.StreamEvents:output_type -> native.Event - 36, // [36:70] is the sub-list for method output_type - 2, // [2:36] is the sub-list for method input_type + 0, // 15: native.NativeService.VideoGetSnapshot:input_type -> native.Empty + 0, // 16: native.NativeService.GetLVGLVersion:input_type -> native.Empty + 16, // 17: native.NativeService.UIObjHide:input_type -> native.UIObjHideRequest + 18, // 18: native.NativeService.UIObjShow:input_type -> native.UIObjShowRequest + 20, // 19: native.NativeService.UISetVar:input_type -> native.UISetVarRequest + 21, // 20: native.NativeService.UIGetVar:input_type -> native.UIGetVarRequest + 23, // 21: native.NativeService.UIObjAddState:input_type -> native.UIObjAddStateRequest + 25, // 22: native.NativeService.UIObjClearState:input_type -> native.UIObjClearStateRequest + 27, // 23: native.NativeService.UIObjAddFlag:input_type -> native.UIObjAddFlagRequest + 29, // 24: native.NativeService.UIObjClearFlag:input_type -> native.UIObjClearFlagRequest + 31, // 25: native.NativeService.UIObjSetOpacity:input_type -> native.UIObjSetOpacityRequest + 33, // 26: native.NativeService.UIObjFadeIn:input_type -> native.UIObjFadeInRequest + 35, // 27: native.NativeService.UIObjFadeOut:input_type -> native.UIObjFadeOutRequest + 37, // 28: native.NativeService.UIObjSetLabelText:input_type -> native.UIObjSetLabelTextRequest + 39, // 29: native.NativeService.UIObjSetImageSrc:input_type -> native.UIObjSetImageSrcRequest + 41, // 30: native.NativeService.DisplaySetRotation:input_type -> native.DisplaySetRotationRequest + 43, // 31: native.NativeService.UpdateLabelIfChanged:input_type -> native.UpdateLabelIfChangedRequest + 44, // 32: native.NativeService.UpdateLabelAndChangeVisibility:input_type -> native.UpdateLabelAndChangeVisibilityRequest + 45, // 33: native.NativeService.SwitchToScreenIf:input_type -> native.SwitchToScreenIfRequest + 46, // 34: native.NativeService.SwitchToScreenIfDifferent:input_type -> native.SwitchToScreenIfDifferentRequest + 0, // 35: native.NativeService.DoNotUseThisIsForCrashTestingOnly:input_type -> native.Empty + 0, // 36: native.NativeService.StreamEvents:input_type -> native.Empty + 2, // 37: native.NativeService.IsReady:output_type -> native.IsReadyResponse + 0, // 38: native.NativeService.VideoSetSleepMode:output_type -> native.Empty + 5, // 39: native.NativeService.VideoGetSleepMode:output_type -> native.VideoGetSleepModeResponse + 6, // 40: native.NativeService.VideoSleepModeSupported:output_type -> native.VideoSleepModeSupportedResponse + 0, // 41: native.NativeService.VideoSetQualityFactor:output_type -> native.Empty + 8, // 42: native.NativeService.VideoGetQualityFactor:output_type -> native.VideoGetQualityFactorResponse + 0, // 43: native.NativeService.VideoSetCodecType:output_type -> native.Empty + 10, // 44: native.NativeService.VideoGetCodecType:output_type -> native.VideoGetCodecTypeResponse + 0, // 45: native.NativeService.VideoSetEDID:output_type -> native.Empty + 12, // 46: native.NativeService.VideoGetEDID:output_type -> native.VideoGetEDIDResponse + 13, // 47: native.NativeService.VideoLogStatus:output_type -> native.VideoLogStatusResponse + 0, // 48: native.NativeService.VideoStop:output_type -> native.Empty + 0, // 49: native.NativeService.VideoStart:output_type -> native.Empty + 14, // 50: native.NativeService.VideoGetSnapshot:output_type -> native.VideoGetSnapshotResponse + 15, // 51: native.NativeService.GetLVGLVersion:output_type -> native.GetLVGLVersionResponse + 17, // 52: native.NativeService.UIObjHide:output_type -> native.UIObjHideResponse + 19, // 53: native.NativeService.UIObjShow:output_type -> native.UIObjShowResponse + 0, // 54: native.NativeService.UISetVar:output_type -> native.Empty + 22, // 55: native.NativeService.UIGetVar:output_type -> native.UIGetVarResponse + 24, // 56: native.NativeService.UIObjAddState:output_type -> native.UIObjAddStateResponse + 26, // 57: native.NativeService.UIObjClearState:output_type -> native.UIObjClearStateResponse + 28, // 58: native.NativeService.UIObjAddFlag:output_type -> native.UIObjAddFlagResponse + 30, // 59: native.NativeService.UIObjClearFlag:output_type -> native.UIObjClearFlagResponse + 32, // 60: native.NativeService.UIObjSetOpacity:output_type -> native.UIObjSetOpacityResponse + 34, // 61: native.NativeService.UIObjFadeIn:output_type -> native.UIObjFadeInResponse + 36, // 62: native.NativeService.UIObjFadeOut:output_type -> native.UIObjFadeOutResponse + 38, // 63: native.NativeService.UIObjSetLabelText:output_type -> native.UIObjSetLabelTextResponse + 40, // 64: native.NativeService.UIObjSetImageSrc:output_type -> native.UIObjSetImageSrcResponse + 42, // 65: native.NativeService.DisplaySetRotation:output_type -> native.DisplaySetRotationResponse + 0, // 66: native.NativeService.UpdateLabelIfChanged:output_type -> native.Empty + 0, // 67: native.NativeService.UpdateLabelAndChangeVisibility:output_type -> native.Empty + 0, // 68: native.NativeService.SwitchToScreenIf:output_type -> native.Empty + 0, // 69: native.NativeService.SwitchToScreenIfDifferent:output_type -> native.Empty + 0, // 70: native.NativeService.DoNotUseThisIsForCrashTestingOnly:output_type -> native.Empty + 47, // 71: native.NativeService.StreamEvents:output_type -> native.Event + 37, // [37:72] is the sub-list for method output_type + 2, // [2:37] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension extendee 0, // [0:2] is the sub-list for field type_name @@ -2674,7 +2724,7 @@ func file_internal_native_proto_native_proto_init() { if File_internal_native_proto_native_proto != nil { return } - file_internal_native_proto_native_proto_msgTypes[46].OneofWrappers = []any{ + file_internal_native_proto_native_proto_msgTypes[47].OneofWrappers = []any{ (*Event_VideoState)(nil), (*Event_IndevEvent)(nil), (*Event_RpcEvent)(nil), @@ -2686,7 +2736,7 @@ func file_internal_native_proto_native_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_internal_native_proto_native_proto_rawDesc), len(file_internal_native_proto_native_proto_rawDesc)), NumEnums: 0, - NumMessages: 48, + NumMessages: 49, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/native/proto/native.proto b/internal/native/proto/native.proto index 8186af14d..dfad251e7 100644 --- a/internal/native/proto/native.proto +++ b/internal/native/proto/native.proto @@ -22,6 +22,7 @@ service NativeService { rpc VideoLogStatus(Empty) returns (VideoLogStatusResponse); rpc VideoStop(Empty) returns (Empty); rpc VideoStart(Empty) returns (Empty); + rpc VideoGetSnapshot(Empty) returns (VideoGetSnapshotResponse); // UI methods rpc GetLVGLVersion(Empty) returns (GetLVGLVersionResponse); @@ -110,6 +111,10 @@ message VideoLogStatusResponse { string status = 1; } +message VideoGetSnapshotResponse { + bytes jpeg = 1; +} + message GetLVGLVersionResponse { string version = 1; } diff --git a/internal/native/proto/native_grpc.pb.go b/internal/native/proto/native_grpc.pb.go index 9a11de683..7346b8d98 100644 --- a/internal/native/proto/native_grpc.pb.go +++ b/internal/native/proto/native_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.6.1 -// - protoc v3.21.12 +// - protoc-gen-go-grpc v1.6.2 +// - protoc v5.29.3 // source: internal/native/proto/native.proto package proto @@ -32,6 +32,7 @@ const ( NativeService_VideoLogStatus_FullMethodName = "/native.NativeService/VideoLogStatus" NativeService_VideoStop_FullMethodName = "/native.NativeService/VideoStop" NativeService_VideoStart_FullMethodName = "/native.NativeService/VideoStart" + NativeService_VideoGetSnapshot_FullMethodName = "/native.NativeService/VideoGetSnapshot" NativeService_GetLVGLVersion_FullMethodName = "/native.NativeService/GetLVGLVersion" NativeService_UIObjHide_FullMethodName = "/native.NativeService/UIObjHide" NativeService_UIObjShow_FullMethodName = "/native.NativeService/UIObjShow" @@ -76,6 +77,7 @@ type NativeServiceClient interface { VideoLogStatus(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoLogStatusResponse, error) VideoStop(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) VideoStart(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) + VideoGetSnapshot(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetSnapshotResponse, error) // UI methods GetLVGLVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetLVGLVersionResponse, error) UIObjHide(ctx context.Context, in *UIObjHideRequest, opts ...grpc.CallOption) (*UIObjHideResponse, error) @@ -240,6 +242,16 @@ func (c *nativeServiceClient) VideoStart(ctx context.Context, in *Empty, opts .. return out, nil } +func (c *nativeServiceClient) VideoGetSnapshot(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VideoGetSnapshotResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(VideoGetSnapshotResponse) + err := c.cc.Invoke(ctx, NativeService_VideoGetSnapshot_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *nativeServiceClient) GetLVGLVersion(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetLVGLVersionResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(GetLVGLVersionResponse) @@ -480,6 +492,7 @@ type NativeServiceServer interface { VideoLogStatus(context.Context, *Empty) (*VideoLogStatusResponse, error) VideoStop(context.Context, *Empty) (*Empty, error) VideoStart(context.Context, *Empty) (*Empty, error) + VideoGetSnapshot(context.Context, *Empty) (*VideoGetSnapshotResponse, error) // UI methods GetLVGLVersion(context.Context, *Empty) (*GetLVGLVersionResponse, error) UIObjHide(context.Context, *UIObjHideRequest) (*UIObjHideResponse, error) @@ -553,6 +566,9 @@ func (UnimplementedNativeServiceServer) VideoStop(context.Context, *Empty) (*Emp func (UnimplementedNativeServiceServer) VideoStart(context.Context, *Empty) (*Empty, error) { return nil, status.Error(codes.Unimplemented, "method VideoStart not implemented") } +func (UnimplementedNativeServiceServer) VideoGetSnapshot(context.Context, *Empty) (*VideoGetSnapshotResponse, error) { + return nil, status.Error(codes.Unimplemented, "method VideoGetSnapshot not implemented") +} func (UnimplementedNativeServiceServer) GetLVGLVersion(context.Context, *Empty) (*GetLVGLVersionResponse, error) { return nil, status.Error(codes.Unimplemented, "method GetLVGLVersion not implemented") } @@ -871,6 +887,24 @@ func _NativeService_VideoStart_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _NativeService_VideoGetSnapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NativeServiceServer).VideoGetSnapshot(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: NativeService_VideoGetSnapshot_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NativeServiceServer).VideoGetSnapshot(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _NativeService_GetLVGLVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Empty) if err := dec(in); err != nil { @@ -1301,6 +1335,10 @@ var NativeService_ServiceDesc = grpc.ServiceDesc{ MethodName: "VideoStart", Handler: _NativeService_VideoStart_Handler, }, + { + MethodName: "VideoGetSnapshot", + Handler: _NativeService_VideoGetSnapshot_Handler, + }, { MethodName: "GetLVGLVersion", Handler: _NativeService_GetLVGLVersion_Handler, diff --git a/internal/native/proxy.go b/internal/native/proxy.go index 93e8d1abc..9bb3644a1 100644 --- a/internal/native/proxy.go +++ b/internal/native/proxy.go @@ -505,12 +505,12 @@ func (p *NativeProxy) Stop() error { return nil } -func zeroValue[V string | bool | float64 | int]() V { +func zeroValue[V string | bool | float64 | int | []byte]() V { var v V return v } -func nativeProxyClientExec[K comparable, V string | bool | float64 | int](p *NativeProxy, fn func(*GRPCClient) (V, error)) (V, error) { +func nativeProxyClientExec[K comparable, V string | bool | float64 | int | []byte](p *NativeProxy, fn func(*GRPCClient) (V, error)) (V, error) { p.clientMu.RLock() defer p.clientMu.RUnlock() @@ -594,6 +594,14 @@ func (p *NativeProxy) VideoLogStatus() (string, error) { }) } +func (p *NativeProxy) VideoGetSnapshot() ([]byte, error) { + // []byte isn't `comparable`, so K (unused by nativeProxyClientExec) can't be + // instantiated as []byte too; bool is an arbitrary stand-in. + return nativeProxyClientExec[bool, []byte](p, func(client *GRPCClient) ([]byte, error) { + return client.VideoGetSnapshot() + }) +} + func (p *NativeProxy) VideoStop() error { return nativeProxyClientExecWithoutArgument(p, func(client *GRPCClient) error { return client.VideoStop() diff --git a/internal/native/video.go b/internal/native/video.go index 5b366073a..9118706da 100644 --- a/internal/native/video.go +++ b/internal/native/video.go @@ -1,12 +1,18 @@ package native import ( + "errors" "fmt" "os" "strings" "time" ) +// ErrVideoNotStreaming is returned by VideoGetSnapshot when there's no +// active video capture to snapshot (video only streams while at least one +// WebRTC viewer session is connected). +var ErrVideoNotStreaming = errors.New("video stream is not active") + const sleepModeFile = "/sys/devices/platform/ff470000.i2c/i2c-4/4-000f/sleep_mode" // DefaultEDID is the default EDID for the video stream. @@ -210,6 +216,15 @@ func (n *Native) VideoLogStatus() (string, error) { return videoLogStatus(), nil } +// VideoGetSnapshot captures a single JPEG-encoded frame of the current video feed. +// Returns ErrVideoNotStreaming if no video capture is currently running. +func (n *Native) VideoGetSnapshot() ([]byte, error) { + n.videoLock.Lock() + defer n.videoLock.Unlock() + + return videoGetSnapshot() +} + // VideoStop stops the video stream. func (n *Native) VideoStop() error { n.videoLock.Lock() diff --git a/video.go b/video.go index e981979d6..6cb566c98 100644 --- a/video.go +++ b/video.go @@ -2,9 +2,13 @@ package kvm import ( "context" + "errors" "fmt" + "net/http" "time" + "github.com/gin-gonic/gin" + "github.com/jetkvm/kvm/internal/native" "github.com/jetkvm/kvm/internal/sync" ) @@ -37,6 +41,22 @@ func rpcGetVideoState() (native.VideoState, error) { return lastVideoState, nil } +// handleSnapshot returns a single JPEG-encoded frame of the current video +// feed. Video only streams while a WebRTC session is connected, so this +// responds 503 if there's nothing to snapshot. +func handleSnapshot(c *gin.Context) { + jpeg, err := nativeInstance.VideoGetSnapshot() + if err != nil { + if errors.Is(err, native.ErrVideoNotStreaming) { + c.JSON(http.StatusServiceUnavailable, gin.H{"error": "video stream is not active"}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.Data(http.StatusOK, "image/jpeg", jpeg) +} + var ( hostDisplayAdvertiseLock = sync.Mutex{} hostDisplayAdvertised bool diff --git a/web.go b/web.go index baa94ff48..a87f008df 100644 --- a/web.go +++ b/web.go @@ -228,6 +228,7 @@ func setupRouter() *gin.Engine { protected.POST("/device/send-wol/:mac-addr", handleSendWOLMagicPacket) protected.GET("/diagnostics", handleDiagnosticsDownload) + protected.GET("/snapshot", handleSnapshot) } // Catch-all route for SPA From 6bb5c318ab068e31bfdf163bc198ef8646ce8c9e Mon Sep 17 00:00:00 2001 From: Lars-Erik Stenholm Date: Sat, 22 Aug 2026 22:34:06 +0200 Subject: [PATCH 2/4] Rework screenshot API: dedicated URLs, auto-start, dual auth - Fix a forward-declaration ordering bug that broke the native build (get_streaming_flag/get_streaming_stopped used before declared). - Split the single /snapshot route into format-specific /screenshot.jpg and /screenshot.png (PNG re-encoded from the hardware JPEG capture in Go, since the capture hardware only produces JPEG). - Add apiAuthMiddleware: accepts either the browser's session cookie or HTTP Basic Auth against the device password (noPassword mode is left open), so both a logged-in browser tab and a headless script/CI runner can use the same URL. - Auto-start video capture on demand when nothing is currently streaming (primary use case is HIL test rigs grabbing a screenshot before/during/ after a run, with no browser session open) and stop it again afterward unless a real WebRTC session or another concurrent screenshot request still needs it, guarded by a small in-flight counter to avoid one request's cleanup cutting off another's capture. Verified end-to-end on hardware: cold-start capture, repeated auto start/stop cycles with no leaked state, and both cookie- and Basic-Auth-gated access. Co-Authored-By: Claude Sonnet 5 --- internal/native/cgo/video.c | 2 + video.go | 103 ++++++++++++++++++++++++++++++++---- web.go | 42 ++++++++++++++- 3 files changed, 135 insertions(+), 12 deletions(-) diff --git a/internal/native/cgo/video.c b/internal/native/cgo/video.c index 5e936559d..3e99e1df2 100644 --- a/internal/native/cgo/video.c +++ b/internal/native/cgo/video.c @@ -49,6 +49,8 @@ int codec_type = 0; static void *venc_read_stream(void *arg); static int32_t venc_jpeg_start(int32_t width, int32_t height); static void venc_jpeg_stop(void); +bool get_streaming_flag(); +bool get_streaming_stopped(); RK_U64 get_us() { diff --git a/video.go b/video.go index 6cb566c98..dbfe9c557 100644 --- a/video.go +++ b/video.go @@ -1,9 +1,12 @@ package kvm import ( + "bytes" "context" "errors" "fmt" + "image/jpeg" + "image/png" "net/http" "time" @@ -41,20 +44,98 @@ func rpcGetVideoState() (native.VideoState, error) { return lastVideoState, nil } -// handleSnapshot returns a single JPEG-encoded frame of the current video -// feed. Video only streams while a WebRTC session is connected, so this -// responds 503 if there's nothing to snapshot. -func handleSnapshot(c *gin.Context) { - jpeg, err := nativeInstance.VideoGetSnapshot() - if err != nil { - if errors.Is(err, native.ErrVideoNotStreaming) { - c.JSON(http.StatusServiceUnavailable, gin.H{"error": "video stream is not active"}) - return +const ( + screenshotAutoStartTimeout = 10 * time.Second + screenshotSnapshotRetryWait = 300 * time.Millisecond +) + +var ( + screenshotInFlightMu sync.Mutex + screenshotInFlight int +) + +// captureScreenshot returns a JPEG snapshot, starting video capture on +// demand if nothing is currently streaming (e.g. no browser session is +// open) and stopping it again afterward, unless a real WebRTC session or +// another concurrent screenshot request still needs it running. +// VideoStart is idempotent (a no-op if a session already has capture +// running), so it's always safe to call here. +func captureScreenshot() ([]byte, error) { + screenshotInFlightMu.Lock() + screenshotInFlight++ + screenshotInFlightMu.Unlock() + defer func() { + screenshotInFlightMu.Lock() + screenshotInFlight-- + screenshotInFlightMu.Unlock() + }() + + deadline := time.Now().Add(screenshotAutoStartTimeout) + _ = nativeInstance.VideoStart() + defer func() { + screenshotInFlightMu.Lock() + soleRequester := screenshotInFlight <= 1 + screenshotInFlightMu.Unlock() + if soleRequester && getActiveSessions() == 0 { + _ = nativeInstance.VideoStop() + } + }() + + for { + jpegBytes, err := nativeInstance.VideoGetSnapshot() + if err == nil { + return jpegBytes, nil } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + if !errors.Is(err, native.ErrVideoNotStreaming) || !time.Now().Before(deadline) { + return nil, err + } + time.Sleep(screenshotSnapshotRetryWait) + } +} + +// handleScreenshotJPEG returns a single JPEG-encoded frame of the current +// video feed, straight from the native capture. Starts video capture on +// demand if nothing is currently streaming. +func handleScreenshotJPEG(c *gin.Context) { + jpegBytes, err := captureScreenshot() + if err != nil { + writeScreenshotError(c, err) + return + } + c.Data(http.StatusOK, "image/jpeg", jpegBytes) +} + +// handleScreenshotPNG returns the same frame as handleScreenshotJPEG, +// re-encoded as PNG. The capture hardware only produces JPEG, so this costs +// a decode+re-encode on the device CPU; fine for an occasional snapshot. +func handleScreenshotPNG(c *gin.Context) { + jpegBytes, err := captureScreenshot() + if err != nil { + writeScreenshotError(c, err) + return + } + + img, err := jpeg.Decode(bytes.NewReader(jpegBytes)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to decode captured frame"}) + return + } + + var buf bytes.Buffer + if err := png.Encode(&buf, img); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to encode PNG"}) + return + } + + c.Data(http.StatusOK, "image/png", buf.Bytes()) +} + +func writeScreenshotError(c *gin.Context, err error) { + if errors.Is(err, native.ErrVideoNotStreaming) { + c.JSON(http.StatusServiceUnavailable, gin.H{"error": "no video signal detected (timed out starting capture)"}) return } - c.Data(http.StatusOK, "image/jpeg", jpeg) + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } var ( diff --git a/web.go b/web.go index a87f008df..9bf7a9a41 100644 --- a/web.go +++ b/web.go @@ -228,9 +228,13 @@ func setupRouter() *gin.Engine { protected.POST("/device/send-wol/:mac-addr", handleSendWOLMagicPacket) protected.GET("/diagnostics", handleDiagnosticsDownload) - protected.GET("/snapshot", handleSnapshot) } + // Screenshot endpoints: for headless/API consumers (CI, HIL rigs), not the + // browser UI, so they use apiAuthMiddleware rather than cookie auth. + r.GET("/screenshot.jpg", apiAuthMiddleware(), handleScreenshotJPEG) + r.GET("/screenshot.png", apiAuthMiddleware(), handleScreenshotPNG) + // Catch-all route for SPA r.NoRoute(func(c *gin.Context) { if c.Request.Method == "GET" && c.NegotiateFormat(gin.MIMEHTML) == gin.MIMEHTML { @@ -629,6 +633,42 @@ func basicAuthProtectedMiddleware(requireDeveloperMode bool) gin.HandlerFunc { } } +// apiAuthMiddleware gates endpoints meant for both headless/programmatic +// access (CI, HIL test rigs) and the browser UI. In noPassword mode it lets +// requests through with no credentials, same trusted-network assumption as +// the cookie-protected routes. In password mode it accepts either the same +// session cookie protectedMiddleware checks (so an already-logged-in tab can +// just load the URL directly) or HTTP Basic Auth against the device +// password with the username ignored (so a script can just +// `curl -u api:`). +func apiAuthMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + if config.LocalAuthMode == "noPassword" { + c.Next() + return + } + + if authToken, err := c.Cookie("authToken"); err == nil && authToken != "" && authToken == config.LocalAuthToken { + c.Next() + return + } + + _, password, ok := c.Request.BasicAuth() + if !ok { + c.Header("WWW-Authenticate", "Basic realm=\"JetKVM\"") + sendErrorJsonThenAbort(c, http.StatusUnauthorized, "Basic auth is required") + return + } + + if err := bcrypt.CompareHashAndPassword([]byte(config.HashedPassword), []byte(password)); err != nil { + sendErrorJsonThenAbort(c, http.StatusUnauthorized, "Invalid password") + return + } + + c.Next() + } +} + func getBindAddress(listenPort int) string { // Determine the binding address based on the config var bindAddress string From 275a9b639bbdc245c5a0174edf522241de15c693 Mon Sep 17 00:00:00 2001 From: Lars-Erik Stenholm Date: Sun, 23 Aug 2026 13:24:58 +0200 Subject: [PATCH 3/4] Address code-review findings: bound snapshot latency and lock hold - Shrink the JPEG snapshot channel's SendFrame/GetStream timeouts (2000ms + retry + 200ms -> 150ms each, single attempt) so a slow/failing encode can no longer stall the primary V4L2 capture loop for seconds; a failed attempt is simply skipped and retried against the next frame instead of retried in place. - Shrink video_get_snapshot()'s internal wait from 500ms to 300ms, since it runs under cgoLock (shared by every native call, including UI ticks) and directly bounds how long unrelated native operations get blocked. - Fix captureScreenshot()'s auto-start retry loop to retry on any error until the deadline, not just ErrVideoNotStreaming -- the native side also returns transient per-attempt errors (encode timeout, no frame yet) while capture is spinning up, which need retrying too. Re-verified end-to-end on hardware after these changes: cold-start capture still succeeds (including the slower ~6s cases, which now correctly retry through transient errors instead of failing), and no visible stutter on an active live view while concurrently fetching a screenshot. Co-Authored-By: Claude Sonnet 5 --- internal/native/cgo/video.c | 32 ++++++++++++++++++-------------- video.go | 7 ++++++- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/internal/native/cgo/video.c b/internal/native/cgo/video.c index 3e99e1df2..ccfadef69 100644 --- a/internal/native/cgo/video.c +++ b/internal/native/cgo/video.c @@ -451,21 +451,20 @@ static void complete_snapshot_request(uint8_t *buf, size_t len, int result) pthread_mutex_unlock(&snapshot_mutex); } -// Runs on the video capture thread. pFrame is the just-captured raw frame -// that was already handed to VENC_CHANNEL; reusing it here avoids capturing -// a second frame off V4L2 just for the snapshot. +// Runs on the video capture thread, so it must stay fast: it blocks +// VIDIOC_QBUF on the primary V4L2 capture loop (only input_buffer_count +// buffers deep) for as long as it takes. A single failed attempt here just +// means this frame's snapshot is skipped — the Go-side caller retries +// against the next captured frame rather than this function retrying +// in-place and doubling the stall. +// +// pFrame is the just-captured raw frame that was already handed to +// VENC_CHANNEL; reusing it here avoids capturing a second frame off V4L2 +// just for the snapshot. static void handle_snapshot_request(VIDEO_FRAME_INFO_S *pFrame) { - bool retried = false; -retry_send_jpeg_frame: - if (RK_MPI_VENC_SendFrame(VENC_CHANNEL_JPEG, pFrame, 2000) != RK_SUCCESS) + if (RK_MPI_VENC_SendFrame(VENC_CHANNEL_JPEG, pFrame, 150) != RK_SUCCESS) { - if (!retried) - { - retried = true; - usleep(1000llu); - goto retry_send_jpeg_frame; - } log_error("snapshot: RK_MPI_VENC_SendFrame(JPEG) failed"); complete_snapshot_request(NULL, 0, VIDEO_SNAPSHOT_ERR_ENCODE); return; @@ -480,7 +479,7 @@ static void handle_snapshot_request(VIDEO_FRAME_INFO_S *pFrame) return; } - int32_t ret = RK_MPI_VENC_GetStream(VENC_CHANNEL_JPEG, &stJpegStream, 200); + int32_t ret = RK_MPI_VENC_GetStream(VENC_CHANNEL_JPEG, &stJpegStream, 150); if (ret != RK_SUCCESS) { log_error("snapshot: RK_MPI_VENC_GetStream(JPEG) failed %#x", ret); @@ -529,9 +528,14 @@ int video_get_snapshot(uint8_t **out_buf, size_t *out_len) snapshot_len = 0; snapshot_result = 0; + // This function is called under the Go side's cgoLock (a single global + // mutex shared by every native call, including UI ticks), so the wait + // here directly stalls unrelated native operations for its duration. + // Kept short; the Go-side caller (captureScreenshot) retries across + // several calls rather than this one call waiting longer. struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_nsec += 500000000L; // 500ms deadline: one frame period plus JPEG encode headroom + ts.tv_nsec += 300000000L; // 300ms: one frame period plus JPEG encode headroom if (ts.tv_nsec >= 1000000000L) { ts.tv_sec += 1; diff --git a/video.go b/video.go index dbfe9c557..630e607d6 100644 --- a/video.go +++ b/video.go @@ -86,7 +86,12 @@ func captureScreenshot() ([]byte, error) { if err == nil { return jpegBytes, nil } - if !errors.Is(err, native.ErrVideoNotStreaming) || !time.Now().Before(deadline) { + // Retry on any error while the deadline allows, not just + // ErrVideoNotStreaming: the native side also returns transient + // per-attempt errors (encoder timeout, no frame yet) while capture + // is still spinning up or between frames, which should be retried + // against the next captured frame rather than failing immediately. + if !time.Now().Before(deadline) { return nil, err } time.Sleep(screenshotSnapshotRetryWait) From a732a7c2e20f910fa0d15b0358076527655575f5 Mon Sep 17 00:00:00 2001 From: Lars-Erik Stenholm Date: Mon, 24 Aug 2026 21:52:22 +0200 Subject: [PATCH 4/4] Add e2e coverage for the screenshot API Covers /screenshot.jpg and /screenshot.png: rejects requests with no credentials or a bogus session cookie, succeeds via HTTP Basic Auth and via a logged-in browser session (checking status, content-type, and that the body is a real image), and succeeds with no credentials at all in noPassword mode. Verified passing 9/9 against the branch build on real hardware. Co-Authored-By: Claude Sonnet 5 --- ui/e2e/screenshot-api.spec.ts | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 ui/e2e/screenshot-api.spec.ts diff --git a/ui/e2e/screenshot-api.spec.ts b/ui/e2e/screenshot-api.spec.ts new file mode 100644 index 000000000..262dfdd22 --- /dev/null +++ b/ui/e2e/screenshot-api.spec.ts @@ -0,0 +1,69 @@ +import { test, expect } from "@playwright/test"; + +import { ensureLocalAuthMode, getDeviceHost } from "./helpers"; + +const TEST_PASSWORD = "TestPassword123"; + +function basicAuthHeader(password: string): string { + return `Basic ${Buffer.from(`api:${password}`).toString("base64")}`; +} + +const SCREENSHOT_PATHS = ["/screenshot.jpg", "/screenshot.png"] as const; + +function expectedContentType(path: string): string { + return path.endsWith(".png") ? "image/png" : "image/jpeg"; +} + +test.describe("Screenshot API", () => { + test.setTimeout(60000); + + test.describe("password mode", () => { + test.beforeEach(async ({ page }) => { + // Leaves `page`'s browser context with a valid session cookie too, so + // page.request below is already authenticated like a logged-in tab. + await ensureLocalAuthMode(page, { mode: "password", password: TEST_PASSWORD }); + }); + + for (const path of SCREENSHOT_PATHS) { + test(`${path} rejects requests with no credentials`, async () => { + const res = await fetch(`http://${getDeviceHost()}${path}`); + expect(res.status).toBe(401); + }); + + test(`${path} rejects a bogus session cookie`, async () => { + const res = await fetch(`http://${getDeviceHost()}${path}`, { + headers: { Cookie: "authToken=not-a-real-token" }, + }); + expect(res.status).toBe(401); + }); + + test(`${path} succeeds with HTTP Basic Auth`, async () => { + const res = await fetch(`http://${getDeviceHost()}${path}`, { + headers: { Authorization: basicAuthHeader(TEST_PASSWORD) }, + }); + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe(expectedContentType(path)); + + const bytes = await res.arrayBuffer(); + expect(bytes.byteLength).toBeGreaterThan(1000); + }); + + test(`${path} succeeds with a logged-in browser session`, async ({ page }) => { + const res = await page.request.get(path); + expect(res.status()).toBe(200); + expect(res.headers()["content-type"]).toBe(expectedContentType(path)); + + const body = await res.body(); + expect(body.byteLength).toBeGreaterThan(1000); + }); + } + }); + + test("succeeds with no credentials in noPassword mode", async ({ page }) => { + await ensureLocalAuthMode(page, { mode: "noPassword" }); + + const res = await fetch(`http://${getDeviceHost()}/screenshot.jpg`); + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("image/jpeg"); + }); +});