todo comment fix screen sharing and video aspect ratio
This commit is contained in:
parent
9eb33512f4
commit
2a9e80cc5a
10 changed files with 902 additions and 188 deletions
|
|
@ -79,16 +79,18 @@ export class NetworkManager extends EventEmitter {
|
|||
switch (msg.type) {
|
||||
case 'Joined':
|
||||
console.log('Joined Room:', msg.data);
|
||||
this.userId = msg.data.self_id; // Server sends self_id, not user_id
|
||||
// Init UDP
|
||||
this.userId = msg.data.self_id;
|
||||
this.setupUdp();
|
||||
resolve(msg.data); // Return joined data (peers, etc)
|
||||
resolve(msg.data);
|
||||
break;
|
||||
case 'PeerJoined':
|
||||
this.mainWindow.webContents.send('peer-joined', msg.data);
|
||||
this.safeSend('peer-joined', msg.data);
|
||||
break;
|
||||
case 'PeerLeft':
|
||||
this.mainWindow.webContents.send('peer-left', msg.data);
|
||||
this.safeSend('peer-left', msg.data);
|
||||
break;
|
||||
case 'ChatMessage':
|
||||
this.safeSend('chat-message', msg.data);
|
||||
break;
|
||||
case 'Error':
|
||||
console.error('WS Error Msg:', msg.data);
|
||||
|
|
@ -97,6 +99,20 @@ export class NetworkManager extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
sendChat(message: string, displayName: string) {
|
||||
if (!this.ws) return;
|
||||
const chatMsg = {
|
||||
type: 'ChatMessage',
|
||||
data: {
|
||||
user_id: this.userId,
|
||||
display_name: displayName,
|
||||
message,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
};
|
||||
this.ws.send(JSON.stringify(chatMsg));
|
||||
}
|
||||
|
||||
setupUdp() {
|
||||
this.udp = dgram.createSocket('udp4');
|
||||
|
||||
|
|
@ -128,6 +144,10 @@ export class NetworkManager extends EventEmitter {
|
|||
// const flags = msg.readUInt16LE(20);
|
||||
|
||||
const payload = msg.subarray(HEADER_SIZE);
|
||||
const sequence = msg.readUInt32LE(6);
|
||||
const timestamp = Number(msg.readBigUInt64LE(10));
|
||||
const fragIdx = msg.readUInt8(18);
|
||||
const fragCnt = msg.readUInt8(19);
|
||||
|
||||
if (mediaType === MediaType.Audio) {
|
||||
// Forward audio? Or decode here?
|
||||
|
|
@ -137,35 +157,69 @@ export class NetworkManager extends EventEmitter {
|
|||
// OR decode here with `opus-native` binding.
|
||||
// For now, let's send payload to renderer via IPC.
|
||||
// Note: IPC with high frequency audio packets might be laggy.
|
||||
// But for MVP it's okay.
|
||||
this.mainWindow.webContents.send('audio-frame', { user_id: userId, data: payload });
|
||||
this.safeSend('audio-frame', { user_id: userId, data: payload });
|
||||
} else if (mediaType === MediaType.Video) {
|
||||
// Send to renderer
|
||||
this.mainWindow.webContents.send('video-frame', { user_id: userId, data: payload });
|
||||
this.safeSend('video-frame', {
|
||||
user_id: userId,
|
||||
data: payload,
|
||||
seq: sequence,
|
||||
ts: timestamp,
|
||||
fidx: fragIdx,
|
||||
fcnt: fragCnt
|
||||
});
|
||||
} else if (mediaType === MediaType.Screen) {
|
||||
this.safeSend('screen-frame', {
|
||||
user_id: userId,
|
||||
data: payload,
|
||||
seq: sequence,
|
||||
ts: timestamp,
|
||||
fidx: fragIdx,
|
||||
fcnt: fragCnt
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private safeSend(channel: string, data: any) {
|
||||
if (this.mainWindow && !this.mainWindow.isDestroyed() && this.mainWindow.webContents) {
|
||||
try {
|
||||
this.mainWindow.webContents.send(channel, data);
|
||||
} catch (e) {
|
||||
console.error(`Failed to send ${channel} to renderer:`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendVideoFrame(frame: Uint8Array) {
|
||||
if (!this.udp) return;
|
||||
if (!this.udp || !this.userId) return;
|
||||
|
||||
// Construct Header
|
||||
const header = Buffer.alloc(HEADER_SIZE);
|
||||
header.writeUInt8(1, 0); // Version
|
||||
header.writeUInt8(MediaType.Video, 1);
|
||||
header.writeUInt32LE(this.userId, 2);
|
||||
header.writeUInt32LE(this.videoSeq++, 6);
|
||||
header.writeBigUInt64LE(BigInt(Date.now()), 10);
|
||||
header.writeUInt8(0, 18); // Frag idx
|
||||
header.writeUInt8(1, 19); // Frag cnt
|
||||
header.writeUInt16LE(0, 20); // Flags
|
||||
const buffer = Buffer.from(frame);
|
||||
const MAX_PAYLOAD = 1400;
|
||||
const fragCount = Math.ceil(buffer.length / MAX_PAYLOAD);
|
||||
const seq = this.videoSeq++;
|
||||
const ts = BigInt(Date.now());
|
||||
|
||||
const packet = Buffer.concat([header, Buffer.from(frame)]);
|
||||
for (let i = 0; i < fragCount; i++) {
|
||||
const start = i * MAX_PAYLOAD;
|
||||
const end = Math.min(start + MAX_PAYLOAD, buffer.length);
|
||||
const chunk = buffer.subarray(start, end);
|
||||
|
||||
console.log(`[UDP] Sending Video: ${packet.length} bytes to ${SERVER_UDP_HOST}:${SERVER_UDP_PORT}`);
|
||||
// Send
|
||||
this.udp.send(packet, SERVER_UDP_PORT, SERVER_UDP_HOST, (err) => {
|
||||
if (err) console.error('UDP Send Error', err);
|
||||
});
|
||||
// MediaType.Video = 1
|
||||
const header = Buffer.alloc(HEADER_SIZE);
|
||||
header.writeUInt8(1, 0); // Version
|
||||
header.writeUInt8(MediaType.Video, 1);
|
||||
header.writeUInt32LE(this.userId, 2);
|
||||
header.writeUInt32LE(seq, 6);
|
||||
header.writeBigUInt64LE(ts, 10);
|
||||
header.writeUInt8(i, 18); // Frag idx
|
||||
header.writeUInt8(fragCount, 19); // Frag cnt
|
||||
header.writeUInt16LE(0, 20); // Flags
|
||||
|
||||
const packet = Buffer.concat([header, chunk]);
|
||||
|
||||
this.udp.send(packet, SERVER_UDP_PORT, SERVER_UDP_HOST, (err) => {
|
||||
if (err) console.error('UDP Video Send Error', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sendAudioFrame(frame: Uint8Array) {
|
||||
|
|
@ -184,12 +238,46 @@ export class NetworkManager extends EventEmitter {
|
|||
|
||||
const packet = Buffer.concat([header, Buffer.from(frame)]);
|
||||
|
||||
console.log(`[UDP] Sending Audio: ${packet.length} bytes to ${SERVER_UDP_HOST}:${SERVER_UDP_PORT}`);
|
||||
this.udp.send(packet, SERVER_UDP_PORT, SERVER_UDP_HOST, (err) => {
|
||||
if (err) console.error('UDP Audio Send Error', err);
|
||||
});
|
||||
}
|
||||
|
||||
private screenSeq = 0;
|
||||
|
||||
sendScreenFrame(frame: number[]) {
|
||||
if (!this.udp || !this.userId) return;
|
||||
|
||||
const buffer = Buffer.from(frame);
|
||||
const MAX_PAYLOAD = 1400; // MTU friendly (~1500 total with headers)
|
||||
const fragCount = Math.ceil(buffer.length / MAX_PAYLOAD);
|
||||
const seq = this.screenSeq++;
|
||||
const ts = BigInt(Date.now());
|
||||
|
||||
for (let i = 0; i < fragCount; i++) {
|
||||
const start = i * MAX_PAYLOAD;
|
||||
const end = Math.min(start + MAX_PAYLOAD, buffer.length);
|
||||
const chunk = buffer.subarray(start, end);
|
||||
|
||||
// MediaType.Screen = 2
|
||||
const header = Buffer.alloc(HEADER_SIZE);
|
||||
header.writeUInt8(1, 0); // Version
|
||||
header.writeUInt8(MediaType.Screen, 1);
|
||||
header.writeUInt32LE(this.userId, 2);
|
||||
header.writeUInt32LE(seq, 6);
|
||||
header.writeBigUInt64LE(ts, 10);
|
||||
header.writeUInt8(i, 18); // Frag idx
|
||||
header.writeUInt8(fragCount, 19); // Frag cnt
|
||||
header.writeUInt16LE(0, 20); // Flags
|
||||
|
||||
const packet = Buffer.concat([header, chunk]);
|
||||
|
||||
this.udp.send(packet, SERVER_UDP_PORT, SERVER_UDP_HOST, (err) => {
|
||||
if (err) console.error('UDP Screen Send Error', err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sendHandshake() {
|
||||
if (!this.udp || !this.userId || !this.roomCode) {
|
||||
console.error('[UDP] Cannot send handshake: missing udp, userId, or roomCode');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue