ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
frame.cpp
Go to the documentation of this file.
1#include <emscripten/bind.h>
2#include <algorithm>
3#include <cstdint>
4#include <optional>
5#include <string>
6#include <vector>
7extern "C" {
9#include "../common/capture.h"
10#include "../mirror.h"
11}
12
14EMSCRIPTEN_DECLARE_VAL_TYPE(VisualizationSamples);
15
16// Retain the input allocation between frames; JS arrays and returned strings
17// remain owned by JavaScript. No heap view escapes this synchronous call.
19public:
20 std::optional<std::string> convert(RgbaBytes rgba, int width, int height, bool contain) {
21 const size_t length = rgba["byteLength"].as<size_t>();
22 if (width <= 0 || height <= 0 || static_cast<uint64_t>(width) * static_cast<uint64_t>(height) * 4 != length) {
23 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid mirror image: %dx%d, %zu bytes", width, height, length);
24 return std::nullopt;
25 }
26 input_.resize(length);
27 emscripten::val view = emscripten::val(emscripten::typed_memory_view(length, input_.data()));
28 view.call<void>("set", rgba);
29 char *frame = mirror_convert_frame(input_.data(), width, height, contain);
30 if (!frame) {
31 SET_ERRNO(ERROR_DISPLAY, "Mirror frame conversion failed");
32 return std::nullopt;
33 }
34 std::string result(frame);
35 mirror_free_string(frame);
36 return result;
37 }
38 int transform(RgbaBytes rgba, int width, int height) {
39 const size_t length = rgba["byteLength"].as<size_t>();
40 if (width <= 0 || height <= 0 || static_cast<uint64_t>(width) * static_cast<uint64_t>(height) * 4 != length)
41 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid capture image: %dx%d, %zu bytes", width, height, length);
42 input_.resize(length);
43 emscripten::val view = emscripten::val(emscripten::typed_memory_view(length, input_.data()));
44 view.call<void>("set", rgba);
45 const int result = browser_capture_transform_rgba(input_.data(), width, height);
46 if (!result) {
47 emscripten::val result_view = emscripten::val(emscripten::typed_memory_view(length, input_.data()));
48 rgba.call<void>("set", result_view);
49 }
50 return result;
51 }
52 void submitAudio(VisualizationSamples samples, int source) {
53 if (source != 0 && source != 1) {
54 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid audio visualization source: %d", source);
55 return;
56 }
57 const size_t length = samples["length"].as<size_t>();
58 if (!length)
59 return;
60 const size_t chunk_size = std::min(length, size_t{8192});
61 audio_.resize(chunk_size);
62 for (size_t offset = 0; offset < length;) {
63 const size_t count = std::min(chunk_size, length - offset);
64 emscripten::val part = samples.call<emscripten::val>("subarray", offset, offset + count);
65 emscripten::val view = emscripten::val(emscripten::typed_memory_view(count, audio_.data()));
66 view.call<void>("set", part);
67 mirror_submit_audio_samples(audio_.data(), static_cast<int>(count), source);
68 offset += count;
69 }
70 }
71 std::optional<std::string> renderAudio(unsigned width, unsigned height, int source) {
72 if (!width || !height || (source != 0 && source != 1)) {
73 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid audio visualization dimensions or source");
74 return std::nullopt;
75 }
77 if (!frame) {
78 SET_ERRNO(ERROR_DISPLAY, "Audio visualization rendering failed");
79 return std::nullopt;
80 }
81 std::string result(frame);
82 mirror_free_string(frame);
83 return result;
84 }
85
86private:
87 std::vector<uint8_t> input_;
88 std::vector<float> audio_;
89};
90
91EMSCRIPTEN_BINDINGS(ascii_chat_frame) {
92 emscripten::function("sessionRenderResetStabilizer", &session_render_reset_stabilizer);
93 emscripten::function("browser_capture_transform_required", &browser_capture_transform_required);
94 emscripten::register_type<RgbaBytes>("RgbaBytes", "Uint8Array | Uint8ClampedArray");
95 emscripten::register_type<VisualizationSamples>("VisualizationSamples", "Float32Array");
96 emscripten::class_<MirrorFrameBinding>("MirrorFrameBinding")
97 .constructor<>()
98 .function("convert", &MirrorFrameBinding::convert)
99 .function("transform", &MirrorFrameBinding::transform)
100 .function("submitAudio", &MirrorFrameBinding::submitAudio)
101 .function("renderAudio", &MirrorFrameBinding::renderAudio);
102}
Synchronized per-thread pending error stacks and value snapshots. SET_ERRNO pushes,...
#define SET_ERRNO(code,...)
void submitAudio(VisualizationSamples samples, int source)
Definition frame.cpp:52
std::optional< std::string > renderAudio(unsigned width, unsigned height, int source)
Definition frame.cpp:71
std::optional< std::string > convert(RgbaBytes rgba, int width, int height, bool contain)
Definition frame.cpp:20
int transform(RgbaBytes rgba, int width, int height)
Definition frame.cpp:38
audio_visualization_source_t source
Definition fft.c:24
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
EMSCRIPTEN_DECLARE_VAL_TYPE(RgbaBytes)
EMSCRIPTEN_BINDINGS(ascii_chat_frame)
Definition frame.cpp:91
unsigned long long uint64_t
Definition common.h:63
@ ERROR_DISPLAY
@ ERROR_INVALID_PARAM
void session_render_reset_stabilizer(void)
Definition mirror.c:82
char * mirror_convert_frame(uint8_t *rgba_data, int src_width, int src_height, int contain)
Definition mirror.c:108
void mirror_submit_audio_samples(const float *samples, int count, int source)
Definition mirror.c:312
char * mirror_render_audio_visualization(unsigned int width, unsigned int height, int source)
Definition mirror.c:320
void mirror_free_string(char *ptr)
Definition mirror.c:336
int browser_capture_transform_rgba(uint8_t *pixels, int width, int height)
int browser_capture_transform_required(void)