Frontend: Blobs are existing!
This commit is contained in:
parent
106f61f881
commit
71f9c3b3ae
@ -27,6 +27,16 @@ export class VoiceService {
|
||||
this.connections.set(channelId, channelConnections);
|
||||
}
|
||||
|
||||
public setForUser(channelId: string, data: ChannelTypes.VoiceConnection) {
|
||||
const channelConnections = this.getOrCreate(channelId);
|
||||
const index = channelConnections.findIndex(c => c.userId === data.userId);
|
||||
|
||||
channelConnections[index] = data;
|
||||
this.connections.set(channelId, channelConnections);
|
||||
|
||||
return this.getForUser(channelId, data.userId);
|
||||
}
|
||||
|
||||
public remove(channelId: string, userId: string) {
|
||||
const channelConnections = this.getOrCreate(channelId);
|
||||
const index = channelConnections.findIndex(c => c.userId === userId);
|
||||
|
@ -8,6 +8,7 @@ import { VoiceService } from '../../voice/voice-service';
|
||||
import Users from '../../data/users';
|
||||
import { SelfUserDocument } from '../../data/models/user';
|
||||
import ChannelLeave from './channel-leave';
|
||||
import VoiceData from './voice-data';
|
||||
|
||||
export default class implements WSEvent<'CHANNEL_JOIN'> {
|
||||
on = 'CHANNEL_JOIN' as const;
|
||||
@ -17,6 +18,7 @@ export default class implements WSEvent<'CHANNEL_JOIN'> {
|
||||
private voice = Deps.get<VoiceService>(VoiceService),
|
||||
private users = Deps.get<Users>(Users),
|
||||
private leaveEvent = Deps.get<ChannelLeave>(ChannelLeave),
|
||||
private voiceDataEvent = Deps.get<VoiceData>(VoiceData),
|
||||
) {}
|
||||
|
||||
public async invoke(ws: WebSocket, client: Socket, { channelId }: WS.Params.ChannelJoin) {
|
||||
@ -35,7 +37,7 @@ export default class implements WSEvent<'CHANNEL_JOIN'> {
|
||||
if (doesExist)
|
||||
throw new TypeError('User already connected to voice');
|
||||
|
||||
this.voice.add(channelId, { stream: null, userId });
|
||||
this.voice.add(channelId, { userId });
|
||||
|
||||
await Promise.all([
|
||||
client.join(channelId),
|
||||
@ -56,6 +58,9 @@ export default class implements WSEvent<'CHANNEL_JOIN'> {
|
||||
userId: user.id,
|
||||
voice: user.voice,
|
||||
} as WS.Args.VoiceStateUpdate);
|
||||
|
||||
// send empty event to initialize cycle of sending data
|
||||
await this.voiceDataEvent.invoke(ws, client, { channelId });
|
||||
}
|
||||
|
||||
private async updateVoiceState(user: SelfUserDocument, channelId: string) {
|
||||
|
@ -12,16 +12,13 @@ export default class implements WSEvent<'VOICE_DATA'> {
|
||||
private voiceService = Deps.get<VoiceService>(VoiceService),
|
||||
) {}
|
||||
|
||||
public async invoke(ws: WebSocket, client: Socket, { channelId }: WS.Params.VoiceData) {
|
||||
public async invoke(ws: WebSocket, client: Socket, { channelId, blob }: WS.Params.VoiceData) {
|
||||
const userId = ws.sessions.get(client.id);
|
||||
// receive data
|
||||
// channel id of voice channel?
|
||||
// -> if specified in args it can be spoofed
|
||||
// -> if we constantly get user voice state from db that's very inefficient
|
||||
|
||||
// send audio back to client
|
||||
const connections = this.voiceService.getForUser(channelId, userId);
|
||||
const connections = this.voiceService.setForUser(channelId, { blob, userId });
|
||||
|
||||
client.emit('VOICE_DATA', { connections } as WS.Args.VoiceData);
|
||||
client.emit('VOICE_DATA', { channelId, connections } as WS.Args.VoiceData);
|
||||
}
|
||||
}
|
||||
|
13
frontend/package-lock.json
generated
13
frontend/package-lock.json
generated
@ -49,6 +49,7 @@
|
||||
"web-vitals": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dom-mediacapture-record": "^1.0.10",
|
||||
"@types/javascript-time-ago": "^2.0.3",
|
||||
"@types/promise-timeout": "^1.3.0",
|
||||
"@types/react-modal": "^3.12.1",
|
||||
@ -3373,6 +3374,12 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
|
||||
"integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg=="
|
||||
},
|
||||
"node_modules/@types/dom-mediacapture-record": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/dom-mediacapture-record/-/dom-mediacapture-record-1.0.10.tgz",
|
||||
"integrity": "sha512-8O84hHuVhMMLHLybf3y9SQpNcnQSuzVzcJaUNq9+4Ovb7fodS0aQXep4hyMtxd6fe/dyszbHFjFqtyawf4y46A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz",
|
||||
@ -24347,6 +24354,12 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
|
||||
"integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg=="
|
||||
},
|
||||
"@types/dom-mediacapture-record": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/dom-mediacapture-record/-/dom-mediacapture-record-1.0.10.tgz",
|
||||
"integrity": "sha512-8O84hHuVhMMLHLybf3y9SQpNcnQSuzVzcJaUNq9+4Ovb7fodS0aQXep4hyMtxd6fe/dyszbHFjFqtyawf4y46A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/eslint": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.0.tgz",
|
||||
|
@ -71,6 +71,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dom-mediacapture-record": "^1.0.10",
|
||||
"@types/javascript-time-ago": "^2.0.3",
|
||||
"@types/promise-timeout": "^1.3.0",
|
||||
"@types/react-modal": "^3.12.1",
|
||||
|
@ -142,17 +142,33 @@ const WSListener: React.FunctionComponent = () => {
|
||||
dispatch(auth.updatedUser(args));
|
||||
dispatch(users.updated(args));
|
||||
});
|
||||
ws.on('VOICE_DATA', (args) => {
|
||||
alert(args);
|
||||
ws.on('VOICE_DATA', async (args) => {
|
||||
const channelId = args.channelId;
|
||||
if (!channelId) return;
|
||||
|
||||
let audioChunks: Blob[] = [];
|
||||
const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
const recorder = new MediaRecorder(mediaStream);
|
||||
recorder.start();
|
||||
|
||||
recorder.onstart = () => {
|
||||
audioChunks = [];
|
||||
}
|
||||
recorder.ondataavailable = (e) =>{
|
||||
console.log('data available');
|
||||
audioChunks.push(e.data);
|
||||
};
|
||||
recorder.onstop = () => {
|
||||
const blob = new Blob(audioChunks, { 'type': 'audio/ogg; codecs=opus' });
|
||||
ws.emit('VOICE_DATA', { channelId, blob });
|
||||
}
|
||||
|
||||
setTimeout(() => recorder.stop(), 100);
|
||||
});
|
||||
ws.on('VOICE_STATE_UPDATE', (args) => {
|
||||
const data = { userId: args.userId, partialUser: { voice: args.voice } };
|
||||
dispatch(auth.updatedUser(data));
|
||||
dispatch(users.updated(data ));
|
||||
|
||||
if (!args.voice.channelId) return;
|
||||
|
||||
ws.emit('VOICE_DATA', { channelId: args.voice.channelId })
|
||||
dispatch(users.updated(data));
|
||||
});
|
||||
|
||||
dispatch(meta.listenedToWS());
|
||||
|
2
types/entity.d.ts
vendored
2
types/entity.d.ts
vendored
@ -92,7 +92,7 @@ declare namespace ChannelTypes {
|
||||
}
|
||||
export interface VoiceConnection {
|
||||
userId: string;
|
||||
stream: any;
|
||||
blob?: Blob;
|
||||
}
|
||||
}
|
||||
|
||||
|
2
types/ws.d.ts
vendored
2
types/ws.d.ts
vendored
@ -228,6 +228,7 @@ declare namespace WS {
|
||||
}
|
||||
export interface VoiceData {
|
||||
channelId: string;
|
||||
blob?: Blob;
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,6 +365,7 @@ declare namespace WS {
|
||||
partialUser: Partial<UserTypes.Self>;
|
||||
}
|
||||
export interface VoiceData {
|
||||
channelId: string;
|
||||
connections: VoiceConnection[];
|
||||
}
|
||||
export interface VoiceStateUpdate {
|
||||
|
Loading…
x
Reference in New Issue
Block a user