fix: Microphone should still work after a view change (#1835)

- Closes #1810
This commit is contained in:
Dermot Duffy
2025-01-18 14:54:40 -08:00
committed by GitHub
parent 57a687d659
commit 3003f82170
14 changed files with 186 additions and 212 deletions
+7 -7
View File
@@ -15,7 +15,7 @@ import {
ConditionsManagerEpoch,
getOverriddenConfig,
} from '../../card-controller/conditions-manager.js';
import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js';
import { MicrophoneState } from '../../card-controller/types.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { MediaActionsController } from '../../components-lib/media-actions-controller.js';
import { ZoomSettingsObserved } from '../../components-lib/zoom/types.js';
@@ -88,7 +88,7 @@ export class FrigateCardLiveCarousel extends LitElement {
public cameraManager?: CameraManager;
@property({ attribute: false })
public microphoneManager?: ReadonlyMicrophoneManager;
public microphoneState?: MicrophoneState;
@property({ attribute: false })
public viewFilterCameraID?: string;
@@ -139,7 +139,7 @@ export class FrigateCardLiveCarousel extends LitElement {
protected willUpdate(changedProps: PropertyValues): void {
if (
changedProps.has('microphoneManager') ||
changedProps.has('microphoneState') ||
changedProps.has('overriddenLiveConfig')
) {
this._mediaActionsController.setOptions({
@@ -158,7 +158,7 @@ export class FrigateCardLiveCarousel extends LitElement {
}),
...((this.overriddenLiveConfig?.auto_unmute ||
this.overriddenLiveConfig?.auto_mute) && {
microphoneManager: this.microphoneManager,
microphoneState: this.microphoneState,
microphoneMuteSeconds:
this.overriddenLiveConfig.microphone.mute_after_microphone_mute_seconds,
}),
@@ -302,8 +302,8 @@ export class FrigateCardLiveCarousel extends LitElement {
<div class="embla__slide">
<frigate-card-live-provider
?load=${!liveConfig.lazy_load}
.microphoneStream=${view?.camera === cameraID
? this.microphoneManager?.getStream()
.microphoneState=${view?.camera === cameraID
? this.microphoneState
: undefined}
.cameraConfig=${cameraConfig}
.cameraEndpoints=${guard(
@@ -429,7 +429,7 @@ export class FrigateCardLiveCarousel extends LitElement {
.loop=${hasMultipleCameras}
.dragEnabled=${hasMultipleCameras && this.overriddenLiveConfig?.draggable}
.plugins=${guard(
[this.cameraManager, this.overriddenLiveConfig, this.microphoneManager],
[this.cameraManager, this.overriddenLiveConfig],
this._getPlugins.bind(this),
)}
.selected=${this._getSelectedCameraIndex()}
+3 -3
View File
@@ -10,7 +10,7 @@ import { customElement, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { CameraManager } from '../../camera-manager/manager.js';
import { ConditionsManagerEpoch } from '../../card-controller/conditions-manager.js';
import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js';
import { MicrophoneState } from '../../card-controller/types.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { MediaGridSelected } from '../../components-lib/media-grid-controller.js';
import { CardWideConfig, LiveConfig, Overrides } from '../../config/types.js';
@@ -46,7 +46,7 @@ export class FrigateCardLiveGrid extends LitElement {
public cameraManager?: CameraManager;
@property({ attribute: false })
public microphoneManager?: ReadonlyMicrophoneManager;
public microphoneState?: MicrophoneState;
@property({ attribute: false })
public triggeredCameraIDs?: Set<string>;
@@ -67,7 +67,7 @@ export class FrigateCardLiveGrid extends LitElement {
.overrides=${this.overrides}
.cardWideConfig=${this.cardWideConfig}
.cameraManager=${this.cameraManager}
.microphoneManager=${this.microphoneManager}
.microphoneState=${this.microphoneState}
?triggered=${triggeredCameraID &&
!!this.triggeredCameraIDs?.has(triggeredCameraID)}
>
+3 -3
View File
@@ -2,7 +2,7 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit
import { customElement, property } from 'lit/decorators.js';
import { CameraManager } from '../../camera-manager/manager.js';
import { ConditionsManagerEpoch } from '../../card-controller/conditions-manager.js';
import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js';
import { MicrophoneState } from '../../card-controller/types.js';
import { ViewManagerEpoch } from '../../card-controller/view/types.js';
import { LiveController } from '../../components-lib/live/live-controller.js';
import { CardWideConfig, LiveConfig, Overrides } from '../../config/types.js';
@@ -38,7 +38,7 @@ export class FrigateCardLive extends LitElement {
public cardWideConfig?: CardWideConfig;
@property({ attribute: false })
public microphoneManager?: ReadonlyMicrophoneManager;
public microphoneState?: MicrophoneState;
@property({ attribute: false })
public triggeredCameraIDs?: Set<string>;
@@ -67,7 +67,7 @@ export class FrigateCardLive extends LitElement {
.overrides=${this.overrides}
.cardWideConfig=${this.cardWideConfig}
.cameraManager=${this.cameraManager}
.microphoneManager=${this.microphoneManager}
.microphoneState=${this.microphoneState}
.triggeredCameraIDs=${this.triggeredCameraIDs}
>
</frigate-card-live-grid>
+3 -2
View File
@@ -11,6 +11,7 @@ import { classMap } from 'lit/directives/class-map.js';
import { guard } from 'lit/directives/guard.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js';
import { CameraEndpoints } from '../../camera-manager/types.js';
import { MicrophoneState } from '../../card-controller/types.js';
import { dispatchLiveErrorEvent } from '../../components-lib/live/utils/dispatch-live-error.js';
import { PartialZoomSettings } from '../../components-lib/zoom/types.js';
import {
@@ -64,7 +65,7 @@ export class FrigateCardLiveProvider
public cardWideConfig?: CardWideConfig;
@property({ attribute: false })
public microphoneStream?: MediaStream;
public microphoneState?: MicrophoneState;
@property({ attribute: false })
public zoomSettings?: PartialZoomSettings | null;
@@ -351,7 +352,7 @@ export class FrigateCardLiveProvider
.hass=${this.hass}
.cameraConfig=${this.cameraConfig}
.cameraEndpoints=${this.cameraEndpoints}
.microphoneStream=${this.microphoneStream}
.microphoneState=${this.microphoneState}
.microphoneConfig=${this.liveConfig.microphone}
?controls=${this.liveConfig.controls.builtin}
@frigate-card:live:error=${() => this._providerErrorHandler()}
+12 -9
View File
@@ -8,6 +8,7 @@ import {
} from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { CameraEndpoints } from '../../../../camera-manager/types.js';
import { MicrophoneState } from '../../../../card-controller/types.js';
import { dispatchLiveErrorEvent } from '../../../../components-lib/live/utils/dispatch-live-error.js';
import { CameraConfig, MicrophoneConfig } from '../../../../config/types.js';
import { localize } from '../../../../localize/localize.js';
@@ -44,7 +45,7 @@ export class FrigateCardGo2RTC extends LitElement implements FrigateCardMediaPla
public cameraEndpoints?: CameraEndpoints;
@property({ attribute: false })
public microphoneStream?: MediaStream;
public microphoneState?: MicrophoneState;
@property({ attribute: false })
public microphoneConfig?: MicrophoneConfig;
@@ -147,7 +148,7 @@ export class FrigateCardGo2RTC extends LitElement implements FrigateCardMediaPla
this._player = new VideoRTC();
this._player.containingPlayer = this;
this._player.microphoneStream = this.microphoneStream ?? null;
this._player.microphoneStream = this.microphoneState?.stream ?? null;
this._player.src = address;
this._player.visibilityCheck = false;
this._player.controls = this.controls;
@@ -172,14 +173,16 @@ export class FrigateCardGo2RTC extends LitElement implements FrigateCardMediaPla
this._player.controls = this.controls;
}
if (this._player && changedProps.has('microphoneStream')) {
if (this._player?.microphoneStream !== this.microphoneStream) {
this._player.microphoneStream = this.microphoneStream ?? null;
if (
this._player &&
changedProps.has('microphoneState') &&
this._player?.microphoneStream !== this.microphoneState?.stream
) {
this._player.microphoneStream = this.microphoneState?.stream ?? null;
// Need to force a reconnect if the microphone stream changes since
// WebRTC cannot introduce a new stream after the offer is already made.
this._player.reconnect();
}
// Need to force a reconnect if the microphone stream changes since
// WebRTC cannot introduce a new stream after the offer is already made.
this._player.reconnect();
}
}
@@ -394,9 +394,10 @@ export class VideoRTC extends HTMLElement {
this.pcState = WebSocket.CLOSED;
if (this.pc) {
this.pc.getSenders().forEach((sender) => {
if (sender.track) sender.track.stop();
});
// Do not close the (microphone) track attached to the peer connection as
// that is controlled by MicrophoneManager.
// See: https://github.com/dermotduffy/frigate-hass-card/issues/1810
this.pc.close();
this.pc = null;
}
+3 -3
View File
@@ -10,7 +10,7 @@ import { customElement, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { CameraManager } from '../camera-manager/manager.js';
import { ConditionsManagerEpoch } from '../card-controller/conditions-manager.js';
import { ReadonlyMicrophoneManager } from '../card-controller/microphone-manager.js';
import { MicrophoneState } from '../card-controller/types.js';
import { ViewManagerEpoch } from '../card-controller/view/types.js';
import {
CardWideConfig,
@@ -60,7 +60,7 @@ export class FrigateCardViews extends LitElement {
public hide?: boolean;
@property({ attribute: false })
public microphoneManager?: ReadonlyMicrophoneManager;
public microphoneState?: MicrophoneState;
@property({ attribute: false })
public triggeredCameraIDs?: Set<string>;
@@ -243,7 +243,7 @@ export class FrigateCardViews extends LitElement {
.overrides=${this.overriddenConfig.overrides}
.cameraManager=${this.cameraManager}
.cardWideConfig=${this.cardWideConfig}
.microphoneManager=${this.microphoneManager}
.microphoneState=${this.microphoneState}
.triggeredCameraIDs=${this.triggeredCameraIDs}
class="${classMap(liveClasses)}"
>