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
78 changes: 0 additions & 78 deletions .github/workflows/claude-code-review.yml

This file was deleted.

49 changes: 0 additions & 49 deletions .github/workflows/claude-dispatch.yml

This file was deleted.

6 changes: 3 additions & 3 deletions js/hang-demo/src/publish.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
Feel free to hard-code it if you have public access configured, like `url="https://relay.moq.dev/anon"`
NOTE: `http` performs an insecure certificate check. You must use `https` in production.
-->
<hang-publish url="%VITE_RELAY_URL%" name="me" audio video controls captions>
<hang-publish url="%VITE_RELAY_URL%" name="me" controls captions>
<!-- It's optional to provide a video element to preview the outgoing media. -->
<video style="max-width: 100%; height: auto; border-radius: 4px; margin: 0 auto;" muted autoplay></video>
</hang-publish>
Comment on lines +25 to 28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Example code below references #publish but the element lacks an id.

Add id="publish" so document.getElementById("publish") works.

-  <hang-publish url="%VITE_RELAY_URL%" name="me" controls captions>
+  <hang-publish id="publish" url="%VITE_RELAY_URL%" name="me" controls captions>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<hang-publish url="%VITE_RELAY_URL%" name="me" controls captions>
<!-- It's optional to provide a video element to preview the outgoing media. -->
<video style="max-width: 100%; height: auto; border-radius: 4px; margin: 0 auto;" muted autoplay></video>
</hang-publish>
<hang-publish id="publish" url="%VITE_RELAY_URL%" name="me" controls captions>
<!-- It's optional to provide a video element to preview the outgoing media. -->
<video style="max-width: 100%; height: auto; border-radius: 4px; margin: 0 auto;" muted autoplay></video>
</hang-publish>
🤖 Prompt for AI Agents
In js/hang-demo/src/publish.html around lines 25 to 28, the <hang-publish>
element is referenced by document.getElementById("publish") but lacks an id
attribute; add id="publish" to the <hang-publish> tag so the DOM lookup
succeeds, ensuring any existing code that calls
document.getElementById("publish") will correctly find the element.

Expand Down Expand Up @@ -69,10 +69,10 @@ <h3>Tips:</h3>
<p>
You can create a broadcaster via the provided <code class="language-html">&lt;hang-publish&gt;</code> <a
href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components">Web Component</a>.
Either modify HTML attributes like <code class="language-html">&lt;hang-publish device="camera" /&gt;</code>
Either modify HTML attributes like <code class="language-html">&lt;hang-publish source="camera" audio /&gt;</code>
or access the element's Javascript API:
<pre><code class="language-typescript">const publish = document.getElementById("publish");
publish.lib.device = "camera";</code></pre>
publish.broadcast.audio.enabled.set(true);</code></pre>

And of course you can use the Javascript API directly instead of the Web Component.
It's a bit more complicated and subject to change, but it gives you more control.
Expand Down
4 changes: 2 additions & 2 deletions js/hang/src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Effect, Signal } from "@kixelated/signals";

export type ConnectionProps = {
// The URL of the relay server.
url?: URL;
url?: URL | Signal<URL | undefined>;

// Reload the connection when it disconnects.
// default: true
Expand Down Expand Up @@ -36,7 +36,7 @@ export class Connection {
#tick = new Signal(0);

constructor(props?: ConnectionProps) {
this.url = new Signal(props?.url);
this.url = Signal.from(props?.url);
this.reload = props?.reload ?? true;
this.delay = props?.delay ?? 1000;
this.maxDelay = props?.maxDelay ?? 30000;
Expand Down
2 changes: 1 addition & 1 deletion js/hang/src/meet/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export default class HangMeet extends HTMLElement {
autoplay: true,
});

const cleanup = broadcast.video.media.subscribe((media) => {
const cleanup = broadcast.video.source.subscribe((media) => {
video.srcObject = media ? new MediaStream([media]) : null;
});

Expand Down
4 changes: 2 additions & 2 deletions js/hang/src/meet/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { type Connection, Moq, type Publish, Watch } from "..";
export type Broadcast = Watch.Broadcast | Publish.Broadcast;

export type RoomProps = {
name?: Path.Valid;
name?: Path.Valid | Signal<Path.Valid>;
};

export class Room {
Expand Down Expand Up @@ -36,7 +36,7 @@ export class Room {

constructor(connection: Connection, props?: RoomProps) {
this.connection = connection;
this.name = new Signal(props?.name ?? Moq.Path.empty());
this.name = Signal.from(props?.name ?? Moq.Path.empty());

this.#signals.effect(this.#init.bind(this));
}
Expand Down
4 changes: 2 additions & 2 deletions js/hang/src/preview/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Effect, Signal } from "@kixelated/signals";
import * as Preview from "./info";

export type MemberProps = {
enabled?: boolean;
enabled?: boolean | Signal<boolean>;
};

export class Member {
Expand All @@ -16,7 +16,7 @@ export class Member {

constructor(broadcast: Moq.BroadcastConsumer, props?: MemberProps) {
this.broadcast = broadcast;
this.enabled = new Signal(props?.enabled ?? false);
this.enabled = Signal.from(props?.enabled ?? false);
this.info = new Signal<Preview.Info | undefined>(undefined);

this.signals.effect((effect) => {
Expand Down
8 changes: 4 additions & 4 deletions js/hang/src/preview/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type { Connection } from "../connection";
import { Member } from "./member";

export type RoomProps = {
name?: Path.Valid;
enabled?: boolean;
name?: Path.Valid | Signal<Path.Valid | undefined>;
enabled?: boolean | Signal<boolean>;
};

export class Room {
Expand All @@ -21,8 +21,8 @@ export class Room {

constructor(connection: Connection, props?: RoomProps) {
this.connection = connection;
this.name = new Signal(props?.name);
this.enabled = new Signal(props?.enabled ?? false);
this.name = Signal.from(props?.name);
this.enabled = Signal.from(props?.enabled ?? false);

this.#signals.effect(this.#init.bind(this));
}
Expand Down
15 changes: 9 additions & 6 deletions js/hang/src/publish/audio/captions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Request, Result } from "./captions-worker";
import CaptureWorklet from "./capture-worklet?worker&url";

export type CaptionsProps = {
enabled?: boolean;
enabled?: boolean | Signal<boolean>;
transcribe?: boolean;

// Captions are cleared after this many milliseconds. (10s default)
Expand All @@ -26,21 +26,23 @@ export class Captions {
signals = new Effect();

#ttl: DOMHighResTimeStamp;

#track = new Moq.TrackProducer("captions.txt", 1);

constructor(audio: Audio, props?: CaptionsProps) {
this.audio = audio;
this.#ttl = props?.ttl ?? 10000;
this.enabled = new Signal(props?.enabled ?? false);
this.enabled = Signal.from(props?.enabled ?? false);

this.signals.effect(this.#run.bind(this));
}

#run(effect: Effect): void {
if (!effect.get(this.enabled)) return;
const enabled = effect.get(this.enabled);
if (!enabled) return;

const media = effect.get(this.audio.media);
if (!media) return;
const source = effect.get(this.audio.source);
if (!source) return;

this.audio.broadcast.insertTrack(this.#track.consume());
effect.cleanup(() => this.audio.broadcast.removeTrack(this.#track.name));
Expand Down Expand Up @@ -76,6 +78,7 @@ export class Captions {
};

effect.cleanup(() => {
worker.onmessage = null;
this.text.set(undefined);
});

Expand All @@ -87,7 +90,7 @@ export class Captions {

// Create the source node.
const root = new MediaStreamAudioSourceNode(ctx, {
mediaStream: new MediaStream([media]),
mediaStream: new MediaStream([source]),
});
effect.cleanup(() => root.disconnect());

Expand Down
Loading
Loading