Fix all the demos to use Twilio STUN/TURN servers
Browse files- app.py +2 -1
- pages/10_sendonly_audio.py +3 -1
- pages/11_programatic_control_playing.py +3 -1
- pages/12_media_constraints_configs.py +3 -1
- pages/13_ui_texts_customization.py +3 -1
- pages/2_opencv_filters.py +3 -1
- pages/3_audio_filter.py +3 -1
- pages/4_delayed_echo.py +3 -1
- pages/5_fork_multi_outputs.py +3 -1
- pages/6_mix_multi_inputs.py +3 -1
- pages/7_record.py +3 -1
- pages/8_media_files_streaming.py +2 -1
- pages/9_sendonly_video.py +3 -1
- sample_utils/turn.py +11 -3
app.py
CHANGED
@@ -15,6 +15,7 @@ import streamlit as st
|
|
15 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
16 |
|
17 |
from sample_utils.download import download_file
|
|
|
18 |
|
19 |
HERE = Path(__file__).parent
|
20 |
ROOT = HERE
|
@@ -137,7 +138,7 @@ def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame:
|
|
137 |
webrtc_ctx = webrtc_streamer(
|
138 |
key="object-detection",
|
139 |
mode=WebRtcMode.SENDRECV,
|
140 |
-
rtc_configuration={"iceServers":
|
141 |
video_frame_callback=video_frame_callback,
|
142 |
media_stream_constraints={"video": True, "audio": False},
|
143 |
async_processing=True,
|
|
|
15 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
16 |
|
17 |
from sample_utils.download import download_file
|
18 |
+
from sample_utils.turn import get_ice_servers
|
19 |
|
20 |
HERE = Path(__file__).parent
|
21 |
ROOT = HERE
|
|
|
138 |
webrtc_ctx = webrtc_streamer(
|
139 |
key="object-detection",
|
140 |
mode=WebRtcMode.SENDRECV,
|
141 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
142 |
video_frame_callback=video_frame_callback,
|
143 |
media_stream_constraints={"video": True, "audio": False},
|
144 |
async_processing=True,
|
pages/10_sendonly_audio.py
CHANGED
@@ -11,6 +11,8 @@ import pydub
|
|
11 |
import streamlit as st
|
12 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
13 |
|
|
|
|
|
14 |
logger = logging.getLogger(__name__)
|
15 |
|
16 |
|
@@ -18,7 +20,7 @@ webrtc_ctx = webrtc_streamer(
|
|
18 |
key="sendonly-audio",
|
19 |
mode=WebRtcMode.SENDONLY,
|
20 |
audio_receiver_size=256,
|
21 |
-
rtc_configuration={"iceServers":
|
22 |
media_stream_constraints={"audio": True},
|
23 |
)
|
24 |
|
|
|
11 |
import streamlit as st
|
12 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
13 |
|
14 |
+
from sample_utils.turn import get_ice_servers
|
15 |
+
|
16 |
logger = logging.getLogger(__name__)
|
17 |
|
18 |
|
|
|
20 |
key="sendonly-audio",
|
21 |
mode=WebRtcMode.SENDONLY,
|
22 |
audio_receiver_size=256,
|
23 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
24 |
media_stream_constraints={"audio": True},
|
25 |
)
|
26 |
|
pages/11_programatic_control_playing.py
CHANGED
@@ -3,11 +3,13 @@
|
|
3 |
import streamlit as st
|
4 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
5 |
|
|
|
|
|
6 |
playing = st.checkbox("Playing", value=True)
|
7 |
|
8 |
webrtc_streamer(
|
9 |
key="programatic_control",
|
10 |
desired_playing_state=playing,
|
11 |
mode=WebRtcMode.SENDRECV,
|
12 |
-
rtc_configuration={"iceServers":
|
13 |
)
|
|
|
3 |
import streamlit as st
|
4 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
5 |
|
6 |
+
from sample_utils.turn import get_ice_servers
|
7 |
+
|
8 |
playing = st.checkbox("Playing", value=True)
|
9 |
|
10 |
webrtc_streamer(
|
11 |
key="programatic_control",
|
12 |
desired_playing_state=playing,
|
13 |
mode=WebRtcMode.SENDRECV,
|
14 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
15 |
)
|
pages/12_media_constraints_configs.py
CHANGED
@@ -3,11 +3,13 @@
|
|
3 |
import streamlit as st
|
4 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
5 |
|
|
|
|
|
6 |
frame_rate = 5
|
7 |
webrtc_streamer(
|
8 |
key="media-constraints",
|
9 |
mode=WebRtcMode.SENDRECV,
|
10 |
-
rtc_configuration={"iceServers":
|
11 |
media_stream_constraints={
|
12 |
"video": {"frameRate": {"ideal": frame_rate}},
|
13 |
},
|
|
|
3 |
import streamlit as st
|
4 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
5 |
|
6 |
+
from sample_utils.turn import get_ice_servers
|
7 |
+
|
8 |
frame_rate = 5
|
9 |
webrtc_streamer(
|
10 |
key="media-constraints",
|
11 |
mode=WebRtcMode.SENDRECV,
|
12 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
13 |
media_stream_constraints={
|
14 |
"video": {"frameRate": {"ideal": frame_rate}},
|
15 |
},
|
pages/13_ui_texts_customization.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1 |
from streamlit_webrtc import webrtc_streamer
|
2 |
|
|
|
|
|
3 |
webrtc_streamer(
|
4 |
key="custom_ui_texts",
|
5 |
-
rtc_configuration={"iceServers":
|
6 |
translations={
|
7 |
"start": "開始",
|
8 |
"stop": "停止",
|
|
|
1 |
from streamlit_webrtc import webrtc_streamer
|
2 |
|
3 |
+
from sample_utils.turn import get_ice_servers
|
4 |
+
|
5 |
webrtc_streamer(
|
6 |
key="custom_ui_texts",
|
7 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
8 |
translations={
|
9 |
"start": "開始",
|
10 |
"stop": "停止",
|
pages/2_opencv_filters.py
CHANGED
@@ -5,6 +5,8 @@ import cv2
|
|
5 |
import streamlit as st
|
6 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
7 |
|
|
|
|
|
8 |
_type = st.radio("Select transform type", ("noop", "cartoon", "edges", "rotate"))
|
9 |
|
10 |
|
@@ -49,7 +51,7 @@ def callback(frame: av.VideoFrame) -> av.VideoFrame:
|
|
49 |
webrtc_streamer(
|
50 |
key="opencv-filter",
|
51 |
mode=WebRtcMode.SENDRECV,
|
52 |
-
rtc_configuration={"iceServers":
|
53 |
video_frame_callback=callback,
|
54 |
media_stream_constraints={"video": True, "audio": False},
|
55 |
async_processing=True,
|
|
|
5 |
import streamlit as st
|
6 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
7 |
|
8 |
+
from sample_utils.turn import get_ice_servers
|
9 |
+
|
10 |
_type = st.radio("Select transform type", ("noop", "cartoon", "edges", "rotate"))
|
11 |
|
12 |
|
|
|
51 |
webrtc_streamer(
|
52 |
key="opencv-filter",
|
53 |
mode=WebRtcMode.SENDRECV,
|
54 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
55 |
video_frame_callback=callback,
|
56 |
media_stream_constraints={"video": True, "audio": False},
|
57 |
async_processing=True,
|
pages/3_audio_filter.py
CHANGED
@@ -4,6 +4,8 @@ import pydub
|
|
4 |
import streamlit as st
|
5 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
6 |
|
|
|
|
|
7 |
gain = st.slider("Gain", -10.0, +20.0, 1.0, 0.05)
|
8 |
|
9 |
|
@@ -32,7 +34,7 @@ def process_audio(frame: av.AudioFrame) -> av.AudioFrame:
|
|
32 |
webrtc_streamer(
|
33 |
key="audio-filter",
|
34 |
mode=WebRtcMode.SENDRECV,
|
35 |
-
rtc_configuration={"iceServers":
|
36 |
audio_frame_callback=process_audio,
|
37 |
async_processing=True,
|
38 |
)
|
|
|
4 |
import streamlit as st
|
5 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
6 |
|
7 |
+
from sample_utils.turn import get_ice_servers
|
8 |
+
|
9 |
gain = st.slider("Gain", -10.0, +20.0, 1.0, 0.05)
|
10 |
|
11 |
|
|
|
34 |
webrtc_streamer(
|
35 |
key="audio-filter",
|
36 |
mode=WebRtcMode.SENDRECV,
|
37 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
38 |
audio_frame_callback=process_audio,
|
39 |
async_processing=True,
|
40 |
)
|
pages/4_delayed_echo.py
CHANGED
@@ -6,6 +6,8 @@ import av
|
|
6 |
import streamlit as st
|
7 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
8 |
|
|
|
|
|
9 |
logger = logging.getLogger(__name__)
|
10 |
|
11 |
|
@@ -34,7 +36,7 @@ async def queued_audio_frames_callback(
|
|
34 |
webrtc_streamer(
|
35 |
key="delay",
|
36 |
mode=WebRtcMode.SENDRECV,
|
37 |
-
rtc_configuration={"iceServers":
|
38 |
queued_video_frames_callback=queued_video_frames_callback,
|
39 |
queued_audio_frames_callback=queued_audio_frames_callback,
|
40 |
async_processing=True,
|
|
|
6 |
import streamlit as st
|
7 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
8 |
|
9 |
+
from sample_utils.turn import get_ice_servers
|
10 |
+
|
11 |
logger = logging.getLogger(__name__)
|
12 |
|
13 |
|
|
|
36 |
webrtc_streamer(
|
37 |
key="delay",
|
38 |
mode=WebRtcMode.SENDRECV,
|
39 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
40 |
queued_video_frames_callback=queued_video_frames_callback,
|
41 |
queued_audio_frames_callback=queued_audio_frames_callback,
|
42 |
async_processing=True,
|
pages/5_fork_multi_outputs.py
CHANGED
@@ -10,6 +10,8 @@ import cv2
|
|
10 |
import streamlit as st
|
11 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
12 |
|
|
|
|
|
13 |
st.markdown(
|
14 |
"""
|
15 |
Fork one input to multiple outputs with different video filters.
|
@@ -60,7 +62,7 @@ def make_video_frame_callback(_type: VideoFilterType):
|
|
60 |
return callback
|
61 |
|
62 |
|
63 |
-
COMMON_RTC_CONFIG = {"iceServers":
|
64 |
|
65 |
st.header("Input")
|
66 |
ctx = webrtc_streamer(
|
|
|
10 |
import streamlit as st
|
11 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
12 |
|
13 |
+
from sample_utils.turn import get_ice_servers
|
14 |
+
|
15 |
st.markdown(
|
16 |
"""
|
17 |
Fork one input to multiple outputs with different video filters.
|
|
|
62 |
return callback
|
63 |
|
64 |
|
65 |
+
COMMON_RTC_CONFIG = {"iceServers": get_ice_servers()}
|
66 |
|
67 |
st.header("Input")
|
68 |
ctx = webrtc_streamer(
|
pages/6_mix_multi_inputs.py
CHANGED
@@ -17,6 +17,8 @@ from streamlit_webrtc import (
|
|
17 |
webrtc_streamer,
|
18 |
)
|
19 |
|
|
|
|
|
20 |
st.markdown(
|
21 |
"""
|
22 |
Mix multiple inputs with different video filters into one stream.
|
@@ -112,7 +114,7 @@ def mixer_callback(frames: List[av.VideoFrame]) -> av.VideoFrame:
|
|
112 |
return new_frame
|
113 |
|
114 |
|
115 |
-
COMMON_RTC_CONFIG = {"iceServers":
|
116 |
|
117 |
st.header("Input 1")
|
118 |
input1_ctx = webrtc_streamer(
|
|
|
17 |
webrtc_streamer,
|
18 |
)
|
19 |
|
20 |
+
from sample_utils.turn import get_ice_servers
|
21 |
+
|
22 |
st.markdown(
|
23 |
"""
|
24 |
Mix multiple inputs with different video filters into one stream.
|
|
|
114 |
return new_frame
|
115 |
|
116 |
|
117 |
+
COMMON_RTC_CONFIG = {"iceServers": get_ice_servers()}
|
118 |
|
119 |
st.header("Input 1")
|
120 |
input1_ctx = webrtc_streamer(
|
pages/7_record.py
CHANGED
@@ -7,6 +7,8 @@ import streamlit as st
|
|
7 |
from aiortc.contrib.media import MediaRecorder
|
8 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
9 |
|
|
|
|
|
10 |
|
11 |
def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame:
|
12 |
img = frame.to_ndarray(format="bgr24")
|
@@ -39,7 +41,7 @@ def app():
|
|
39 |
webrtc_streamer(
|
40 |
key="record",
|
41 |
mode=WebRtcMode.SENDRECV,
|
42 |
-
rtc_configuration={"iceServers":
|
43 |
media_stream_constraints={
|
44 |
"video": True,
|
45 |
"audio": True,
|
|
|
7 |
from aiortc.contrib.media import MediaRecorder
|
8 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
9 |
|
10 |
+
from sample_utils.turn import get_ice_servers
|
11 |
+
|
12 |
|
13 |
def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame:
|
14 |
img = frame.to_ndarray(format="bgr24")
|
|
|
41 |
webrtc_streamer(
|
42 |
key="record",
|
43 |
mode=WebRtcMode.SENDRECV,
|
44 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
45 |
media_stream_constraints={
|
46 |
"video": True,
|
47 |
"audio": True,
|
pages/8_media_files_streaming.py
CHANGED
@@ -10,6 +10,7 @@ from aiortc.contrib.media import MediaPlayer
|
|
10 |
from streamlit_webrtc import WebRtcMode, WebRtcStreamerContext, webrtc_streamer
|
11 |
|
12 |
from sample_utils.download import download_file
|
|
|
13 |
|
14 |
HERE = Path(__file__).parent
|
15 |
ROOT = HERE.parent
|
@@ -112,7 +113,7 @@ def video_frame_callback(frame: av.VideoFrame) -> av.VideoFrame:
|
|
112 |
webrtc_streamer(
|
113 |
key=key,
|
114 |
mode=WebRtcMode.RECVONLY,
|
115 |
-
rtc_configuration={"iceServers":
|
116 |
media_stream_constraints={
|
117 |
"video": media_file_info["type"] == "video",
|
118 |
"audio": media_file_info["type"] == "audio",
|
|
|
10 |
from streamlit_webrtc import WebRtcMode, WebRtcStreamerContext, webrtc_streamer
|
11 |
|
12 |
from sample_utils.download import download_file
|
13 |
+
from sample_utils.turn import get_ice_servers
|
14 |
|
15 |
HERE = Path(__file__).parent
|
16 |
ROOT = HERE.parent
|
|
|
113 |
webrtc_streamer(
|
114 |
key=key,
|
115 |
mode=WebRtcMode.RECVONLY,
|
116 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
117 |
media_stream_constraints={
|
118 |
"video": media_file_info["type"] == "video",
|
119 |
"audio": media_file_info["type"] == "audio",
|
pages/9_sendonly_video.py
CHANGED
@@ -7,13 +7,15 @@ import queue
|
|
7 |
import streamlit as st
|
8 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
9 |
|
|
|
|
|
10 |
logger = logging.getLogger(__name__)
|
11 |
|
12 |
|
13 |
webrtc_ctx = webrtc_streamer(
|
14 |
key="video-sendonly",
|
15 |
mode=WebRtcMode.SENDONLY,
|
16 |
-
rtc_configuration={"iceServers":
|
17 |
media_stream_constraints={"video": True},
|
18 |
)
|
19 |
|
|
|
7 |
import streamlit as st
|
8 |
from streamlit_webrtc import WebRtcMode, webrtc_streamer
|
9 |
|
10 |
+
from sample_utils.turn import get_ice_servers
|
11 |
+
|
12 |
logger = logging.getLogger(__name__)
|
13 |
|
14 |
|
15 |
webrtc_ctx = webrtc_streamer(
|
16 |
key="video-sendonly",
|
17 |
mode=WebRtcMode.SENDONLY,
|
18 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
19 |
media_stream_constraints={"video": True},
|
20 |
)
|
21 |
|
sample_utils/turn.py
CHANGED
@@ -1,17 +1,25 @@
|
|
1 |
import logging
|
2 |
import os
|
3 |
|
4 |
-
from twilio.rest import Client
|
5 |
import streamlit as st
|
|
|
6 |
|
7 |
logger = logging.getLogger(__name__)
|
8 |
|
9 |
|
10 |
@st.cache_data
|
11 |
def get_ice_servers():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
try:
|
13 |
-
account_sid = os.environ[
|
14 |
-
auth_token = os.environ[
|
15 |
except KeyError:
|
16 |
logger.warning(
|
17 |
"Twilio credentials are not set. Fallback to a free STUN server from Google." # noqa: E501
|
|
|
1 |
import logging
|
2 |
import os
|
3 |
|
|
|
4 |
import streamlit as st
|
5 |
+
from twilio.rest import Client
|
6 |
|
7 |
logger = logging.getLogger(__name__)
|
8 |
|
9 |
|
10 |
@st.cache_data
|
11 |
def get_ice_servers():
|
12 |
+
"""Use Twilio's TURN server because Streamlit Community Cloud has changed
|
13 |
+
its infrastructure and WebRTC connection cannot be established without TURN server now. # noqa: E501
|
14 |
+
We considered Open Relay Project (https://www.metered.ca/tools/openrelay/) too,
|
15 |
+
but it is not stable and hardly works as some people reported like https://github.com/aiortc/aiortc/issues/832#issuecomment-1482420656 # noqa: E501
|
16 |
+
See https://github.com/whitphx/streamlit-webrtc/issues/1213
|
17 |
+
"""
|
18 |
+
|
19 |
+
# Ref: https://www.twilio.com/docs/stun-turn/api
|
20 |
try:
|
21 |
+
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
|
22 |
+
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
|
23 |
except KeyError:
|
24 |
logger.warning(
|
25 |
"Twilio credentials are not set. Fallback to a free STUN server from Google." # noqa: E501
|