fix(core): auto-unmute on volume change and restore volume on unmute (#752)

This commit is contained in:
rahim
2026-03-05 17:48:59 -08:00
committed by GitHub
parent c61fcdcc3a
commit 4466d0a15c
2 changed files with 84 additions and 1 deletions
@@ -78,6 +78,39 @@ describe('volumeFeature', () => {
expect(video.volume).toBe(1);
});
it('unmutes when setting volume above 0 while muted', async () => {
const video = createMockVideo({ muted: true, volume: 0.5 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.setVolume(0.7);
expect(video.volume).toBe(0.7);
expect(video.muted).toBe(false);
});
it('does not unmute when setting volume to 0', async () => {
const video = createMockVideo({ muted: true, volume: 0.5 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.setVolume(0);
expect(video.volume).toBe(0);
expect(video.muted).toBe(true);
});
it('does not change muted when already unmuted', async () => {
const video = createMockVideo({ muted: false, volume: 0.5 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.setVolume(0.8);
expect(video.volume).toBe(0.8);
expect(video.muted).toBe(false);
});
});
describe('toggleMuted', () => {
@@ -102,6 +135,39 @@ describe('volumeFeature', () => {
expect(video.muted).toBe(false);
expect(result).toBe(false);
});
it('restores volume to 0.25 when unmuting at volume 0', async () => {
const video = createMockVideo({ muted: true, volume: 0 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.toggleMuted();
expect(video.muted).toBe(false);
expect(video.volume).toBe(0.25);
});
it('preserves volume when unmuting with volume > 0', async () => {
const video = createMockVideo({ muted: true, volume: 0.6 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.toggleMuted();
expect(video.muted).toBe(false);
expect(video.volume).toBe(0.6);
});
it('does not change volume when muting', async () => {
const video = createMockVideo({ muted: false, volume: 0.8 });
const store = createStore<PlayerTarget>()(volumeFeature);
store.attach({ media: video, container: null });
await store.toggleMuted();
expect(video.muted).toBe(true);
expect(video.volume).toBe(0.8);
});
});
});
});
+18 -1
View File
@@ -3,6 +3,9 @@ import { listen } from '@videojs/utils/dom';
import type { MediaFeatureAvailability, MediaVolumeState } from '../../../core/media/state';
import { definePlayerFeature } from '../../feature';
/** Volume to restore when unmuting at zero. */
const UNMUTE_VOLUME = 0.25;
export const volumeFeature = definePlayerFeature({
name: 'volume',
state: ({ target }): MediaVolumeState => ({
@@ -12,13 +15,27 @@ export const volumeFeature = definePlayerFeature({
setVolume(volume: number) {
const { media } = target();
media.volume = Math.max(0, Math.min(1, volume));
const clamped = Math.max(0, Math.min(1, volume));
// Auto-unmute when raising volume above zero.
if (clamped > 0 && media.muted) {
media.muted = false;
}
media.volume = clamped;
return media.volume;
},
toggleMuted() {
const { media } = target();
const willUnmute = media.muted;
media.muted = !media.muted;
// Restore a sensible volume when unmuting at zero.
if (willUnmute && media.volume === 0) {
media.volume = UNMUTE_VOLUME;
}
return media.muted;
},
}),