## Summary
- add optional microphone constraints for echo cancellation, noise
suppression, automatic gain control, and channel count
- request configured values as non-mandatory `ideal` constraints
- expose privacy-safe microphone capabilities, requested constraints,
and applied settings in card diagnostics
- document the new configuration and add schema, microphone manager, and
diagnostics tests
## Motivation
The card currently calls `getUserMedia()` with `audio: true`. This
leaves echo cancellation, noise suppression, automatic gain control, and
channel count implicit.
Browser and device behavior differs. Explicit processing defaults can
regress microphone gain or amplify noise on some devices. This change
therefore keeps all processing constraints optional and configurable.
## Configuration
```yaml
live:
microphone:
constraints:
echo_cancellation: true
noise_suppression: true
auto_gain_control: false
channel_count: 1
```
Configured values use `ideal` constraints. A browser can ignore
unsupported values. Card diagnostics show the browser capabilities, the
requested constraints, and the reported applied settings.
## Backward compatibility
- existing configurations still use `audio: true`
- no audio-processing defaults are added
- explicit `false` values are preserved
- diagnostic output excludes device and group identifiers
## Validation
- focused microphone, schema, and diagnostics tests: 46 passed
- full test suite: 7,177 passed
- lint passed
- format check passed
- typecheck passed
- unused-code check passed
- production build passed
The optional constraints were also tested successfully with an iOS Home
Assistant Companion client and a go2rtc-based full-duplex intercom. This
is a client microphone-processing change only. It does not add backend
audio denoise.
---------
Co-authored-by: dermotduffy <dermot.duffy@gmail.com>
221 lines
5.7 KiB
YAML
221 lines
5.7 KiB
YAML
---
|
|
name: 'CI'
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- dev
|
|
pull_request:
|
|
schedule:
|
|
- cron: '17 6 * * *'
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
check-code:
|
|
name: Check / Code
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node and Yarn
|
|
uses: volta-cli/action@v5
|
|
|
|
- name: Install dependencies
|
|
run: yarn install --immutable
|
|
|
|
- name: Lint
|
|
run: yarn run lint
|
|
|
|
- name: Type-check
|
|
run: yarn run typecheck
|
|
|
|
- name: Check for dead exports
|
|
run: yarn run prune
|
|
|
|
- name: Check formatting
|
|
run: yarn run format-check
|
|
|
|
# Validates the repository's own metadata, which needs neither the card built
|
|
# nor Node installed.
|
|
check-hacs:
|
|
name: Check / HACS
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: HACS validation
|
|
uses: 'hacs/action@22.5.0'
|
|
with:
|
|
category: 'plugin'
|
|
|
|
# Always validate this repository, rather than a contributor's fork:
|
|
# HACS resolves the entry file (`advanced-camera-card.js`) from a
|
|
# release and a fork has none.
|
|
repository: ${{ github.repository }}
|
|
|
|
# Don't attempt to load into HACS (as it loads the release, not the
|
|
# build).
|
|
ignore: 'hacs'
|
|
|
|
test-unit:
|
|
name: Test / Unit
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node and Yarn
|
|
uses: volta-cli/action@v5
|
|
|
|
- name: Install dependencies
|
|
run: yarn install --immutable
|
|
|
|
- name: Test & Coverage
|
|
run: yarn run coverage
|
|
|
|
test-browser:
|
|
name: Test / Browser / ${{ matrix.name }}
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
# Use Playwright's own image to avoid having to (slowly) install browsers
|
|
# and dependencies. The tag has to name the `playwright` version in
|
|
# package.json .
|
|
container:
|
|
image: mcr.microsoft.com/playwright:v1.62.0-noble
|
|
|
|
# As the image's own user rather than root, which Firefox refuses to run
|
|
# as when the home directory belongs to somebody else.
|
|
#
|
|
# See https://playwright.dev/docs/ci#via-containers .
|
|
options: --user 1001
|
|
|
|
strategy:
|
|
# One browser failing does not invalidate the others.
|
|
fail-fast: false
|
|
matrix:
|
|
# `name` is only how the browser is written for a human: it titles the
|
|
# job, while `browser` is the name Playwright knows it by.
|
|
include:
|
|
- browser: chromium
|
|
name: Chromium
|
|
- browser: firefox
|
|
name: Firefox
|
|
- browser: webkit
|
|
name: WebKit
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node and Yarn
|
|
uses: volta-cli/action@v5
|
|
|
|
- name: Install dependencies
|
|
run: yarn install --immutable
|
|
|
|
- name: Browser test
|
|
run: yarn run test:browser
|
|
env:
|
|
VITEST_BROWSER: ${{ matrix.browser }}
|
|
|
|
- name: Upload browser test failures
|
|
if: failure()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: browser-test-failures-${{ matrix.browser }}
|
|
path: .vitest/
|
|
if-no-files-found: ignore
|
|
|
|
test-dist:
|
|
name: Test / Dist / ${{ matrix.name }}
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
# Use Playwright's own image to avoid having to (slowly) install browsers
|
|
# and dependencies. The tag has to name the `playwright` version in
|
|
# package.json .
|
|
container:
|
|
image: mcr.microsoft.com/playwright:v1.62.0-noble
|
|
|
|
# As the image's own user rather than root, which Firefox refuses to run
|
|
# as when the home directory belongs to somebody else.
|
|
#
|
|
# See https://playwright.dev/docs/ci#via-containers .
|
|
options: --user 1001
|
|
|
|
strategy:
|
|
# One browser failing does not invalidate the others.
|
|
fail-fast: false
|
|
matrix:
|
|
# `name` is only how the browser is written for a human: it titles the
|
|
# job, while `browser` is the name Playwright knows it by.
|
|
include:
|
|
- browser: chromium
|
|
name: Chromium
|
|
- browser: firefox
|
|
name: Firefox
|
|
- browser: webkit
|
|
name: WebKit
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node and Yarn
|
|
uses: volta-cli/action@v5
|
|
|
|
- name: Install dependencies
|
|
run: yarn install --immutable
|
|
|
|
# These tests read a build rather than making one.
|
|
- name: Build
|
|
run: yarn run build
|
|
|
|
- name: Test the built card
|
|
run: yarn run test:dist
|
|
env:
|
|
VITEST_BROWSER: ${{ matrix.browser }}
|
|
|
|
- name: Upload failures
|
|
if: failure()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: dist-test-failures-${{ matrix.browser }}
|
|
path: .vitest/
|
|
if-no-files-found: ignore
|
|
|
|
build:
|
|
name: Build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
|
|
- name: Setup Node and Yarn
|
|
uses: volta-cli/action@v5
|
|
|
|
- name: Install dependencies
|
|
run: yarn install --immutable
|
|
|
|
- name: Build
|
|
run: yarn run build
|
|
|
|
- name: Upload javascript
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: advanced-camera-card
|
|
path: dist/*.js
|
|
|
|
# Uploaded unarchived so the self-contained treemap can be viewed directly
|
|
# in the browser rather than downloaded and unzipped. The artifact is
|
|
# named after the file, as `name` is ignored when `archive` is false.
|
|
- name: Upload bundle visualization
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
path: visualizations/treemap.html
|
|
archive: false
|