package io.g365sfu; import java.nio.ByteBuffer; import java.util.HashSet; import io.g365sfu.net.Outgoing; /** * Это комната для звонков, она может быть как для двоих участников, так и для групповых звонков. * Комната содержит в себе информацию о том, на каком она SFU сервере, какой у нее ID, кто в ней участвует. */ public class Room { private String roomId; private SFU sfu; private HashSet participants; /** * Создать комнату с заданным ID, SFU сервером и участниками * @param roomId уникальный идентификатор комнаты, который должен быть согласован с SFU сервером и использоваться для всех операций с этой комнатой * @param sfu SFU сервер, на котором будет создана комната и через который будет происходить обмен данными между участниками * @param participants массив идентификаторов участников, которые будут добавлены в комнату. Идентификаторы должны быть согласованы с SFU сервером и использоваться для маршрутизации данных между участниками. */ public Room(String roomId, SFU sfu, HashSet participants) { this.roomId = roomId; this.sfu = sfu; this.participants = participants; } public String getRoomId() { return roomId; } public SFU getSfu() { return sfu; } public HashSet getParticipants() { return participants; } public void addParticipant(String participantId) { this.participants.add(participantId); } public void removeParticipant(String participantId) { this.participants.remove(participantId); } public boolean containsParticipant(String participantId) { return this.participants.contains(participantId); } /** * Отправляет SDP offer в SFU сервер для организации звонка между пользователями. * Этот метод используется для отправки предложения о соединении от одного участника * к другому через сервер SFU, который будет пересылать это предложение целевому участнику. * Параметры roomId и peerId используются для идентификации комнаты и целевого участника, * а sdpOffer содержит описание медиа-сессии, которую участник хочет установить. * @param roomId идентификатор комнаты, в которой участник хочет организовать звонок * @param peerId идентификатор целевого участника, которому отправляется предложение о соединении * @param sdpOffer строка, содержащая SDP offer, которая описывает медиа-сессию, которую участник хочет установить с целевым участником. * @internal Этот метод формирует пакет с кодом 0x04, за которым следует идентификатор комнаты, идентификатор целевого участника и строка SDP offer. */ public void sdpOffer(String participantId, String sdpOffer) { /** * 1 байт номер пакета, * 4 байта длина ID комнаты, * N байт ID комнаты, * 4 байта длина ID участника, * M байт ID участника, * 4 байта длина SDP offer, * K байт SDP offer */ ByteBuffer buffer = ByteBuffer.allocate( 1 + 4 + this.roomId.getBytes().length + 4 + participantId.getBytes().length + 4 + sdpOffer.getBytes().length); /** * 0x03 - SDP offer */ buffer.put(Outgoing.SDP_OFFER_RETRANSLATE); buffer.putInt(this.roomId.getBytes().length); buffer.put(this.roomId.getBytes()); buffer.putInt(participantId.getBytes().length); buffer.put(participantId.getBytes()); buffer.putInt(sdpOffer.getBytes().length); buffer.put(sdpOffer.getBytes()); buffer.flip(); this.sfu.getConnection().send(buffer); } /** * Отправляет ICE-кандидата в SFU сервер для одного из участников комнаты. * @param participantId участник комнаты * @param iceCandidate кандидат */ public void iceCandidate(String participantId, String iceCandidate) { /** * 1 байт номер пакета, * 4 байта длина ID комнаты, * N байт ID комнаты, * 4 байта длина ID участника, * M байт ID участника, * 4 байта длина ICE кандидата, * K байт ICE кандидата */ ByteBuffer buffer = ByteBuffer.allocate( 1 + 4 + this.roomId.getBytes().length + 4 + participantId.getBytes().length + 4 + iceCandidate.getBytes().length); /** * 0x06 - ICE кандидат */ buffer.put(Outgoing.ICE_CANDIDATE_RETRANSLATE); buffer.putInt(this.roomId.getBytes().length); buffer.put(this.roomId.getBytes()); buffer.putInt(participantId.getBytes().length); buffer.put(participantId.getBytes()); buffer.putInt(iceCandidate.getBytes().length); buffer.put(iceCandidate.getBytes()); buffer.flip(); this.sfu.getConnection().send(buffer); } /** * Отправляет SDP answer в SFU сервер для одного из участников комнаты. * @param participantId участник комнаты * @param sdpAnswer SDP answer */ public void sdpAnswer(String participantId, String sdpAnswer) { /** * 1 байт номер пакета, * 4 байта длина ID комнаты, * N байт ID комнаты, * 4 байта длина ID участника, * M байт ID участника, * 4 байта длина SDP answer, * K байт SDP answer */ ByteBuffer buffer = ByteBuffer.allocate( 1 + 4 + this.roomId.getBytes().length + 4 + participantId.getBytes().length + 4 + sdpAnswer.getBytes().length); /** * 0x07 - SDP answer */ buffer.put(Outgoing.SDP_ANSWER_RETRANSLATE); buffer.putInt(this.roomId.getBytes().length); buffer.put(this.roomId.getBytes()); buffer.putInt(participantId.getBytes().length); buffer.put(participantId.getBytes()); buffer.putInt(sdpAnswer.getBytes().length); buffer.put(sdpAnswer.getBytes()); buffer.flip(); this.sfu.getConnection().send(buffer); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Room room = (Room) obj; return roomId.equals(room.roomId); } }