Skip to content

Commit

Permalink
sending webrtc video stream
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjoz committed Jul 7, 2024
1 parent c39a73c commit 7ab1909
Show file tree
Hide file tree
Showing 5 changed files with 388 additions and 22 deletions.
2 changes: 1 addition & 1 deletion backend/handlers/webrtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func AskRTCConnection(args *core.HandlerArgs) core.HandlerResponse {
}

if request.ClientAskID == "" || request.Offer == "" {
core.Log("No se recibió el ClientID o Offer")
core.Log("Error: No se recibió el ClientID o Offer")
return core.HandlerResponse{}
}

Expand Down
112 changes: 110 additions & 2 deletions frontend/src/components/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { For, createSignal } from "solid-js"
import { IClient, connectionManager } from "~/services/connection"
import { For, createEffect, createSignal, on } from "solid-js"
import { IClient, connectionManager, mimeCodec } from "~/services/connection"
// import s1 from '../styles/components.module.css';

export interface IChatContainer {
Expand All @@ -17,6 +17,85 @@ export const [chatMessages, setChatMessages] = createSignal([] as IChatMessage[]
export const ChatContainer = (props: IChatContainer) => {

let textArea: HTMLTextAreaElement
let videoLocal: HTMLVideoElement
let videoInput: HTMLVideoElement
let localStream: MediaStream
let sourceBuffer: SourceBuffer
let queue: Uint8Array[] = []

createEffect(() => {
console.log("obteniendo mensajes::",props.client)
/*
getDexieInstance().then(db => {
db.table('messages').where({ cid: props.client.id }).toArray().then(messages => {
messages.sort((a,b) => a.id < b.id ? 1 : -1)
props.client.messages = messages
setChatMessages(messages)
})
})
*/
})

createEffect(on(() => props.client,() => {
if(!videoInput){ return }
console.log("seteando video input::", videoInput)
videoInput.onloadedmetadata = () => {
console.log(`Remote video width: ${videoLocal.videoWidth}px, height: ${videoLocal.videoHeight}px`);
};

videoInput.onplay = () => {
console.log('Remote video is playing');
};

videoInput.onerror = (e) => {
console.error('Remote video error', e);
};

connectionManager.onVideoStream(props.client.id, (mediaStream: MediaStream) => {
console.log("stream recibido como source de vídeo::", mediaStream)
const videoTracks = mediaStream.getVideoTracks();
const audioTracks = mediaStream.getAudioTracks();
console.log("video tracks and audio tracks", videoTracks, audioTracks)

mediaStream.onaddtrack = (ev) => {
console.log("track añadido::", ev)
}
mediaStream.onremovetrack = (ev) => {
console.log("track removido::", ev)
}

if(videoInput.srcObject !== mediaStream){
videoInput.srcObject = mediaStream
}
})

/*
const mediaSource = new MediaSource()
console.log("generando media source::", mediaSource)
videoInput.src = URL.createObjectURL(mediaSource)
mediaSource.addEventListener('sourceopen', () => {
sourceBuffer = mediaSource.addSourceBuffer(mimeCodec)
sourceBuffer.mode = 'sequence'
sourceBuffer.addEventListener('updateend', () => {
if(queue.length > 0 && !sourceBuffer.updating){
sourceBuffer.appendBuffer(queue.shift())
}
})
})
connectionManager.onVideoChunk(props.client.id, (chunk, header) => {
console.log("chunk recibido::", chunk.length, header)
if(sourceBuffer && !sourceBuffer.updating){
sourceBuffer.appendBuffer(new Uint8Array(chunk))
} else {
queue.push(chunk)
}
})
*/
},{ defer: true }))

const sendMessage = () => {
const message = textArea?.value || ""
Expand All @@ -25,9 +104,38 @@ export const ChatContainer = (props: IChatContainer) => {
textArea.value = ""
}

const onvideoInit = async () => {
const constraints: MediaStreamConstraints = {
audio: true,
video: { width: { ideal: 640 }, height: { ideal: 480 } }
}

localStream = await navigator.mediaDevices.getUserMedia(constraints)
const localVideoStream = new MediaStream(localStream.getVideoTracks());
videoLocal.srcObject = localVideoStream
/*
connectionManager.sendMediaStream(props.client.id, localStream)
*/
connectionManager.sendStreamRequest(props.client.id, localStream)
}

return <div class="h100 p-rel flex-column">
{
props.client && <>
<div class="flex w100">
<div class="video-v1 mr-08" onClick={ev => {
ev.stopPropagation()
onvideoInit()
}}>
<video class="w100 h100" ref={videoLocal} autoplay playsinline></video>
</div>
<div class="video-v1" onClick={ev => {
ev.stopPropagation()
onvideoInit()
}}>
<video class="w100 h100" ref={videoInput} autoplay playsinline></video>
</div>
</div>
<div class="flex w100 mt-06 mb-06">
<textarea class="ttx chat_textarea w100" rows={2} ref={textArea} />
<button onClick={ev => {
Expand Down
53 changes: 48 additions & 5 deletions frontend/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,44 @@ import { ChatContainer, setChatMessages } from "~/components/chat";

export default function Home() {

// List of common video and audio codecs to check
const videoCodecs = [
'video/webm; codecs="vp8"',
'video/webm; codecs="vp9"',
'video/webm; codecs="av01"',
'video/mp4; codecs="avc1.42E01E"',
'video/mp4; codecs="avc1.4D401E"',
'video/mp4; codecs="avc1.64001E"',
'video/mp4; codecs="hev1.1.6.L93.B0"',
'video/mp4; codecs="hvc1.1.6.L93.B0"'
];

const audioCodecs = [
'audio/webm; codecs="opus"',
'audio/webm; codecs="vorbis"',
'audio/mp4; codecs="mp4a.40.2"',
'audio/aac'
];

console.log('Supported Video Codecs:');
videoCodecs.forEach(codec => {
if (MediaSource.isTypeSupported(codec)) {
console.log(codec, 'is supported');
} else {
console.log(codec, 'is NOT supported');
}
});

console.log('Supported Audio Codecs:');
audioCodecs.forEach(codec => {
if (MediaSource.isTypeSupported(codec)) {
console.log(codec, 'is supported');
} else {
console.log(codec, 'is NOT supported');
}
});


const [loadingClients, setLoadingClients] = createSignal(true)

const clientSelected = createMemo(() => {
Expand Down Expand Up @@ -89,6 +127,14 @@ const ClientCard = (props: IClientCard) => {
setStatus({...(props.client.connStatus||{})})
}

const statusMessage = createMemo(() => {
let message = status().status
if(message !== status().iceStatus){
message += " | " + status().iceStatus
}
return message
})

const nowTime = Math.floor(Date.now()/1000)
const haceMin = Math.ceil((nowTime - props.client._updated)/60)

Expand All @@ -106,11 +152,8 @@ const ClientCard = (props: IClientCard) => {
</div>
<div class="w100 flex jc-between">
<div>
{ status().status &&
<div>{status().status} | {status().iceStatus}</div>
}
{ !status().status &&
<div>?</div>
{ statusMessage() &&
<div>{statusMessage()}</div>
}
</div>
<div class="flex a-center">
Expand Down
Loading

0 comments on commit 7ab1909

Please sign in to comment.