Mark Duppenthaler commited on
Commit
bb3dc0d
1 Parent(s): f67796b

Single User

Browse files
seamless_server/app_pubsub.py CHANGED
@@ -123,12 +123,12 @@ class ServerLock(TypedDict):
123
  client_id: str
124
  member_object: Member
125
 
126
- MAX_SPEAKERS = os.environ.get("MAX_SPEAKERS")
127
 
128
  if os.environ.get("LOCK_SERVER_COMPLETELY", "0") == "1":
129
  logger.info("LOCK_SERVER_COMPLETELY is set. Server will be locked on startup.")
130
- if MAX_SPEAKERS is not None and int(MAX_SPEAKERS):
131
- logger.info(f"MAX_SPEAKERS is set to: {MAX_SPEAKERS}")
132
  dummy_server_lock_member_object = Member(
133
  client_id="seamless_user", session_id="dummy", name="Seamless User"
134
  )
@@ -428,6 +428,7 @@ async def join_room(sid, client_id, room_id_from_client, config_dict):
428
  }
429
  logger.info(f"[event: join_room] {args}")
430
  session_data = await get_session_data(sid)
 
431
  logger.info(f"session_data: {session_data}")
432
 
433
  room_id = room_id_from_client
@@ -459,6 +460,13 @@ async def join_room(sid, client_id, room_id_from_client, config_dict):
459
  session_id=sid,
460
  name=name,
461
  )
 
 
 
 
 
 
 
462
  logger.info(f"Created a new Member object: {member}")
463
  logger.info(f"Adding {member} to room {room_id}")
464
  room.members[client_id] = member
@@ -500,32 +508,22 @@ async def join_room(sid, client_id, room_id_from_client, config_dict):
500
  speaker_id for speaker_id in room.speakers if speaker_id != client_id
501
  ]
502
 
503
- # If we currently own the server lock and are updating roles and we no longer have server lock specified, release it
504
- if (
505
- server_lock is not None
506
- and server_lock["client_id"] == client_id
507
- and config_dict.get("lockServerName") is None
508
- ):
509
- logger.info(f"[join_room] Releasing server lock: {pformat(server_lock)}")
510
- server_lock = None
511
-
512
  # Only speakers should be able to lock the server
513
  if config_dict.get("lockServerName") is not None and "speaker" in config_dict.get(
514
  "roles", {}
515
  ):
516
  # If something goes wrong and the server gets stuck in a locked state the client can
517
  # force the server to remove the lock by passing the special name ESCAPE_HATCH_SERVER_LOCK_RELEASE_NAME
518
- if (
519
- server_lock is not None
520
- and config_dict.get("lockServerName")
521
- == ESCAPE_HATCH_SERVER_LOCK_RELEASE_NAME
522
- # If we are locking the server completely we don't want someone to be able to unlock it
523
- and not os.environ.get("LOCK_SERVER_COMPLETELY", "0") == "1"
524
- ):
525
- server_lock = None
526
- logger.info(
527
- f"🔓 Server lock has been reset by {client_id} using the escape hatch name {ESCAPE_HATCH_SERVER_LOCK_RELEASE_NAME}"
528
- )
529
 
530
  # If the server is not locked, set a lock. If it's already locked to this client, update the lock object
531
  if server_lock is None or server_lock.get("client_id") == client_id:
@@ -559,12 +557,21 @@ async def join_room(sid, client_id, room_id_from_client, config_dict):
559
 
560
  return {"roomsJoined": sio.rooms(sid), "roomID": room_id}
561
 
562
- def allow_speaker(room, client_id):
563
- if MAX_SPEAKERS is not None and client_id in room.speakers:
564
- room_statuses = {room_id: room.get_room_status_dict() for room_id, room in rooms.items()}
565
- speakers = sum(room_status["activeTranscoders"] for room_status in room_statuses.values())
566
- return speakers < int(MAX_SPEAKERS)
567
- return True
 
 
 
 
 
 
 
 
 
568
 
569
  # TODO: Add code to prevent more than one speaker from connecting/streaming at a time
570
  @sio.event
 
123
  client_id: str
124
  member_object: Member
125
 
126
+ SINGLE_USER = os.environ.get("SINGLE_USER")
127
 
128
  if os.environ.get("LOCK_SERVER_COMPLETELY", "0") == "1":
129
  logger.info("LOCK_SERVER_COMPLETELY is set. Server will be locked on startup.")
130
+ if SINGLE_USER == "1":
131
+ logger.info(f"SINGLE_USER mode is set. Server will only allow one speaker or listener at a time.")
132
  dummy_server_lock_member_object = Member(
133
  client_id="seamless_user", session_id="dummy", name="Seamless User"
134
  )
 
428
  }
429
  logger.info(f"[event: join_room] {args}")
430
  session_data = await get_session_data(sid)
431
+
432
  logger.info(f"session_data: {session_data}")
433
 
434
  room_id = room_id_from_client
 
460
  session_id=sid,
461
  name=name,
462
  )
463
+ allow_user = check_and_lock_single_user(client_id, member)
464
+ if not allow_user:
465
+ logger.error(
466
+ f"In SINGLE_USER mode we only allow one user at a time. Ignoring request to configure stream from client {client_id}."
467
+ )
468
+ return {"status": "error", "message": "max_users"}
469
+
470
  logger.info(f"Created a new Member object: {member}")
471
  logger.info(f"Adding {member} to room {room_id}")
472
  room.members[client_id] = member
 
508
  speaker_id for speaker_id in room.speakers if speaker_id != client_id
509
  ]
510
 
 
 
 
 
 
 
 
 
 
511
  # Only speakers should be able to lock the server
512
  if config_dict.get("lockServerName") is not None and "speaker" in config_dict.get(
513
  "roles", {}
514
  ):
515
  # If something goes wrong and the server gets stuck in a locked state the client can
516
  # force the server to remove the lock by passing the special name ESCAPE_HATCH_SERVER_LOCK_RELEASE_NAME
517
+ # TEMP: remove escape hatch for demo
518
+ # if (
519
+ # server_lock is not None
520
+ # and config_dict.get("lockServerName")
521
+ # == ESCAPE_HATCH_SERVER_LOCK_RELEASE_NAME
522
+ # ):
523
+ # server_lock = None
524
+ # logger.info(
525
+ # f"🔓 Server lock has been reset by {client_id} using the escape hatch name {ESCAPE_HATCH_SERVER_LOCK_RELEASE_NAME}"
526
+ # )
 
527
 
528
  # If the server is not locked, set a lock. If it's already locked to this client, update the lock object
529
  if server_lock is None or server_lock.get("client_id") == client_id:
 
557
 
558
  return {"roomsJoined": sio.rooms(sid), "roomID": room_id}
559
 
560
+ def check_and_lock_single_user(client_id, member):
561
+ global server_lock
562
+
563
+ if SINGLE_USER is None:
564
+ return True
565
+
566
+ if server_lock is None:
567
+ server_lock = {
568
+ "name": "single_user",
569
+ "client_id": client_id,
570
+ "member_object": member,
571
+ }
572
+ return True
573
+
574
+ return server_lock["client_id"] == client_id
575
 
576
  # TODO: Add code to prevent more than one speaker from connecting/streaming at a time
577
  @sio.event
streaming-react-app/src/RoomConfig.tsx CHANGED
@@ -27,12 +27,14 @@ type Props = {
27
  serverState: ServerState | null;
28
  onJoinRoomOrUpdateRoles?: () => void;
29
  streamingStatus: StreamingStatus;
 
30
  };
31
 
32
  export default function RoomConfig({
33
  roomState,
34
  serverState,
35
  onJoinRoomOrUpdateRoles,
 
36
  streamingStatus,
37
  }: Props) {
38
  const {socket, clientID} = useSocket();
@@ -90,6 +92,13 @@ export default function RoomConfig({
90
  configObject,
91
  (result) => {
92
  console.log('join_room result:', result);
 
 
 
 
 
 
 
93
  if (createNewRoom) {
94
  setRoomID(result.roomID);
95
  }
 
27
  serverState: ServerState | null;
28
  onJoinRoomOrUpdateRoles?: () => void;
29
  streamingStatus: StreamingStatus;
30
+ setHasMaxUsers: (hasMaxUsers: boolean) => void;
31
  };
32
 
33
  export default function RoomConfig({
34
  roomState,
35
  serverState,
36
  onJoinRoomOrUpdateRoles,
37
+ setHasMaxUsers,
38
  streamingStatus,
39
  }: Props) {
40
  const {socket, clientID} = useSocket();
 
92
  configObject,
93
  (result) => {
94
  console.log('join_room result:', result);
95
+ if (result.message === 'max_users') {
96
+ setHasMaxUsers(true);
97
+ setJoinInProgress(false);
98
+ return;
99
+ } else {
100
+ setHasMaxUsers(false);
101
+ }
102
  if (createNewRoom) {
103
  setRoomID(result.roomID);
104
  }
streaming-react-app/src/SocketWrapper.tsx CHANGED
@@ -11,9 +11,10 @@ import {getURLParams} from './URLParams';
11
 
12
  // The time to wait before showing a "disconnected" screen upon initial app load
13
  const INITIAL_DISCONNECT_SCREEN_DELAY = 2000;
14
- const SERVER_URL_DEFAULT = `${window.location.protocol === "https:" ? "wss" : "ws"
15
- }://${window.location.host}`;
16
-
 
17
  export default function SocketWrapper({children}) {
18
  const [socket, setSocket] = useState<Socket | null>(null);
19
  const [connected, setConnected] = useState<boolean | null>(null);
 
11
 
12
  // The time to wait before showing a "disconnected" screen upon initial app load
13
  const INITIAL_DISCONNECT_SCREEN_DELAY = 2000;
14
+ // const SERVER_URL_DEFAULT = `${window.location.protocol === "https:" ? "wss" : "ws"
15
+ // }://${window.location.host}`;
16
+ const SERVER_URL_DEFAULT = 'http://localhost:8000/'
17
+
18
  export default function SocketWrapper({children}) {
19
  const [socket, setSocket] = useState<Socket | null>(null);
20
  const [connected, setConnected] = useState<boolean | null>(null);
streaming-react-app/src/StreamingInterface.tsx CHANGED
@@ -152,7 +152,7 @@ export default function StreamingInterface() {
152
  useState<StreamingStatus>('stopped');
153
 
154
  const isStreamConfiguredRef = useRef<boolean>(false);
155
- const [hasMaxSpeakers, setHasMaxSpeakers] = useState<boolean>(false);
156
 
157
  const [outputMode, setOutputMode] = useState<SupportedOutputMode>('s2s&t');
158
  const [inputSource, setInputSource] =
@@ -309,7 +309,6 @@ export default function StreamingInterface() {
309
  console.log('[configureStreamAsync] sending config', config);
310
 
311
  socket.emit('configure_stream', config, (statusObject) => {
312
- setHasMaxSpeakers(statusObject.message === 'max_speakers')
313
  if (statusObject.status === 'ok') {
314
  isStreamConfiguredRef.current = true;
315
  console.debug(
@@ -757,20 +756,20 @@ export default function StreamingInterface() {
757
  <div className="header-container-sra">
758
  <div>
759
  <Typography variant="body2" sx={{color: '#65676B'}}>
760
- Welcome! This space is limited to one speaker at a time.
761
- If using the live HF space, sharing room code to listeners on another
762
- IP address may not work because it's running on different replicas.
763
  Use headphones if you are both speaker and listener to prevent feedback.
764
  <br/>
765
- If max speakers reached, please duplicate the space <a target="_blank" rel="noopener noreferrer" href="https://huggingface.co/spaces/facebook/seamless-streaming?duplicate=true">here</a>.
766
- In your duplicated space, join a room as speaker or listener (or both),
767
  and share the room code to invite listeners.
768
  <br/>
769
  Check out the seamless_communication <a target="_blank" rel="noopener noreferrer" href="https://github.com/facebookresearch/seamless_communication/tree/main">README</a> for more information.
770
  <br/>
771
  SeamlessStreaming model is a research model and is not released
772
- for production deployment. It is important to use a microphone with
773
- noise cancellation (for e.g. a smartphone), otherwise you may see model hallucination on noises.
774
  It works best if you pause every couple of sentences, or you may wish adjust the VAD threshold
775
  in the model config. The real-time performance will degrade
776
  if you try streaming multiple speakers at the same time.
@@ -783,6 +782,7 @@ export default function StreamingInterface() {
783
  roomState={roomState}
784
  serverState={serverState}
785
  streamingStatus={streamingStatus}
 
786
  onJoinRoomOrUpdateRoles={() => {
787
  // If the user has switched from speaker to listener we need to tell the
788
  // player to play eagerly, since currently the listener doesn't have any stop/start controls
@@ -955,6 +955,13 @@ export default function StreamingInterface() {
955
  </Grid>
956
  </Stack>
957
 
 
 
 
 
 
 
 
958
  <Stack
959
  direction="row"
960
  spacing={2}
@@ -1120,13 +1127,6 @@ export default function StreamingInterface() {
1120
  </Alert>
1121
  </div>
1122
  )}
1123
- {serverState != null && hasMaxSpeakers && (
1124
- <div>
1125
- <Alert severity="error">
1126
- {`Maximum number of speakers reached. Please try again at a later time.`}
1127
- </Alert>
1128
- </div>
1129
- )}
1130
  {serverState != null &&
1131
  serverState.totalActiveTranscoders >=
1132
  TOTAL_ACTIVE_TRANSCODER_WARNING_THRESHOLD && (
@@ -1156,6 +1156,13 @@ export default function StreamingInterface() {
1156
  )}
1157
  </div>
1158
 
 
 
 
 
 
 
 
1159
  {debugParam && roomID != null && <DebugSection />}
1160
 
1161
  <div className="translation-text-container-sra horizontal-padding-sra">
 
152
  useState<StreamingStatus>('stopped');
153
 
154
  const isStreamConfiguredRef = useRef<boolean>(false);
155
+ const [hasMaxUsers, setHasMaxUsers] = useState<boolean>(false);
156
 
157
  const [outputMode, setOutputMode] = useState<SupportedOutputMode>('s2s&t');
158
  const [inputSource, setInputSource] =
 
309
  console.log('[configureStreamAsync] sending config', config);
310
 
311
  socket.emit('configure_stream', config, (statusObject) => {
 
312
  if (statusObject.status === 'ok') {
313
  isStreamConfiguredRef.current = true;
314
  console.debug(
 
756
  <div className="header-container-sra">
757
  <div>
758
  <Typography variant="body2" sx={{color: '#65676B'}}>
759
+ Welcome! This space is limited to one user at a time.
760
+ If using the live HF space, sharing room code to listeners on another
761
+ IP address may not work because it's running on different replicas.
762
  Use headphones if you are both speaker and listener to prevent feedback.
763
  <br/>
764
+ If max users reached, please duplicate the space <a target="_blank" rel="noopener noreferrer" href="https://huggingface.co/spaces/facebook/seamless-streaming?duplicate=true">here</a>.
765
+ In your duplicated space, join a room as speaker or listener (or both),
766
  and share the room code to invite listeners.
767
  <br/>
768
  Check out the seamless_communication <a target="_blank" rel="noopener noreferrer" href="https://github.com/facebookresearch/seamless_communication/tree/main">README</a> for more information.
769
  <br/>
770
  SeamlessStreaming model is a research model and is not released
771
+ for production deployment. It is important to use a microphone with
772
+ noise cancellation (for e.g. a smartphone), otherwise you may see model hallucination on noises.
773
  It works best if you pause every couple of sentences, or you may wish adjust the VAD threshold
774
  in the model config. The real-time performance will degrade
775
  if you try streaming multiple speakers at the same time.
 
782
  roomState={roomState}
783
  serverState={serverState}
784
  streamingStatus={streamingStatus}
785
+ setHasMaxUsers={setHasMaxUsers}
786
  onJoinRoomOrUpdateRoles={() => {
787
  // If the user has switched from speaker to listener we need to tell the
788
  // player to play eagerly, since currently the listener doesn't have any stop/start controls
 
955
  </Grid>
956
  </Stack>
957
 
958
+ <Typography variant="body2" sx={{color: '#65676B'}}>
959
+ Note: we don't recommend echo cancellation, as it may distort
960
+ the input audio (dropping words/sentences) if there is output
961
+ audio playing. Instead, you should use headphones if you'd like
962
+ to listen to the output audio while speaking.
963
+ </Typography>
964
+
965
  <Stack
966
  direction="row"
967
  spacing={2}
 
1127
  </Alert>
1128
  </div>
1129
  )}
 
 
 
 
 
 
 
1130
  {serverState != null &&
1131
  serverState.totalActiveTranscoders >=
1132
  TOTAL_ACTIVE_TRANSCODER_WARNING_THRESHOLD && (
 
1156
  )}
1157
  </div>
1158
 
1159
+ {hasMaxUsers && (
1160
+ <div>
1161
+ <Alert severity="error">
1162
+ {`Maximum number of users reached. Please try again at a later time.`}
1163
+ </Alert>
1164
+ </div>
1165
+ )}
1166
  {debugParam && roomID != null && <DebugSection />}
1167
 
1168
  <div className="translation-text-container-sra horizontal-padding-sra">