Spaces:
Running
on
T4
Running
on
T4
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 |
-
|
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
|
131 |
-
logger.info(f"
|
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 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
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
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
return
|
567 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
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 [
|
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
|
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
|
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">
|