Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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/add-audio-in-out-widgets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@viamrobotics/test-widgets': minor
---

Add `AudioInputWidget` and `AudioOutputWidget` components for audio in/out resources
8 changes: 8 additions & 0 deletions src/lib/builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { ResourceName } from '@viamrobotics/sdk'

import {
ArmWidget,
AudioInputWidget,
AudioOutputWidget,
BaseWidget,
BoardWidget,
ButtonWidget,
Expand Down Expand Up @@ -35,6 +37,12 @@ const resourceMap =
// list created via `cat rdkbuiltins/viam-server-stable.json | rg "api" | sort | uniq`
{
'rdk:component:arm': [clientMap['rdk:component:arm'], ArmWidget, true],
'rdk:component:audio_input': [clientMap['rdk:component:audio_input'], AudioInputWidget, true],
'rdk:component:audio_output': [
clientMap['rdk:component:audio_output'],
AudioOutputWidget,
true,
],
'rdk:component:base': [clientMap['rdk:component:base'], BaseWidget, true],
'rdk:component:board': [clientMap['rdk:component:board'], BoardWidget, true],
'rdk:component:button': [clientMap['rdk:component:button'], ButtonWidget, true],
Expand Down
4 changes: 4 additions & 0 deletions src/lib/client-map.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
ArmClient,
AudioInClient,
AudioOutClient,
BaseClient,
BoardClient,
ButtonClient,
Expand Down Expand Up @@ -33,6 +35,8 @@ import { getResourceAPI } from './resource.ts'

export const clientMap = {
'rdk:component:arm': ArmClient,
'rdk:component:audio_input': AudioInClient,
'rdk:component:audio_output': AudioOutClient,
'rdk:component:base': BaseClient,
'rdk:component:board': BoardClient,
'rdk:component:button': ButtonClient,
Expand Down
4 changes: 4 additions & 0 deletions src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export { default as ArmMoveToJointPositionsWidget } from './widgets/arm/move-to-
export { default as ArmMoveToPositionWidget } from './widgets/arm/move-to-position-widget.svelte'
export { default as ArmQuickMoveWidget } from './widgets/arm/quick-move-widget.svelte'

export { default as AudioInputWidget } from './widgets/audio-input/audio-input.svelte'

export { default as AudioOutputWidget } from './widgets/audio-output/audio-output.svelte'

export { default as BaseWidget } from './widgets/base/base.svelte'
export { default as BaseMoveStraightWidget } from './widgets/base/move-straight-widget.svelte'
export { default as BaseQuickMoveWidget } from './widgets/base/quick-move-widget.svelte'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { ComponentProps } from 'svelte'

import { render, screen } from '@testing-library/svelte'
import { describe, expect, it } from 'vitest'

import Subject from '../properties.svelte'

const renderSubject = (props: Partial<ComponentProps<typeof Subject>> = {}) =>
render(Subject, {
supportedCodecs: [],
sampleRateHz: 0,
numChannels: 0,
...props,
})

describe('AudioInput Properties', () => {
it('displays supported codecs', () => {
renderSubject({ supportedCodecs: ['mp3', 'pcm16'] })
expect(screen.getByText('mp3, pcm16')).toBeInTheDocument()
})

it('displays None when no codecs are supported', () => {
renderSubject({ supportedCodecs: [] })
expect(screen.getByText('None')).toBeInTheDocument()
})

it('displays sample rate', () => {
renderSubject({ sampleRateHz: 48000 })
expect(screen.getByText('48000 Hz')).toBeInTheDocument()
})

it('displays number of channels', () => {
renderSubject({ numChannels: 2 })
expect(screen.getByText('2')).toBeInTheDocument()
})
Comment thread
DTCurrie marked this conversation as resolved.
})
65 changes: 65 additions & 0 deletions src/lib/components/widgets/audio-input/audio-input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<script lang="ts">
import { AudioInClient } from '@viamrobotics/sdk'
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'

import ApiSection from '$lib/components/api-section.svelte'
import ConnectionStatus from '$lib/components/connection-status.svelte'
import Query from '$lib/components/query.svelte'
import RefetchController from '$lib/components/refetch-controller.svelte'
import { createRefetchIntervalStore } from '$lib/components/refetch-interval-store.svelte'

import Properties from './properties.svelte'

interface Props {
partID: string
resourceName: string
}

const { partID, resourceName }: Props = $props()

const refetchInterval = createRefetchIntervalStore(
() => partID,
() => resourceName,
'audio-input'
)

const client = createResourceClient(
AudioInClient,
() => partID,
() => resourceName
)

const propertiesQuery = createResourceQuery(client, 'getProperties', () => ({
Comment thread
DTCurrie marked this conversation as resolved.
refetchInterval: refetchInterval.current,
}))
</script>

<ConnectionStatus {partID}>
{#snippet connected()}
<div class="p-4 pb-3">
<RefetchController
{refetchInterval}
queries={[propertiesQuery]}
/>
</div>

<ApiSection
title="GetProperties"
description="Audio input properties"
class="relative"
>
<Query
query={propertiesQuery}
contentCx="h-6"
>
{#if propertiesQuery.data !== undefined}
<Properties
supportedCodecs={propertiesQuery.data.supportedCodecs}
sampleRateHz={propertiesQuery.data.sampleRateHz}
numChannels={propertiesQuery.data.numChannels}
/>
{/if}
</Query>
</ApiSection>
{/snippet}
</ConnectionStatus>
26 changes: 26 additions & 0 deletions src/lib/components/widgets/audio-input/properties.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts">
interface Props {
supportedCodecs: string[]
sampleRateHz: number
numChannels: number
}

const { supportedCodecs, sampleRateHz, numChannels }: Props = $props()
</script>

<dl class="font-roboto-mono flex flex-col gap-y-2 text-sm">
<div class="flex flex-row">
<dt class="text-default w-50 min-w-50 pr-2 font-medium">Supported Codecs</dt>
<dd class="text-subtle-1">
{supportedCodecs.length > 0 ? supportedCodecs.join(', ') : 'None'}
</dd>
</div>
<div class="flex flex-row">
<dt class="text-default w-50 min-w-50 pr-2 font-medium">Sample Rate</dt>
<dd class="text-subtle-1">{sampleRateHz} Hz</dd>
</div>
<div class="flex flex-row">
<dt class="text-default w-50 min-w-50 pr-2 font-medium">Channels</dt>
<dd class="text-subtle-1">{numChannels}</dd>
</div>
</dl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { ComponentProps } from 'svelte'

import { render, screen } from '@testing-library/svelte'
import { describe, expect, it } from 'vitest'

import Subject from '../properties.svelte'

const renderSubject = (props: Partial<ComponentProps<typeof Subject>> = {}) =>
render(Subject, {
supportedCodecs: [],
sampleRateHz: 0,
numChannels: 0,
...props,
})

describe('AudioOutput Properties', () => {
it('displays supported codecs', () => {
renderSubject({ supportedCodecs: ['mp3', 'pcm16'] })
expect(screen.getByText('mp3, pcm16')).toBeInTheDocument()
})

it('displays None when no codecs are supported', () => {
renderSubject({ supportedCodecs: [] })
expect(screen.getByText('None')).toBeInTheDocument()
})

it('displays sample rate', () => {
renderSubject({ sampleRateHz: 44100 })
expect(screen.getByText('44100 Hz')).toBeInTheDocument()
})

it('displays number of channels', () => {
renderSubject({ numChannels: 1 })
expect(screen.getByText('1')).toBeInTheDocument()
})
})
65 changes: 65 additions & 0 deletions src/lib/components/widgets/audio-output/audio-output.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<script lang="ts">
import { AudioOutClient } from '@viamrobotics/sdk'
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'

import ApiSection from '$lib/components/api-section.svelte'
import ConnectionStatus from '$lib/components/connection-status.svelte'
import Query from '$lib/components/query.svelte'
import RefetchController from '$lib/components/refetch-controller.svelte'
import { createRefetchIntervalStore } from '$lib/components/refetch-interval-store.svelte'

import Properties from './properties.svelte'

interface Props {
partID: string
resourceName: string
}

const { partID, resourceName }: Props = $props()

const refetchInterval = createRefetchIntervalStore(
() => partID,
() => resourceName,
'audio-output'
)

const client = createResourceClient(
AudioOutClient,
() => partID,
() => resourceName
)

const propertiesQuery = createResourceQuery(client, 'getProperties', () => ({
Comment thread
DTCurrie marked this conversation as resolved.
refetchInterval: refetchInterval.current,
}))
</script>

<ConnectionStatus {partID}>
{#snippet connected()}
<div class="p-4 pb-3">
<RefetchController
{refetchInterval}
queries={[propertiesQuery]}
/>
</div>

<ApiSection
title="GetProperties"
description="Audio output properties"
class="relative"
>
<Query
query={propertiesQuery}
contentCx="h-6"
>
{#if propertiesQuery.data !== undefined}
<Properties
supportedCodecs={propertiesQuery.data.supportedCodecs}
sampleRateHz={propertiesQuery.data.sampleRateHz}
numChannels={propertiesQuery.data.numChannels}
/>
{/if}
</Query>
</ApiSection>
{/snippet}
</ConnectionStatus>
26 changes: 26 additions & 0 deletions src/lib/components/widgets/audio-output/properties.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts">
Comment thread
DTCurrie marked this conversation as resolved.
interface Props {
supportedCodecs: string[]
sampleRateHz: number
numChannels: number
}

const { supportedCodecs, sampleRateHz, numChannels }: Props = $props()
</script>

<dl class="font-roboto-mono flex flex-col gap-y-2 text-sm">
<div class="flex flex-row">
<dt class="text-default w-50 min-w-50 pr-2 font-medium">Supported Codecs</dt>
<dd class="text-subtle-1">
{supportedCodecs.length > 0 ? supportedCodecs.join(', ') : 'None'}
</dd>
</div>
<div class="flex flex-row">
<dt class="text-default w-50 min-w-50 pr-2 font-medium">Sample Rate</dt>
<dd class="text-subtle-1">{sampleRateHz} Hz</dd>
</div>
<div class="flex flex-row">
<dt class="text-default w-50 min-w-50 pr-2 font-medium">Channels</dt>
<dd class="text-subtle-1">{numChannels}</dd>
</div>
</dl>
Loading