narinder1231 commited on
Commit
9a4d513
·
1 Parent(s): 7e89980

Add useWebRTC hook for managing WebRTC connections and voice calls

Browse files
Files changed (1) hide show
  1. src/hooks/useWebRTC.ts +130 -0
src/hooks/useWebRTC.ts ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from "react";
2
+
3
+ import { ICreateConversationResponse } from "../interfaces/conversation";
4
+ import { createConversation, createConnection } from "../services/api/chatService";
5
+ import { conversationWebSocket } from "../services/websockets/conversation";
6
+
7
+ export function useWebRTC() {
8
+ const [peerConnection, setPeerConnection] = useState<RTCPeerConnection | null>(null);
9
+ const [socket, setSocket] = useState<WebSocket | null>(null);
10
+ const [transcript, setTranscript] = useState<string>("");
11
+ const [isConnected, setIsConnected] = useState(false);
12
+ const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null);
13
+ const [error, setError] = useState<string | null>(null);
14
+
15
+ async function startCall() {
16
+ try {
17
+ setError(null);
18
+ const sessionResponse = await createConversation({ modality: "voice" });
19
+ const sessionData: ICreateConversationResponse = await sessionResponse.data;
20
+ const conversationId = sessionData.conversation_id;
21
+
22
+ const pc = new RTCPeerConnection();
23
+ setPeerConnection(pc);
24
+
25
+ pc.ontrack = (event) => {
26
+ const newStream = new MediaStream();
27
+ newStream.addTrack(event.track);
28
+ setRemoteStream(newStream);
29
+ };
30
+
31
+ pc.onconnectionstatechange = () => {
32
+ if (pc.connectionState === "connected") {
33
+ setIsConnected(true);
34
+ }
35
+ };
36
+
37
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
38
+ stream.getTracks().forEach((track) => {
39
+ pc.addTrack(track, stream);
40
+ });
41
+
42
+ const offer = await pc.createOffer();
43
+ await pc.setLocalDescription(offer);
44
+
45
+ const webrtcResponse = await createConnection(conversationId, {
46
+ conversation_id: conversationId,
47
+ offer: { sdp: offer.sdp, type: offer.type },
48
+ });
49
+
50
+ const response = await webrtcResponse.data;
51
+ const ephemeralKey = response.ephemeral_key;
52
+
53
+ const ws = conversationWebSocket({
54
+ conversationId,
55
+ modality: "voice",
56
+ });
57
+
58
+ setSocket(ws);
59
+
60
+ ws.onopen = () => {
61
+ ws.send(
62
+ JSON.stringify({
63
+ type: "headers",
64
+ headers: {
65
+ Authorization: `Bearer ${ephemeralKey}`,
66
+ },
67
+ })
68
+ );
69
+ };
70
+
71
+ ws.onmessage = (event) => {
72
+ try {
73
+ const data = JSON.parse(event.data);
74
+ if (data.transcript) {
75
+ setTranscript(data.transcript);
76
+ }
77
+ } catch {
78
+ setError("Error processing message from server");
79
+ }
80
+ };
81
+
82
+ pc.onicecandidate = (event) => {
83
+ if (event.candidate && ws.readyState === WebSocket.OPEN) {
84
+ ws.send(
85
+ JSON.stringify({
86
+ type: "ice-candidate",
87
+ candidate: event.candidate,
88
+ })
89
+ );
90
+ }
91
+ };
92
+
93
+ ws.onclose = (_event) => {
94
+ if (isConnected) {
95
+ endCall();
96
+ }
97
+ };
98
+
99
+ await pc.setRemoteDescription(new RTCSessionDescription(response.answer));
100
+
101
+ const dataChannel = pc.createDataChannel("chat");
102
+ dataChannel.onmessage = (event) => {
103
+ if (ws && ws.readyState === WebSocket.OPEN) {
104
+ ws.send(event.data);
105
+ }
106
+ };
107
+ } catch (error) {
108
+ setError(error instanceof Error ? error.message : "Failed to start call");
109
+ endCall();
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ function endCall() {
115
+ if (peerConnection) {
116
+ peerConnection.close();
117
+ setPeerConnection(null);
118
+ }
119
+
120
+ if (socket) {
121
+ socket.close();
122
+ setSocket(null);
123
+ }
124
+
125
+ setIsConnected(false);
126
+ setRemoteStream(null);
127
+ }
128
+
129
+ return { startCall, endCall, transcript, isConnected, remoteStream, error };
130
+ }