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
5 changes: 5 additions & 0 deletions .changeset/chilled-zebras-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@livekit/components-react": patch
---

allow localtrack passing on bar visualizer
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"format:write": "prettier --write \"**/src/**/*.{ts,tsx,md}\"",
"gen:docs": "turbo run gen:docs",
"gen:docs:watch": "nodemon --watch \"tooling/api-documenter/src/**/*\" --watch \"packages/react/src/**/*\" --ignore \"packages/react/src/assets/**/*\" -e js,jsx,ts,tsx -x \"pnpm gen:docs\"",
"lint": "turbo run lint",
"lint": "turbo run lint -- --quiet",
"preinstall": "npx only-allow pnpm",
"ci:publish": "turbo run build --filter=./packages/* && pnpm gen:docs && changeset publish",
"start:next": "turbo run start --filter=@livekit/component-example-next...",
Expand Down
43 changes: 37 additions & 6 deletions packages/core/etc/components-core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ConnectionQuality } from 'livekit-client';
import { ConnectionState } from 'livekit-client';
import { DataPacket_Kind } from 'livekit-client';
import { DataPublishOptions } from 'livekit-client';
import { Encryption_Type } from 'livekit-client';
import { LocalAudioTrack } from 'livekit-client';
import { LocalParticipant } from 'livekit-client';
import { LocalVideoTrack } from 'livekit-client';
Expand Down Expand Up @@ -114,7 +115,7 @@ export function createChatObserver(room: Room): Observable<[message: ChatMessage
export function createConnectionQualityObserver(participant: Participant): Observable<ConnectionQuality>;

// @public (undocumented)
export function createDataObserver(room: Room): Observable<[payload: Uint8Array<ArrayBufferLike>, participant?: RemoteParticipant | undefined, kind?: DataPacket_Kind | undefined, topic?: string | undefined]>;
export function createDataObserver(room: Room): Observable<[payload: Uint8Array<ArrayBufferLike>, participant?: RemoteParticipant | undefined, kind?: DataPacket_Kind | undefined, topic?: string | undefined, encryptionType?: Encryption_Type | undefined]>;

// @public (undocumented)
export const createDefaultGrammar: () => {
Expand Down Expand Up @@ -320,6 +321,20 @@ export function observeRoomEvents(room: Room, ...events: RoomEvent[]): Observabl
// @public (undocumented)
export function observeTrackEvents(track: TrackPublication, ...events: TrackEvent_2[]): Observable<TrackPublication>;

// @public
export enum ParticipantAgentAttributes {
// (undocumented)
AgentState = "lk.agent.state",
// (undocumented)
PublishOnBehalf = "lk.publish_on_behalf",
// (undocumented)
TranscribedTrackId = "lk.transcribed_track_id",
// (undocumented)
TranscriptionFinal = "lk.transcription_final",
// (undocumented)
TranscriptionSegmentId = "lk.segment_id"
}

// @public (undocumented)
export function participantAttributesObserver(participant: Participant): Observable<{
changed: Readonly<Record<string, string>>;
Expand Down Expand Up @@ -410,26 +425,39 @@ export const PIN_DEFAULT_STATE: PinState;
// @public (undocumented)
export type PinState = TrackReferenceOrPlaceholder[];

// Warning: (ae-forgotten-export) The symbol "ReceivedMessageWithType" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export interface ReceivedChatMessage extends ChatMessage {
// (undocumented)
attributes?: Record<string, string>;
// (undocumented)
export type ReceivedAgentTranscriptionMessage = ReceivedMessageWithType<'agentTranscript', {
message: string;
}>;

// @public (undocumented)
export type ReceivedChatMessage = ReceivedMessageWithType<'chatMessage', ChatMessage & {
from?: Participant;
}
attributes?: Record<string, string>;
}>;

Comment on lines +428 to 440
Copy link
Contributor

Choose a reason for hiding this comment

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

thought: It looks like some changes from #1207 didn;t get included in this file - sorry about that, my bad 😞

However, I am a bit suprised that the ci step didn't check this? Maybe this is something to make a ticket on to look into, since it seems like this file isn't being checked like the associated components-reactone is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we don't check the API compat on CI for the core module as that's treated as an internal package.
Don't have a strong opinion on whether or not to change that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see what you are saying, I guess that makes a certain amount of sense. Thinking about this in another way then - is there a good reason to even have the api-extractor tool run on the core package and generate this artifact if it won't be consumed externally?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, good point, both options sound fine to me!

// @public (undocumented)
export interface ReceivedDataMessage<T extends string | undefined = string> extends BaseDataMessage<T> {
// (undocumented)
from?: Participant;
}

// @public (undocumented)
export type ReceivedMessage = ReceivedUserTranscriptionMessage | ReceivedAgentTranscriptionMessage | ReceivedChatMessage;

// @public (undocumented)
export type ReceivedTranscriptionSegment = TranscriptionSegment & {
receivedAtMediaTimestamp: number;
receivedAt: number;
};

// @public (undocumented)
export type ReceivedUserTranscriptionMessage = ReceivedMessageWithType<'userTranscript', {
message: string;
}>;

// @public (undocumented)
export function recordingStatusObservable(room: Room): Observable<boolean>;

Expand Down Expand Up @@ -479,6 +507,9 @@ export function selectGridLayout(layoutDefinitions: GridLayoutDefinition[], part
// @public
export function sendMessage(localParticipant: LocalParticipant, payload: Uint8Array, options?: DataPublishOptions): Promise<void>;

// @public (undocumented)
export type SentMessage = ChatMessage;

// @public (undocumented)
export function setDifference<T>(setA: Set<T>, setB: Set<T>): Set<T>;

Expand Down
5 changes: 3 additions & 2 deletions packages/react/etc/components-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { isTrackReference } from '@livekit/components-core';
import { KrispNoiseFilterProcessor } from '@livekit/krisp-noise-filter';
import { LocalAudioTrack } from 'livekit-client';
import { LocalParticipant } from 'livekit-client';
import { LocalTrack } from 'livekit-client';
import { LocalTrackPublication } from 'livekit-client';
import { LocalUserChoices } from '@livekit/components-core';
import { LocalVideoTrack } from 'livekit-client';
Expand Down Expand Up @@ -165,6 +164,8 @@ export interface BarVisualizerProps extends React_2.HTMLProps<HTMLDivElement> {
options?: BarVisualizerOptions;
state?: AgentState;
// (undocumented)
track?: TrackReferenceOrPlaceholder | LocalAudioTrack | RemoteAudioTrack;
// @deprecated (undocumented)
trackRef?: TrackReferenceOrPlaceholder;
}

Expand Down Expand Up @@ -1147,7 +1148,7 @@ export function usePreviewDevice<T extends LocalVideoTrack | LocalAudioTrack>(en
};

// @public (undocumented)
export function usePreviewTracks(options: CreateLocalTracksOptions, onError?: (err: Error) => void): LocalTrack<Track.Kind>[] | undefined;
export function usePreviewTracks(options: CreateLocalTracksOptions, onError?: (err: Error) => void): (LocalAudioTrack | LocalVideoTrack)[] | undefined;

// @public
export function useRemoteParticipant(identifier: ParticipantIdentifier, options?: UseRemoteParticipantOptions): RemoteParticipant | undefined;
Expand Down
16 changes: 10 additions & 6 deletions packages/react/src/components/participant/BarVisualizer.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';
import { useBarAnimator } from './animators/useBarAnimator';
import { useMultibandTrackVolume, type AgentState } from '../../hooks';
import type { TrackReferenceOrPlaceholder } from '@livekit/components-core';
import { type TrackReferenceOrPlaceholder } from '@livekit/components-core';
import { useMaybeTrackRefContext } from '../../context';
import { cloneSingleChild, mergeProps } from '../../utils';
import { LocalAudioTrack, RemoteAudioTrack } from 'livekit-client';

/**
* @beta
Expand All @@ -23,7 +24,9 @@ export interface BarVisualizerProps extends React.HTMLProps<HTMLDivElement> {
state?: AgentState;
/** Number of bars that show up in the visualizer */
barCount?: number;
/** @deprecated use `track` field instead */
trackRef?: TrackReferenceOrPlaceholder;
track?: TrackReferenceOrPlaceholder | LocalAudioTrack | RemoteAudioTrack;
Comment on lines +27 to +29
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Other components currently seem to favor the trackRef prop name rather than track. I think I understand why you did it here (as a stepping stone to migrating away from TrackReference) but this means this component has two similar props which could be used at the same time, resulting in a less clear end interface.

What about instead, making BarVisualizerProps actually have two versions in a discriminated union, one that is the pre-existing version with trackRef (plus adding the deprecation), and the other getting rid of trackRef and adding track instead? The nice thing about doing it that way is the fields are mutually exclusive.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's somewhat cleaner that way, true. But the downside of that is that the props wouldn't be as easy to inspect anymore, right?

I thought deprecating one of them is pretty clear?

Copy link
Contributor

Choose a reason for hiding this comment

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

To be clear I don't really have a strong opinion on this, it just struck me reading this code that it would be nice if they were mutually exclusive since they really should never both be set and then once you've migrated over to the new track prop, it is as if the old trackRef prop no longer exists .

By "props wouldn't be as easy to inspect anymore" if you mean that the component props wouldn't point to a singular interface on a "go to definition" type operation and instead would be an expression of some sort - yes, that is a good point. I guess there are pros and cons to both approaches, so do whatever you think makes sense.

options?: BarVisualizerOptions;
/** The template component to be used in the visualizer. */
children?: React.ReactNode;
Expand Down Expand Up @@ -106,17 +109,18 @@ const getSequencerInterval = (
*/
export const BarVisualizer = /* @__PURE__ */ React.forwardRef<HTMLDivElement, BarVisualizerProps>(
function BarVisualizer(
{ state, options, barCount = 15, trackRef, children, ...props }: BarVisualizerProps,
{ state, options, barCount = 15, trackRef, track, children, ...props }: BarVisualizerProps,
ref,
) {
const elementProps = mergeProps(props, { className: 'lk-audio-bar-visualizer' });
let trackReference = useMaybeTrackRefContext();
let targetTrack: TrackReferenceOrPlaceholder | LocalAudioTrack | RemoteAudioTrack | undefined =
useMaybeTrackRefContext();

if (trackRef) {
trackReference = trackRef;
if (trackRef || track) {
targetTrack = trackRef || track;
}

const volumeBands = useMultibandTrackVolume(trackReference, {
const volumeBands = useMultibandTrackVolume(targetTrack, {
bands: barCount,
loPass: 100,
hiPass: 200,
Expand Down
9 changes: 5 additions & 4 deletions packages/react/src/prefabs/PreJoin.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type {
CreateLocalTracksOptions,
LocalAudioTrack,
LocalTrack,
LocalVideoTrack,
TrackProcessor,
} from 'livekit-client';
Expand Down Expand Up @@ -59,17 +58,19 @@ export function usePreviewTracks(
options: CreateLocalTracksOptions,
onError?: (err: Error) => void,
) {
const [tracks, setTracks] = React.useState<LocalTrack[]>();
const [tracks, setTracks] = React.useState<Array<LocalAudioTrack | LocalVideoTrack>>();

const trackLock = React.useMemo(() => new Mutex(), []);

React.useEffect(() => {
let needsCleanup = false;
let localTracks: Array<LocalTrack> = [];
let localTracks: Array<LocalAudioTrack | LocalVideoTrack> = [];
trackLock.lock().then(async (unlock) => {
try {
if (options.audio || options.video) {
localTracks = await createLocalTracks(options);
localTracks = (await createLocalTracks(options)) as Array<
LocalAudioTrack | LocalVideoTrack
>;

if (needsCleanup) {
localTracks.forEach((tr) => tr.stop());
Expand Down