Skip to content

Commit

Permalink
speaker button
Browse files Browse the repository at this point in the history
  • Loading branch information
xdzqyyds committed Nov 19, 2024
1 parent e233362 commit 36bff61
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 0 deletions.
37 changes: 37 additions & 0 deletions webapp/components/device.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '../lib/device'

import Loading from './svg/loading'
import SvgSpeaker from './svg/speaker'
import SvgAudio from './svg/audio'
import SvgVideo from './svg/video'
import { SvgPresentCancel, SvgPresentToAll } from './svg/present'
Expand All @@ -24,20 +25,25 @@ export default function DeviceBar(props: { streamId: string }) {
const [permissionAudio, setPermissionAudio] = useState('')
const [permissionVideo, setPermissionVideo] = useState('')

const [loadingSpeaker, setLoadingSpeaker] = useState(false)
const [loadingAudio, setLoadingAudio] = useState(false)
const [loadingVideo, setLoadingVideo] = useState(false)
const [loadingScreen, setLoadingScreen] = useState(false)

const {
userStatus,
currentDeviceSpeaker,
currentDeviceAudio,
currentDeviceVideo,
setCurrentDeviceSpeaker,
setCurrentDeviceAudio,
setCurrentDeviceVideo,
toggleEnableSpeaker,

Check failure on line 41 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

'toggleEnableSpeaker' is assigned a value but never used. Allowed unused vars must match /^_/u

Check failure on line 41 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

'toggleEnableSpeaker' is assigned a value but never used. Allowed unused vars must match /^_/u
toggleEnableAudio,
toggleEnableVideo,
} = useWhipClient(props.streamId)

const [deviceSpeaker, setDeviceSpeaker] = useState<Device[]>([deviceNone])
const [deviceAudio, setDeviceAudio] = useState<Device[]>([deviceNone])
const [deviceVideo, setDeviceVideo] = useState<Device[]>([deviceNone])

Expand Down Expand Up @@ -82,9 +88,15 @@ export default function DeviceBar(props: { streamId: string }) {

const devices = (await navigator.mediaDevices.enumerateDevices()).filter(i => !!i.deviceId)

const speakers = devices.filter(i => i.kind === 'audiooutput').map(toDevice)
const audios = devices.filter(i => i.kind === 'audioinput').map(toDevice)
const videos = devices.filter(i => i.kind === 'videoinput').map(toDevice)

if ( currentDeviceSpeaker === deviceNone.deviceId) {
let device = speakers[0];

Check failure on line 96 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

'device' is never reassigned. Use 'const' instead

Check warning on line 96 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Extra semicolon

Check failure on line 96 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

'device' is never reassigned. Use 'const' instead

Check warning on line 96 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Extra semicolon
if (device) await setCurrentDeviceSpeaker(device.deviceId);

Check warning on line 97 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Extra semicolon

Check warning on line 97 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Extra semicolon
}

if (currentDeviceAudio === deviceNone.deviceId) {
const device = audios[0]
if (device) await setCurrentDeviceAudio(device.deviceId)
Expand All @@ -95,6 +107,7 @@ export default function DeviceBar(props: { streamId: string }) {
if (device) await setCurrentDeviceVideo(device.deviceId)
}

setDeviceSpeaker([...speakers])
setDeviceAudio([...audios])
setDeviceVideo([...videos, deviceScreen])
}
Expand Down Expand Up @@ -130,6 +143,12 @@ export default function DeviceBar(props: { streamId: string }) {
return () => { navigator.mediaDevices.removeEventListener('devicechange', updateDeviceList) }
}, [])

const onChangedDeviceSpeaker = async (current: string) => {
setLoadingSpeaker(true)
await setCurrentDeviceSpeaker(current)
setLoadingSpeaker(false)
}

const onChangedDeviceAudio = async (current: string) => {
setLoadingAudio(true)
await setCurrentDeviceAudio(current)
Expand All @@ -151,6 +170,24 @@ export default function DeviceBar(props: { streamId: string }) {
return (
<div className="flex flex-row flex-wrap justify-around p-xs">
<center className="flex flex-row flex-wrap justify-around">
<section className="m-1 p-1 flex flex-row justify-center rounded-md border-1 border-indigo-500">

Check warning on line 173 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Expected indentation of 8 spaces but found 6

Check warning on line 173 in webapp/components/device.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Expected indentation of 8 spaces but found 6
<button className="text-rose-400 rounded-md w-8 h-8" onClick={async () => {
}}>
<center>{ loadingSpeaker ? <Loading/> : <SvgSpeaker/> }</center>
</button>
<div className="flex flex-col justify-between w-1 pointer-events-none">
</div>
<select
className="w-3.5 h-8 rounded-sm rotate-180"
value={currentDeviceSpeaker}
onChange={e => onChangedDeviceSpeaker(e.target.value)}
>
{deviceSpeaker.map(device =>
<option key={device.deviceId} value={device.deviceId}>{device.label}</option>
)}
</select>
</section>

<section className="m-1 p-1 flex flex-row justify-center rounded-md border-1 border-indigo-500">
<button className="text-rose-400 rounded-md w-8 h-8" onClick={async () => {
setLoadingAudio(true)
Expand Down
8 changes: 8 additions & 0 deletions webapp/components/svg/speaker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function SvgSpeaker() {
return (
<svg focusable="false" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M4 7h4l5-5v20l-5-5H4c-1.1 0-2-.9-2-2V9c0-1.1.9-2 2-2zm11.54 3.88l1.41-1.41c1.78 1.78 1.78 4.66 0 6.44l-1.41-1.41c1.17-1.17 1.17-3.07 0-4.24zm2.83-2.83l1.41-1.41c3.12 3.12 3.12 8.19 0 11.31l-1.41-1.41c2.34-2.34 2.34-6.13 0-8.49z"></path>
</svg>
);

Check warning on line 6 in webapp/components/svg/speaker.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Extra semicolon

Check warning on line 6 in webapp/components/svg/speaker.tsx

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Extra semicolon
}

43 changes: 43 additions & 0 deletions webapp/components/use/whip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,32 @@ interface WHIPData extends Data {
setUserName: (name: string) => void,
setSyncUserStatus: (callback: (userStatus: Stream) => void) => void,

currentDeviceSpeaker: string,
currentDeviceAudio: string,
currentDeviceVideo: string,
setCurrentDeviceSpeaker: (current: string) => Promise<void>,
setCurrentDeviceAudio: (current: string) => Promise<void>,
setCurrentDeviceVideo: (current: string) => Promise<void>,
toggleEnableSpeaker: () => Promise<void>,
toggleEnableAudio: () => Promise<void>,
toggleEnableVideo: () => Promise<void>,
}

class WHIPContext extends Context {
private audioElement: HTMLAudioElement
client: WHIPClient = new WHIPClient()
cache: WHIPData

currentDeviceSpeaker = deviceNone.deviceId
currentDeviceAudio = deviceNone.deviceId
currentDeviceVideo = deviceNone.deviceId
toggleEnableSpeaker = async () => this.setCurrentDeviceSpeaker(this.userStatus.speaker ? deviceNone.deviceId : this.currentDeviceSpeaker)
toggleEnableAudio = async () => this.setCurrentDeviceAudio(this.userStatus.audio ? deviceNone.deviceId : this.currentDeviceAudio)
toggleEnableVideo = async () => this.setCurrentDeviceVideo(this.userStatus.video ? deviceNone.deviceId : this.currentDeviceVideo)

constructor(id: string) {
super(id)
this.audioElement = document.createElement("audio")

Check warning on line 41 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Strings must use singlequote

Check warning on line 41 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Strings must use singlequote
this.cache = this.clone()
}

Expand Down Expand Up @@ -64,10 +71,13 @@ class WHIPContext extends Context {
setUserName: (name: string) => this.setUserName(name),
setSyncUserStatus: (callback: (userStatus: Stream) => void) => this.setSyncUserStatus(callback),

currentDeviceSpeaker: this.currentDeviceSpeaker,
currentDeviceAudio: this.currentDeviceAudio,
currentDeviceVideo: this.currentDeviceVideo,
setCurrentDeviceSpeaker: (current: string) => this.setCurrentDeviceSpeaker(current),
setCurrentDeviceAudio: (current: string) => this.setCurrentDeviceAudio(current),
setCurrentDeviceVideo: (current: string) => this.setCurrentDeviceVideo(current),
toggleEnableSpeaker: () => this.toggleEnableSpeaker(),
toggleEnableAudio: () => this.toggleEnableAudio(),
toggleEnableVideo: () => this.toggleEnableVideo(),
}
Expand Down Expand Up @@ -98,6 +108,39 @@ class WHIPContext extends Context {
}
}

async setCurrentDeviceSpeaker(current: string) {
const { userStatus, currentDeviceSpeaker } = this;

Check warning on line 112 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Extra semicolon

Check warning on line 112 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Extra semicolon

// 检查是否需要切换设备

Check warning on line 114 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Expected indentation of 4 spaces but found 6

Check warning on line 114 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Expected indentation of 4 spaces but found 6
if (current !== currentDeviceSpeaker || !userStatus.speaker) {

Check warning on line 115 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Expected indentation of 4 spaces but found 6

Check warning on line 115 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Expected indentation of 4 spaces but found 6
if (!this.audioElement) {

Check warning on line 116 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Expected indentation of 6 spaces but found 8

Check warning on line 116 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Expected indentation of 6 spaces but found 8
// 使用全局或共享的 audioElement

Check warning on line 117 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (macos-latest)

Expected indentation of 8 spaces but found 10

Check warning on line 117 in webapp/components/use/whip.ts

View workflow job for this annotation

GitHub Actions / Deploy proxy (ubuntu-latest)

Expected indentation of 8 spaces but found 10
this.audioElement = document.createElement("audio");
document.body.appendChild(this.audioElement);
}

// 设置新的扬声器设备
if (this.audioElement.setSinkId) {
try {
await this.audioElement.setSinkId(current);
console.log(`扬声器切换到设备: ${current}`);
} catch (error) {
console.error("切换音频输出设备失败:", error);
}
} else {
console.error("当前浏览器不支持 setSinkId");
}

// 更新状态
userStatus.speaker = current === deviceNone.deviceId ? false : true
this.currentDeviceSpeaker = current === deviceNone.deviceId ? this.currentDeviceSpeaker : current

// 同步状态并触发相关回调
this.sync();
this.syncUserStatus(userStatus);
}
}

onChangedDeviceAudio() {
const { pc, stream } = this
// If WebRTC is connected, switch track
Expand Down
1 change: 1 addition & 0 deletions webapp/components/use/whxp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Context extends EventTarget {
userStatus: Stream = {
name: '',
state: StreamState.New,
speaker: true,
audio: true,
video: true,
screen: false,
Expand Down
1 change: 1 addition & 0 deletions webapp/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum StreamState {
interface Stream {
name: string,
state: StreamState
speaker: boolean,
audio: boolean,
video: boolean,
screen: boolean,
Expand Down

0 comments on commit 36bff61

Please sign in to comment.