streamlit-webrtc 0.61.2__py3-none-any.whl → 0.61.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ import copy
2
2
  import json
3
3
  import logging
4
4
  import os
5
+ import threading
5
6
  import warnings
6
7
  import weakref
7
8
  from typing import (
@@ -92,6 +93,7 @@ class WebRtcStreamerContext(Generic[VideoProcessorT, AudioProcessorT]):
92
93
  _worker_ref: "Optional[weakref.ReferenceType[WebRtcWorker[VideoProcessorT, AudioProcessorT]]]" # noqa
93
94
 
94
95
  _component_value_snapshot: Union[ComponentValueSnapshot, None]
96
+ _worker_creation_lock: threading.Lock
95
97
  _frontend_rtc_configuration: Optional[Union[Dict[str, Any], RTCConfiguration]]
96
98
 
97
99
  def __init__(
@@ -102,6 +104,7 @@ class WebRtcStreamerContext(Generic[VideoProcessorT, AudioProcessorT]):
102
104
  self._set_worker(worker)
103
105
  self._set_state(state)
104
106
  self._component_value_snapshot = None
107
+ self._worker_creation_lock = threading.Lock()
105
108
  self._frontend_rtc_configuration = None
106
109
 
107
110
  def _set_worker(
@@ -594,65 +597,66 @@ def webrtc_streamer(
594
597
  on_ended=on_audio_ended,
595
598
  )
596
599
 
597
- if not webrtc_worker and sdp_offer:
598
- LOGGER.debug(
599
- "No worker exists though the offer SDP is set. "
600
- 'Create a new worker (key="%s").',
601
- key,
602
- )
600
+ worker_created_in_this_run = None
601
+ with context._worker_creation_lock: # This point can be reached in parallel so we need to use a lock to make the worker creation process atomic.
602
+ should_create_worker_in_this_run = not context._get_worker() and sdp_offer
603
603
 
604
- aiortc_rtc_configuration = (
605
- compile_rtc_configuration(server_rtc_configuration)
606
- if server_rtc_configuration and isinstance(server_rtc_configuration, dict)
607
- else AiortcRTCConfiguration()
608
- )
609
- if aiortc_rtc_configuration.iceServers is None:
610
- LOGGER.info(
611
- "rtc_configuration.iceServers is not set. Try to set it automatically."
604
+ if should_create_worker_in_this_run:
605
+ LOGGER.debug(
606
+ "No worker exists though the offer SDP is set. "
607
+ 'Create a new worker (key="%s").',
608
+ key,
612
609
  )
613
- ice_servers = get_available_ice_servers()
614
- aiortc_rtc_configuration.iceServers = compile_ice_servers(ice_servers)
615
-
616
- webrtc_worker = WebRtcWorker(
617
- mode=mode,
618
- rtc_configuration=aiortc_rtc_configuration,
619
- player_factory=player_factory,
620
- in_recorder_factory=in_recorder_factory,
621
- out_recorder_factory=out_recorder_factory,
622
- video_frame_callback=video_frame_callback,
623
- audio_frame_callback=audio_frame_callback,
624
- queued_video_frames_callback=queued_video_frames_callback,
625
- queued_audio_frames_callback=queued_audio_frames_callback,
626
- on_video_ended=on_video_ended,
627
- on_audio_ended=on_audio_ended,
628
- video_processor_factory=video_processor_factory,
629
- audio_processor_factory=audio_processor_factory,
630
- async_processing=async_processing,
631
- video_receiver_size=video_receiver_size,
632
- audio_receiver_size=audio_receiver_size,
633
- source_video_track=source_video_track,
634
- source_audio_track=source_audio_track,
635
- sendback_video=sendback_video,
636
- sendback_audio=sendback_audio,
637
- )
638
610
 
639
- # Setting the worker here before calling `webrtc_worker.process_offer()` is important.
640
- # `webrtc_worker.process_offer()` waits for processing the offer in another thread and
641
- # a new script run can be triggered during it.
642
- # so, if the worker is not set here, `context._get_worker()` will return None in the next run
643
- # and it leads to creating a worker in the next run again.
644
- context._set_worker(webrtc_worker)
611
+ aiortc_rtc_configuration = (
612
+ compile_rtc_configuration(server_rtc_configuration)
613
+ if server_rtc_configuration
614
+ and isinstance(server_rtc_configuration, dict)
615
+ else AiortcRTCConfiguration()
616
+ )
617
+ if aiortc_rtc_configuration.iceServers is None:
618
+ LOGGER.info(
619
+ "rtc_configuration.iceServers is not set. Try to set it automatically."
620
+ )
621
+ ice_servers = get_available_ice_servers() # NOTE: This may include a yield point where Streamlit's script runner interrupts the execution and may stop the current run.
622
+ aiortc_rtc_configuration.iceServers = compile_ice_servers(ice_servers)
623
+
624
+ worker_created_in_this_run = WebRtcWorker(
625
+ mode=mode,
626
+ rtc_configuration=aiortc_rtc_configuration,
627
+ player_factory=player_factory,
628
+ in_recorder_factory=in_recorder_factory,
629
+ out_recorder_factory=out_recorder_factory,
630
+ video_frame_callback=video_frame_callback,
631
+ audio_frame_callback=audio_frame_callback,
632
+ queued_video_frames_callback=queued_video_frames_callback,
633
+ queued_audio_frames_callback=queued_audio_frames_callback,
634
+ on_video_ended=on_video_ended,
635
+ on_audio_ended=on_audio_ended,
636
+ video_processor_factory=video_processor_factory,
637
+ audio_processor_factory=audio_processor_factory,
638
+ async_processing=async_processing,
639
+ video_receiver_size=video_receiver_size,
640
+ audio_receiver_size=audio_receiver_size,
641
+ source_video_track=source_video_track,
642
+ source_audio_track=source_audio_track,
643
+ sendback_video=sendback_video,
644
+ sendback_audio=sendback_audio,
645
+ )
645
646
 
646
- webrtc_worker.process_offer(sdp_offer["sdp"], sdp_offer["type"], timeout=None)
647
+ # Set the worker here within the lock.
648
+ context._set_worker(worker_created_in_this_run)
647
649
 
648
- if ice_candidates:
649
- webrtc_worker.set_ice_candidates_from_offerer(ice_candidates)
650
+ webrtc_worker = context._get_worker()
651
+ if webrtc_worker and ice_candidates:
652
+ webrtc_worker.set_ice_candidates_from_offerer(ice_candidates)
653
+
654
+ if worker_created_in_this_run:
655
+ worker_created_in_this_run.process_offer(
656
+ sdp_offer["sdp"], sdp_offer["type"], timeout=None
657
+ )
650
658
 
651
659
  # Rerun to send the SDP answer to frontend
652
660
  rerun()
653
661
 
654
- if webrtc_worker and ice_candidates:
655
- webrtc_worker.set_ice_candidates_from_offerer(ice_candidates)
656
-
657
- context._set_worker(webrtc_worker)
658
662
  return context
@@ -662,7 +662,8 @@ class WebRtcWorker(Generic[VideoProcessorT, AudioProcessorT]):
662
662
  self.on_video_ended = on_ended
663
663
 
664
664
  if not self.video_processor:
665
- raise TypeError("video_processor is None")
665
+ # `update_video_callbacks` can be called before `process_offer` is called that sets up the video processor.
666
+ return
666
667
  if type(self.video_processor).__name__ != CallbackAttachableProcessor.__name__:
667
668
  raise TypeError(
668
669
  f"video_processor has an invalid type: {type(self.video_processor)}"
@@ -686,7 +687,8 @@ class WebRtcWorker(Generic[VideoProcessorT, AudioProcessorT]):
686
687
  self.on_audio_ended = on_ended
687
688
 
688
689
  if not self.audio_processor:
689
- raise TypeError("audio_processor is None")
690
+ # `update_audio_callbacks` can be called before `process_offer` is called that sets up the audio processor.
691
+ return
690
692
  if type(self.audio_processor).__name__ != CallbackAttachableProcessor.__name__:
691
693
  raise TypeError(
692
694
  f"audio_processor has an invalid type: {type(self.audio_processor)}"
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-webrtc
3
- Version: 0.61.2
3
+ Version: 0.61.3
4
4
  Summary: Real-time video and audio processing on Streamlit
5
5
  Project-URL: Repository, https://github.com/whitphx/streamlit-webrtc
6
6
  Author-email: "Yuichiro Tachibana (Tsuchiya)" <t.yic.yt@gmail.com>
7
7
  License-Expression: MIT
8
8
  License-File: LICENSE
9
9
  Requires-Python: !=3.9.7,>=3.9
10
- Requires-Dist: aioice>=0.9.0
10
+ Requires-Dist: aioice>=0.10.0
11
11
  Requires-Dist: aiortc>=1.11.0
12
12
  Requires-Dist: packaging>=20.0
13
13
  Requires-Dist: streamlit>=0.89.0
@@ -1,6 +1,6 @@
1
1
  streamlit_webrtc/__init__.py,sha256=jMWwXoQ9hVyYXPD4Vrps7MyiR9goyC-n7LtkZNFBOxU,2273
2
2
  streamlit_webrtc/_compat.py,sha256=AVRcUGdgWDQcCE7-ufhGr6Hb5P6EHLgejUAA72ArJmg,4384
3
- streamlit_webrtc/component.py,sha256=uNmy3kLxhT6vlIp61uMgAjqeS4PaaPMy9choGIHvENE,26832
3
+ streamlit_webrtc/component.py,sha256=Imoz2xuLRvgjy2Lxi9VVXgCMdvf-nUriTim2AjdFfC0,27155
4
4
  streamlit_webrtc/components_callbacks.py,sha256=tdrj2TlV8qcexFEdjm4PVkz8JwHffo4A8imoXOtjNHA,2401
5
5
  streamlit_webrtc/config.py,sha256=yKFIVjIoX2F62_G2qcDrNYm2Qe_qx1E9E0YqAnAibMo,5544
6
6
  streamlit_webrtc/credentials.py,sha256=3IOk7w1JLQ2Qs6XFP9dxsF81lpjLL2kdRe2ZIhHvaj4,4562
@@ -16,10 +16,10 @@ streamlit_webrtc/server.py,sha256=5o9E2MRIPoS18lfGPJkyhbd23RWyTwblNVVuAA2kKrA,14
16
16
  streamlit_webrtc/session_info.py,sha256=V1EdzD2I8dWANXdC84EKSz8XgPM-zugtkYsb4hJm8Qo,2313
17
17
  streamlit_webrtc/shutdown.py,sha256=PUjMoNZcTRGzZCooCmjWARpeVs5EG_9JXAf1Iay7dBM,2353
18
18
  streamlit_webrtc/source.py,sha256=haPqMZ50Xh8tg7Z1yN8Frfk8v7D3oOuKteaD59asbzs,2263
19
- streamlit_webrtc/webrtc.py,sha256=CC6Z55e2aikhF1r_C6p08xmIYqbYZGFTpsmgBd1lo_A,29732
19
+ streamlit_webrtc/webrtc.py,sha256=WzgydYm3Xhoi5c1QHNLc_GiF_E0aGC5ynzmxeAbtJCw,29900
20
20
  streamlit_webrtc/frontend/dist/index.html,sha256=ZY_Iflaf7wRUHHNpw7JMlSMraE3ewM9T_tZA94NIPRs,527
21
21
  streamlit_webrtc/frontend/dist/assets/index-Cz1nSw2-.js,sha256=j126AA3NGo8BLgQSjjMyQR6QwpDRq_jILP9woihrncI,589799
22
- streamlit_webrtc-0.61.2.dist-info/METADATA,sha256=cKoOJcEhOc6G7jFgywtCTY20omtR-SDS2Ouc5MSPn6s,18287
23
- streamlit_webrtc-0.61.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
- streamlit_webrtc-0.61.2.dist-info/licenses/LICENSE,sha256=pwccNHVA7r4rYofGlMU10aKEU90GLUlQr8uY80PR0NQ,1081
25
- streamlit_webrtc-0.61.2.dist-info/RECORD,,
22
+ streamlit_webrtc-0.61.3.dist-info/METADATA,sha256=nUJ6oMZtfpG5E0l5dQw_E0UfXX3XrQ1gTxkYEwalntA,18288
23
+ streamlit_webrtc-0.61.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
+ streamlit_webrtc-0.61.3.dist-info/licenses/LICENSE,sha256=pwccNHVA7r4rYofGlMU10aKEU90GLUlQr8uY80PR0NQ,1081
25
+ streamlit_webrtc-0.61.3.dist-info/RECORD,,