Web/vueVersion/src/hooks/device.ts (189 lines of code) (raw):
import { useDeviceInfo, useChannelInfo } from '~/store';
import DingRTC, {
CameraVideoTrack,
DeviceInfo,
LocalVideoTrack,
MicrophoneAudioTrack,
} from 'dingrtc';
import { print } from '~/utils/tools';
import { ref } from 'vue';
import { useChannel } from './channel';
type DeviceType = 'camera' | 'playback-device' | 'microphone';
export const useDevice = (scene?: 'pre' | 'in') => {
const loading = ref(false);
const channelInfo = useChannelInfo()
const deviceInfo = useDeviceInfo();
const { publish } = useChannel();
const updateDeviceList = (deviceType: DeviceType, info: DeviceInfo) => {
deviceInfo.$patch((prev) => {
const { cameraList, micList, speakerList } = prev;
const prevListMap: Record<DeviceType, any> = {
camera: { key: 'cameraList', value: cameraList },
'playback-device': { key: 'speakerList', value: speakerList },
microphone: { key: 'micList', value: micList },
};
const prevList = prevListMap[deviceType].value;
const newList = [...prevList];
print(`${deviceType} ${info.state}`, info.device.label, info.device.deviceId);
const index = prevList.findIndex(
(item: MediaDeviceInfo) => item.deviceId === info.device.deviceId,
);
if (info.state === 'active' && index === -1) {
newList.push(info.device);
} else if (info.state === 'inactive' && index !== -1) {
newList.splice(index, 1);
}
return {
[prevListMap[deviceType].key]: newList,
};
});
};
const openMicAndCameraSameTime = async () => {
await getDeviceList(true, true);
const [newCameraTrack, newMicTrack] = (await DingRTC.createMicrophoneAndCameraTracks(
{ dimension: deviceInfo.cameraDimension, frameRate: deviceInfo.cameraFrameRate, deviceId: deviceInfo.cameraId },
{ deviceId: deviceInfo.micId },
)) as [CameraVideoTrack, MicrophoneAudioTrack];
print('got camera and mic tracks');
newCameraTrack.on('track-ended', () => {
channelInfo.$patch({ cameraTrack: null });
});
newMicTrack.on('track-ended', () => {
channelInfo.$patch({ micTrack: null });
});
deviceInfo.$patch({
cameraId: newCameraTrack?.getMediaStreamTrack()?.getSettings().deviceId,
micId: newMicTrack?.getMediaStreamTrack()?.getSettings().deviceId,
speakerId: deviceInfo.speakerList?.[0]?.deviceId,
})
channelInfo.$patch({
cameraTrack: newCameraTrack,
micTrack: newMicTrack,
});
return [newCameraTrack, newMicTrack];
};
const getDeviceList = async (camera: boolean, mic: boolean) => {
if (camera) {
await DingRTC.getCameras().then((cameraList) => {
const pattern = /\([0-9a-zA+Z:]+\)/i;
const newCameraList = cameraList
.filter((item) => item.deviceId)
.map((item) => ({
...item.toJSON(),
label: item.label.replace(pattern, ''),
}));
deviceInfo.cameraList = newCameraList;
});
}
if (mic) {
await Promise.all([DingRTC.getMicrophones(), DingRTC.getPlaybackDevices()]).then((result) => {
const [micList, speakerList] = result;
const newMicList = micList.filter((item) => item.deviceId);
const newSpeakerList = speakerList.filter((item) => item.deviceId);
deviceInfo.$patch({
micList: newMicList,
speakerList: newSpeakerList,
});
});
}
};
const openCamera = () => {
return DingRTC.createCameraVideoTrack({
deviceId: deviceInfo.cameraId,
dimension: deviceInfo.cameraDimension,
frameRate: deviceInfo.cameraFrameRate,
}).then((track) => {
loading.value = false;
print('got camera track');
if (!deviceInfo.cameraId) {
const currentCameraId = track.getMediaStreamTrack()?.getCapabilities?.()?.deviceId;
deviceInfo.$patch({
cameraId: currentCameraId,
});
}
track.on('track-ended', () => {
channelInfo.$patch({ cameraTrack: null });
});
channelInfo.$patch({ cameraTrack: track });
return track;
});
};
const openMic = () => {
return DingRTC.createMicrophoneAudioTrack({ deviceId: deviceInfo.micId }).then((track) => {
loading.value = false;
if (!deviceInfo.micId) {
const currentMicId = track.getMediaStreamTrack()?.getCapabilities()?.deviceId;
deviceInfo.$patch({
micId: currentMicId,
speakerId: deviceInfo.speakerList[0]?.deviceId,
});
}
track.on('track-ended', () => {
channelInfo.$patch({ micTrack: null });
});
channelInfo.$patch({ micTrack: track });
print('got mic track');
return track;
});
};
const openScreen = () => {
if (loading.value) return Promise.reject();
return DingRTC.createScreenVideoTrack({
dimension: deviceInfo.screenDimension,
frameRate: deviceInfo.screenFrameRate,
}).then((track) => {
loading.value = false;
print('got screen track');
return track[0] as LocalVideoTrack;
});
};
const operateCamera = () => {
if (!channelInfo.cameraTrack) {
return openCamera().then((track) => {
if (scene !== 'pre') publish([track]);
});
} else {
return channelInfo.cameraTrack.setEnabled(!channelInfo.cameraTrack.enabled).then(() => {
print(`cameraTrack change to ${!channelInfo.cameraTrack.enabled ? 'disbaled' : 'enabled'}`);
channelInfo.$patch({ cameraTrack: channelInfo.cameraTrack });
});
}
};
const operateMic = () => {
if (!channelInfo.micTrack) {
return openMic().then((track) => {
const inPre = scene === 'pre';
if (!inPre) publish([track]);
});
} else {
return channelInfo.micTrack.setEnabled(!channelInfo.micTrack.enabled).then(() => {
print(`micTrack change to ${!channelInfo.micTrack.enabled ? 'disbaled' : 'enabled'}`);
});
}
};
const operateScreen = () => {
if (!channelInfo.screenTrack) {
openScreen().then((track) => {
channelInfo.$patch({ screenTrack: track });
publish([track]).catch(() => {
track.close();
channelInfo.$patch({ screenTrack: null });
});
});
} else {
channelInfo.screenTrack?.close();
print(`stop share screen`);
channelInfo.$patch({ screenTrack: null });
}
};
return {
openMic,
openCamera,
operateMic,
operateCamera,
operateScreen,
getDeviceList,
updateDeviceList,
openMicAndCameraSameTime,
};
};