Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ jobs:

- name: Run unit tests (Bun)
if: matrix.runtime.kind == 'bun'
run: bun x vitest --no-watch
run: bun x vitest --no-watch --no-file-parallelism --sequence.concurrent=false

- name: Run unit tests (Deno)
if: matrix.runtime.kind == 'deno'
run: deno run -A --node-modules-dir=auto npm:vitest --no-watch
run: deno run -A --node-modules-dir=auto npm:vitest --no-watch --no-file-parallelism --sequence.concurrent=false
30 changes: 22 additions & 8 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,33 @@
{
"name": "linux-gcc-x64",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}",
"${workspaceFolder}/src/cpp",
"${workspaceFolder}/node_modules/node-addon-api",
"/usr/include/node",
"/usr/include/gstreamer-1.0",
"/usr/include/orc-0.4",
"/usr/include/x86_64-linux-gnu",
"/usr/include/glib-2.0",
"/usr/lib/x86_64-linux-gnu/glib-2.0/include",
"${workspaceFolder}/node_modules/node-addon-api"
"/usr/lib/x86_64-linux-gnu/glib-2.0/include"
],
"compilerPath": "/usr/lib/ccache/gcc",
"cStandard": "${default}",
"cppStandard": "${default}",
"browse": {
"path": [
"${workspaceFolder}/src/cpp",
"${workspaceFolder}/node_modules/node-addon-api",
"/usr/include/node",
"/usr/include/gstreamer-1.0",
"/usr/include/orc-0.4",
"/usr/include/x86_64-linux-gnu",
"/usr/include/glib-2.0",
"/usr/lib/x86_64-linux-gnu/glib-2.0/include"
]
},
"compilerPath": "/usr/bin/g++",
"cStandard": "c17",
"cppStandard": "c++20",
"intelliSenseMode": "linux-gcc-x64",
"compilerArgs": [""],
"defines": ["NAPI_CPP_EXCEPTIONS", "BUILDING_NODE_EXTENSION"]
"defines": ["NAPI_VERSION=9", "NAPI_DISABLE_CPP_EXCEPTIONS", "BUILDING_NODE_EXTENSION"]
}
],
"version": 4
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This project represents a complete modernization of the old [node-gstreamer-supe
- **Rolldown bundling**: Generates both CommonJS and ESM modules for maximum compatibility
- **TypeScript-first**: Complete TypeScript support with full type definitions
- **GYP build system**: Robust C++ compilation with proper dependency management
- **Modern testing**: Uses Vitest for fast, concurrent testing instead of legacy test frameworks
- **Modern testing**: Uses Vitest for fast testing instead of legacy test frameworks

### Enhanced Developer Experience

Expand Down Expand Up @@ -1046,7 +1046,7 @@ if (sampleResult?.type === "sample") {

### Testing & Quality

- **Vitest**: Modern, fast test runner with concurrent execution
- **Vitest**: Modern, fast test runner
- **Oxlint**: Fast Rust-based linter with TypeScript support
- **Prettier**: Code formatting
- **Coverage**: Built-in test coverage reporting
Expand Down Expand Up @@ -1093,7 +1093,6 @@ gst-kit/

## Performance Considerations

- **Concurrent Testing**: All tests run concurrently for faster execution
- **Efficient Memory Management**: Proper buffer lifecycle management
- **Async Operations**: Non-blocking operations for better performance
- **Type Safety**: Compile-time error detection reduces runtime overhead
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
"build:native": "node-gyp rebuild",
"build:ts": "rolldown -c rolldown.config.mjs",
"build": "npm run clean && npm run build:native && npm run build:ts",
"test:unit": "vitest --no-watch",
"test:unit:bun": "bun x vitest --no-watch",
"test:unit:deno": "deno run -A --node-modules-dir=auto npm:vitest --no-watch",
"test:unit": "vitest --no-watch --no-file-parallelism --sequence.concurrent=false",
"test:unit:bun": "bun x vitest --no-watch --no-file-parallelism --sequence.concurrent=false",
"test:unit:deno": "deno run -A --node-modules-dir=auto npm:vitest --no-watch --no-file-parallelism --sequence.concurrent=false",
"test": "npm run test:unit",
"prepublishOnly": "npm run build:ts",
"postinstall": "node scripts/ensure-native-addon.mjs",
Expand Down
3 changes: 1 addition & 2 deletions src/cpp/pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,7 @@ Napi::Value Pipeline::end_of_stream(const Napi::CallbackInfo &info) {
}

// Send EOS event to the pipeline
gboolean result =
gst_element_send_event(GST_ELEMENT(pipeline.get()), gst_event_new_eos());
gboolean result = gst_element_send_event(GST_ELEMENT(pipeline.get()), gst_event_new_eos());

return Napi::Boolean::New(env, result);
}
Expand Down
12 changes: 6 additions & 6 deletions src/ts/appsink.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { Pipeline, type GStreamerSample } from ".";
import { arePluginsAvailable } from "./test-utils";

describe.concurrent("AppSink", () => {
describe("AppSink", () => {
it("should pull frames", async () => {
const pipeline = new Pipeline("videotestsrc ! videoconvert ! appsink name=sink");
const sink = pipeline.getElementByName("sink");
Expand All @@ -13,7 +13,7 @@ describe.concurrent("AppSink", () => {

const result = await sink.getSample();

pipeline.stop();
await pipeline.stop();

expect(result).not.toBeNull();
expect(result?.buffer).toBeDefined();
Expand All @@ -34,7 +34,7 @@ describe.concurrent("AppSink", () => {

const result = await sink.getSample(10);

pipeline.stop();
await pipeline.stop();

expect(result).toBeNull();
}
Expand All @@ -48,7 +48,7 @@ describe.concurrent("AppSink", () => {

const result = await sink.getSample();

pipeline.stop();
await pipeline.stop();

expect(result).toBeNull();
});
Expand All @@ -74,7 +74,7 @@ describe.concurrent("AppSink", () => {
currFrames++;
}

pipeline.stop();
await pipeline.stop();

expect(currFrames).toBe(frames);
});
Expand Down Expand Up @@ -102,7 +102,7 @@ describe.concurrent("AppSink", () => {
});

unsubscribe();
pipeline.stop();
await pipeline.stop();

expect(samples).toHaveLength(frames);
expect(samples[0].buffer).toBeDefined();
Expand Down
2 changes: 1 addition & 1 deletion src/ts/appsrc-eos.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { Pipeline, type GstMessage } from ".";

describe.concurrent("AppSrc End-of-Stream", () => {
describe("AppSrc End-of-Stream", () => {
it("should send EOS signal through endOfStream method", async () => {
const pipeline = new Pipeline("appsrc name=source ! fakesink");
const source = pipeline.getElementByName("source");
Expand Down
2 changes: 1 addition & 1 deletion src/ts/appsrc.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { Pipeline } from ".";

describe.concurrent("AppSrc", () => {
describe("AppSrc", () => {
it("should push buffer to app source", () => {
const pipeline = new Pipeline("appsrc name=source ! fakesink");
const source = pipeline.getElementByName("source");
Expand Down
16 changes: 8 additions & 8 deletions src/ts/bus-pop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { describe, expect, it } from "vitest";
import { Pipeline, type GstMessage } from ".";
import { isWindows } from "./test-utils";

describe.concurrent("Pipeline busPop Method", () => {
describe("Pipeline busPop Method", () => {
it("should return null when no message available with timeout", async () => {
const pipeline = new Pipeline("videotestsrc ! fakesink");

// Try to pop a message with a very short timeout (10ms)
const message = await pipeline.busPop(10);

pipeline.stop();
await pipeline.stop();

// Should return null when timeout expires with no messages
expect(message).toBeNull();
Expand All @@ -24,7 +24,7 @@ describe.concurrent("Pipeline busPop Method", () => {
// Pop a message with reasonable timeout
const message = await pipeline.busPop(1000);

pipeline.stop();
await pipeline.stop();

expect(message).not.toBeNull();
expect(typeof message?.type).toBe("string");
Expand Down Expand Up @@ -52,7 +52,7 @@ describe.concurrent("Pipeline busPop Method", () => {
}
}

pipeline.stop();
await pipeline.stop();

// Should have found at least one message during pipeline startup
expect(foundMessage).toBe(true);
Expand All @@ -66,7 +66,7 @@ describe.concurrent("Pipeline busPop Method", () => {

const message = await pipeline.busPop(1000);

pipeline.stop();
await pipeline.stop();

if (message && message.type === "error") {
expect(message.errorMessage).toBeDefined();
Expand All @@ -84,7 +84,7 @@ describe.concurrent("Pipeline busPop Method", () => {
const endTime = Date.now();
const elapsed = endTime - startTime;

pipeline.stop();
await pipeline.stop();

// Should timeout within a reasonable range (timing varies by platform)
expect(elapsed).toBeGreaterThan(80);
Expand All @@ -101,7 +101,7 @@ describe.concurrent("Pipeline busPop Method", () => {
// Use -1 for infinite timeout, but pipeline should generate EOS quickly
const message = await pipeline.busPop(-1);

pipeline.stop();
await pipeline.stop();

// Should get a message (likely EOS or state-changed)
expect(message).not.toBeNull();
Expand All @@ -127,7 +127,7 @@ describe.concurrent("Pipeline busPop Method", () => {
}
}

pipeline.stop();
await pipeline.stop();

if (messageWithStructure) {
expect(messageWithStructure.structureName).toBeDefined();
Expand Down
6 changes: 3 additions & 3 deletions src/ts/codec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { Pipeline, type GStreamerSample, GstBufferFlags, type BufferData } from ".";
import { arePluginsAvailable } from "./test-utils";

describe.concurrent("codec", () => {
describe("codec", () => {
it.skipIf(!arePluginsAvailable(["x264enc", "rtph264pay", "rtph264depay", "h264parse"]))(
"should be able to distinguish between delta and key frames",
async () => {
Expand All @@ -26,7 +26,7 @@ describe.concurrent("codec", () => {
currFrames++;
}

pipeline.stop();
await pipeline.stop();

const keyFrame = samples.find(e =>
e.flags ? !(e.flags & GstBufferFlags.GST_BUFFER_FLAG_DELTA_UNIT) : false
Expand Down Expand Up @@ -60,7 +60,7 @@ describe.concurrent("codec", () => {
});

unsubscribe();
pipeline.stop();
await pipeline.stop();

expect(bufferData).toBeDefined();
expect(bufferData.buffer).toBeDefined();
Expand Down
6 changes: 1 addition & 5 deletions src/ts/element-props.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { describe, it, expect } from "vitest";
import { Pipeline } from "./";

describe.concurrent("Element Properties", () => {
describe("Element Properties", () => {
it("should get prop value", async () => {
const caps = "video/x-raw,format=(string)GRAY8";
const pipeline = new Pipeline(`videotestsrc ! capsfilter name=target caps=${caps} ! fakesink`);

await pipeline.play();

const element = pipeline.getElementByName("target");

if (!element) throw new Error("Element not found");
Expand All @@ -17,8 +15,6 @@ describe.concurrent("Element Properties", () => {
expect(prop).not.toBeNull();
expect(prop?.type).toBe("primitive");
caps.split(",").forEach(cap => expect(prop?.value).toContain(cap));

await pipeline.stop();
});

it("should set string property", () => {
Expand Down
10 changes: 5 additions & 5 deletions src/ts/fakesink.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { Pipeline, type GStreamerSample } from ".";

describe.concurrent("FakeSink", () => {
describe("FakeSink", () => {
it("should capture last sample when enabled", async () => {
const pipeline = new Pipeline("videotestsrc ! fakesink enable-last-sample=true name=sink");
const fakesink = pipeline.getElementByName("sink");
Expand All @@ -13,7 +13,7 @@ describe.concurrent("FakeSink", () => {
// Get the last sample
const sampleResult = fakesink.getElementProperty("last-sample");

pipeline.stop();
await pipeline.stop();

expect(sampleResult).not.toBeNull();
expect(sampleResult?.type).toBe("sample");
Expand Down Expand Up @@ -45,7 +45,7 @@ describe.concurrent("FakeSink", () => {
// Try to get the last sample (should be null since it's disabled)
const sampleResult = fakesink.getElementProperty("last-sample");

pipeline.stop();
await pipeline.stop();

expect(sampleResult).toBeNull();
});
Expand Down Expand Up @@ -82,7 +82,7 @@ describe.concurrent("FakeSink", () => {

const sampleResult = fakesink.getElementProperty("last-sample");

pipeline.stop();
await pipeline.stop();

expect(sampleResult).not.toBeNull();
expect(sampleResult?.type).toBe("sample");
Expand All @@ -108,7 +108,7 @@ describe.concurrent("FakeSink", () => {

const sampleResult = fakesink.getElementProperty("last-sample");

pipeline.stop();
await pipeline.stop();

expect(sampleResult).not.toBeNull();
expect(sampleResult?.type).toBe("sample");
Expand Down
Loading
Loading