Classroom Videoplayer kısımları düzeltildi.
This commit is contained in:
parent
c00bc1acf0
commit
d1ae106db7
4 changed files with 114 additions and 1 deletions
|
|
@ -360,6 +360,28 @@ public class ClassroomHub : Hub
|
|||
await Clients.Group(sessionId.ToString()).SendAsync("HandRaiseDismissed", new { studentId });
|
||||
}
|
||||
|
||||
[HubMethodName("SendOffer")]
|
||||
public async Task SendOfferAsync(Guid sessionId, Guid targetUserId, object offer)
|
||||
{
|
||||
// Tek hedef kullanıcıya gönderiyoruz
|
||||
await Clients.User(targetUserId.ToString())
|
||||
.SendAsync("ReceiveOffer", _currentUser.Id?.ToString(), offer);
|
||||
}
|
||||
|
||||
[HubMethodName("SendAnswer")]
|
||||
public async Task SendAnswerAsync(Guid sessionId, Guid targetUserId, object answer)
|
||||
{
|
||||
await Clients.User(targetUserId.ToString())
|
||||
.SendAsync("ReceiveAnswer", _currentUser.Id?.ToString(), answer);
|
||||
}
|
||||
|
||||
[HubMethodName("SendIceCandidate")]
|
||||
public async Task SendIceCandidateAsync(Guid sessionId, Guid targetUserId, object candidate)
|
||||
{
|
||||
await Clients.User(targetUserId.ToString())
|
||||
.SendAsync("ReceiveIceCandidate", _currentUser.Id?.ToString(), candidate);
|
||||
}
|
||||
|
||||
public override async Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ export class SignalRService {
|
|||
private onParticipantMuted?: (userId: string, isMuted: boolean) => void
|
||||
private onHandRaiseReceived?: (studentId: string) => void
|
||||
private onHandRaiseDismissed?: (studentId: string) => void
|
||||
private onOfferReceived?: (fromUserId: string, offer: RTCSessionDescriptionInit) => void
|
||||
private onAnswerReceived?: (fromUserId: string, answer: RTCSessionDescriptionInit) => void
|
||||
private onIceCandidateReceived?: (fromUserId: string, candidate: RTCIceCandidateInit) => void
|
||||
|
||||
constructor() {
|
||||
const { auth } = store.getState()
|
||||
|
|
@ -62,6 +65,21 @@ export class SignalRService {
|
|||
this.onHandRaiseDismissed?.(payload.studentId)
|
||||
})
|
||||
|
||||
this.connection.on('ReceiveOffer', (fromUserId: string, offer: RTCSessionDescriptionInit) => {
|
||||
this.onOfferReceived?.(fromUserId, offer)
|
||||
})
|
||||
|
||||
this.connection.on('ReceiveAnswer', (fromUserId: string, answer: RTCSessionDescriptionInit) => {
|
||||
this.onAnswerReceived?.(fromUserId, answer)
|
||||
})
|
||||
|
||||
this.connection.on(
|
||||
'ReceiveIceCandidate',
|
||||
(fromUserId: string, candidate: RTCIceCandidateInit) => {
|
||||
this.onIceCandidateReceived?.(fromUserId, candidate)
|
||||
},
|
||||
)
|
||||
|
||||
this.connection.onreconnected(() => {
|
||||
console.log('SignalR reconnected')
|
||||
})
|
||||
|
|
@ -350,6 +368,21 @@ export class SignalRService {
|
|||
}
|
||||
}
|
||||
|
||||
async sendOffer(sessionId: string, targetUserId: string, offer: RTCSessionDescriptionInit) {
|
||||
if (!this.isConnected) return
|
||||
await this.connection.invoke('SendOffer', sessionId, targetUserId, offer)
|
||||
}
|
||||
|
||||
async sendAnswer(sessionId: string, targetUserId: string, answer: RTCSessionDescriptionInit) {
|
||||
if (!this.isConnected) return
|
||||
await this.connection.invoke('SendAnswer', sessionId, targetUserId, answer)
|
||||
}
|
||||
|
||||
async sendIceCandidate(sessionId: string, targetUserId: string, candidate: RTCIceCandidateInit) {
|
||||
if (!this.isConnected) return
|
||||
await this.connection.invoke('SendIceCandidate', sessionId, targetUserId, candidate)
|
||||
}
|
||||
|
||||
setAttendanceUpdatedHandler(callback: (record: ClassroomAttendanceDto) => void) {
|
||||
this.onAttendanceUpdate = callback
|
||||
}
|
||||
|
|
@ -378,6 +411,24 @@ export class SignalRService {
|
|||
this.onHandRaiseDismissed = callback
|
||||
}
|
||||
|
||||
setOfferReceivedHandler(
|
||||
callback: (fromUserId: string, offer: RTCSessionDescriptionInit) => void,
|
||||
) {
|
||||
this.onOfferReceived = callback
|
||||
}
|
||||
|
||||
setAnswerReceivedHandler(
|
||||
callback: (fromUserId: string, answer: RTCSessionDescriptionInit) => void,
|
||||
) {
|
||||
this.onAnswerReceived = callback
|
||||
}
|
||||
|
||||
setIceCandidateReceivedHandler(
|
||||
callback: (fromUserId: string, candidate: RTCIceCandidateInit) => void,
|
||||
) {
|
||||
this.onIceCandidateReceived = callback
|
||||
}
|
||||
|
||||
async disconnect(): Promise<void> {
|
||||
if (this.isConnected && this.connection) {
|
||||
await this.connection.stop()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ export class WebRTCService {
|
|||
private peerConnections: Map<string, RTCPeerConnection> = new Map()
|
||||
private localStream: MediaStream | null = null
|
||||
private onRemoteStream?: (userId: string, stream: MediaStream) => void
|
||||
private onIceCandidate?: (userId: string, candidate: RTCIceCandidateInit) => void
|
||||
|
||||
// STUN servers for NAT traversal
|
||||
private rtcConfiguration: RTCConfiguration = {
|
||||
|
|
@ -55,6 +56,7 @@ export class WebRTCService {
|
|||
if (event.candidate) {
|
||||
console.log('ICE candidate generated for user:', userId, event.candidate)
|
||||
// In a real implementation, this would be sent via SignalR
|
||||
this.onIceCandidate?.(userId, event.candidate)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +70,10 @@ export class WebRTCService {
|
|||
return peerConnection
|
||||
}
|
||||
|
||||
setIceCandidateHandler(callback: (userId: string, candidate: RTCIceCandidateInit) => void) {
|
||||
this.onIceCandidate = callback
|
||||
}
|
||||
|
||||
async createOffer(userId: string): Promise<RTCSessionDescriptionInit> {
|
||||
const peerConnection = this.peerConnections.get(userId)
|
||||
if (!peerConnection) throw new Error('Peer connection not found')
|
||||
|
|
@ -138,6 +144,10 @@ export class WebRTCService {
|
|||
}
|
||||
}
|
||||
|
||||
getPeerConnection(userId: string): RTCPeerConnection | undefined {
|
||||
return this.peerConnections.get(userId)
|
||||
}
|
||||
|
||||
closeAllConnections(): void {
|
||||
this.peerConnections.forEach((pc) => pc.close())
|
||||
this.peerConnections.clear()
|
||||
|
|
|
|||
|
|
@ -240,8 +240,32 @@ const RoomDetail: React.FC = () => {
|
|||
setParticipants((prev) => prev.map((p) => (p.id === userId ? { ...p, stream } : p)))
|
||||
})
|
||||
|
||||
webRTCServiceRef.current.setIceCandidateHandler(async (toUserId, candidate) => {
|
||||
if (signalRServiceRef.current) {
|
||||
await signalRServiceRef.current.sendIceCandidate(classSession.id, toUserId, candidate)
|
||||
}
|
||||
})
|
||||
|
||||
signalRServiceRef.current.setOfferReceivedHandler(async (fromUserId, offer) => {
|
||||
if (!webRTCServiceRef.current?.getPeerConnection(fromUserId)) {
|
||||
await webRTCServiceRef.current?.createPeerConnection(fromUserId)
|
||||
}
|
||||
const answer = await webRTCServiceRef.current?.createAnswer(fromUserId, offer)
|
||||
if (answer) {
|
||||
await signalRServiceRef.current?.sendAnswer(classSession.id, fromUserId, answer)
|
||||
}
|
||||
})
|
||||
|
||||
signalRServiceRef.current.setAnswerReceivedHandler(async (fromUserId, answer) => {
|
||||
await webRTCServiceRef.current?.handleAnswer(fromUserId, answer)
|
||||
})
|
||||
|
||||
signalRServiceRef.current.setIceCandidateReceivedHandler(async (fromUserId, candidate) => {
|
||||
await webRTCServiceRef.current?.addIceCandidate(fromUserId, candidate)
|
||||
})
|
||||
|
||||
// Setup SignalR event handlers
|
||||
signalRServiceRef.current.setParticipantJoinHandler((userId, name) => {
|
||||
signalRServiceRef.current.setParticipantJoinHandler(async (userId, name) => {
|
||||
// 🔑 Eğer gelen participant bizsek, listeye ekleme
|
||||
if (userId === user.id) return
|
||||
|
||||
|
|
@ -250,6 +274,12 @@ const RoomDetail: React.FC = () => {
|
|||
// Create WebRTC connection for new participant
|
||||
if (webRTCServiceRef.current) {
|
||||
webRTCServiceRef.current.createPeerConnection(userId)
|
||||
|
||||
// Eğer biz teacher isek offer oluşturup gönderelim
|
||||
if (user.role === 'teacher') {
|
||||
const offer = await webRTCServiceRef.current.createOffer(userId)
|
||||
await signalRServiceRef.current?.sendOffer(classSession.id, userId, offer)
|
||||
}
|
||||
}
|
||||
|
||||
setParticipants((prev) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue