videosdk 0.0.1__tar.gz
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.
- videosdk-0.0.1/PKG-INFO +58 -0
- videosdk-0.0.1/README.md +28 -0
- videosdk-0.0.1/pyproject.toml +40 -0
- videosdk-0.0.1/setup.cfg +4 -0
- videosdk-0.0.1/setup.py +15 -0
- videosdk-0.0.1/videosdk/__init__.py +10 -0
- videosdk-0.0.1/videosdk/_events.py +101 -0
- videosdk-0.0.1/videosdk/custom_audio_track.py +50 -0
- videosdk-0.0.1/videosdk/custom_video_track.py +51 -0
- videosdk-0.0.1/videosdk/event_handler.py +256 -0
- videosdk-0.0.1/videosdk/exceptions.py +39 -0
- videosdk-0.0.1/videosdk/lib/__init__.py +1 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/__init__.py +2 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/__version__.py +3 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/consumer.py +206 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/data_consumer.py +170 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/data_producer.py +191 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/device.py +220 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/emitter.py +18 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/errors.py +11 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/__init__.py +0 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/aiortc_handler.py +564 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/handler_interface.py +121 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/sdp/__init__.py +0 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/sdp/common_utils.py +145 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/sdp/media_section.py +432 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/sdp/remote_sdp.py +275 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/handlers/sdp/unified_plan_utils.py +128 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/models/__init__.py +0 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/models/handler_interface.py +78 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/models/transport.py +85 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/ortc.py +378 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/producer.py +309 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/rtp_parameters.py +219 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/scalability_modes.py +21 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/sctp_parameters.py +50 -0
- videosdk-0.0.1/videosdk/lib/pymediasoup/transport.py +504 -0
- videosdk-0.0.1/videosdk/meeting.py +196 -0
- videosdk-0.0.1/videosdk/participant.py +198 -0
- videosdk-0.0.1/videosdk/room_client.py +1035 -0
- videosdk-0.0.1/videosdk/stream.py +9 -0
- videosdk-0.0.1/videosdk/utils.py +90 -0
- videosdk-0.0.1/videosdk/videosdk.py +137 -0
- videosdk-0.0.1/videosdk.egg-info/PKG-INFO +58 -0
- videosdk-0.0.1/videosdk.egg-info/SOURCES.txt +46 -0
- videosdk-0.0.1/videosdk.egg-info/dependency_links.txt +1 -0
- videosdk-0.0.1/videosdk.egg-info/requires.txt +9 -0
- videosdk-0.0.1/videosdk.egg-info/top_level.txt +1 -0
videosdk-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: videosdk
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: VideoSDK Python SDK
|
|
5
|
+
Author: videosdk
|
|
6
|
+
Author-email: sdk@videosdk.live
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Home, https://docs.videosdk.live
|
|
9
|
+
Project-URL: Documentation, https://docs.videosdk.live
|
|
10
|
+
Project-URL: Source, https://docs.videosdk.live
|
|
11
|
+
Project-URL: Website, https://videosdk.live
|
|
12
|
+
Keywords: ml,webrtc,audio,video,ai,videosdk
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Communications :: Conferencing
|
|
16
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
17
|
+
Classifier: Topic :: Multimedia :: Video
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: pydantic<1.11.0,>=1.10.15
|
|
22
|
+
Requires-Dist: vsaiortc>=0.0.1
|
|
23
|
+
Requires-Dist: h264-profile-level-id<1.1.0,>=1.0.0
|
|
24
|
+
Requires-Dist: sdp-transform<1.2.0,>=1.1.0
|
|
25
|
+
Requires-Dist: pyee<11.2.0,>=11.1.0
|
|
26
|
+
Requires-Dist: av<11.1.0,>=11.0.0
|
|
27
|
+
Requires-Dist: websockets<12.1.0,>=12.0.0
|
|
28
|
+
Requires-Dist: requests<2.32.0,>=2.3.1
|
|
29
|
+
Requires-Dist: pycryptodome==3.20.0
|
|
30
|
+
|
|
31
|
+
# VideoSDK Python SDK
|
|
32
|
+
|
|
33
|
+
## Overview
|
|
34
|
+
|
|
35
|
+
The VideoSDK Python SDK provides a convenient way to interact with the VideoSDK API. It allows you to integrate video functionalities, including video calling, recording, and streaming, into your Python applications easily.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Video Calling**: Start, join, and manage video calls.
|
|
40
|
+
- **Recording**: Record video calls.
|
|
41
|
+
- **Live Streaming**: Stream your video calls to platforms like YouTube, Facebook, etc.
|
|
42
|
+
- **Chat**: Send and receive messages during a video call.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
To install the SDK, use pip:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install videosdk
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Documentation
|
|
53
|
+
|
|
54
|
+
For detailed documentation, visit the [VideoSDK Documentation](https://docs.videosdk.live).
|
|
55
|
+
|
|
56
|
+
## Support
|
|
57
|
+
|
|
58
|
+
If you need help or have any questions, please feel free to reach out to our support team at [support@videosdk.live](mailto:support@videosdk.live) or join our community forum.
|
videosdk-0.0.1/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# VideoSDK Python SDK
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The VideoSDK Python SDK provides a convenient way to interact with the VideoSDK API. It allows you to integrate video functionalities, including video calling, recording, and streaming, into your Python applications easily.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Video Calling**: Start, join, and manage video calls.
|
|
10
|
+
- **Recording**: Record video calls.
|
|
11
|
+
- **Live Streaming**: Stream your video calls to platforms like YouTube, Facebook, etc.
|
|
12
|
+
- **Chat**: Send and receive messages during a video call.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
To install the SDK, use pip:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install videosdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Documentation
|
|
23
|
+
|
|
24
|
+
For detailed documentation, visit the [VideoSDK Documentation](https://docs.videosdk.live).
|
|
25
|
+
|
|
26
|
+
## Support
|
|
27
|
+
|
|
28
|
+
If you need help or have any questions, please feel free to reach out to our support team at [support@videosdk.live](mailto:support@videosdk.live) or join our community forum.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "videosdk"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "VideoSDK Python SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
keywords = ["ml", "webrtc", "audio", "video", "ai", "videosdk"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Topic :: Communications :: Conferencing",
|
|
17
|
+
"Topic :: Multimedia :: Sound/Audio",
|
|
18
|
+
"Topic :: Multimedia :: Video",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence"
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"pydantic >= 1.10.15, < 1.11.0",
|
|
23
|
+
"vsaiortc >= 0.0.1",
|
|
24
|
+
"h264-profile-level-id >= 1.0.0, < 1.1.0",
|
|
25
|
+
"sdp-transform >=1.1.0, < 1.2.0",
|
|
26
|
+
"pyee >= 11.1.0, < 11.2.0",
|
|
27
|
+
"av >= 11.0.0, < 11.1.0",
|
|
28
|
+
"websockets >= 12.0.0, < 12.1.0",
|
|
29
|
+
"requests >= 2.3.1, < 2.32.0",
|
|
30
|
+
"pycryptodome==3.20.0"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Home = "https://docs.videosdk.live"
|
|
35
|
+
Documentation = "https://docs.videosdk.live"
|
|
36
|
+
Source = "https://docs.videosdk.live"
|
|
37
|
+
Website = "https://videosdk.live"
|
|
38
|
+
|
|
39
|
+
[tool.coverage.run]
|
|
40
|
+
source = ["videosdk"]
|
videosdk-0.0.1/setup.cfg
ADDED
videosdk-0.0.1/setup.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import setuptools
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setuptools.setup(
|
|
7
|
+
name="videosdk",
|
|
8
|
+
version="0.0.1",
|
|
9
|
+
long_description=long_description,
|
|
10
|
+
long_description_content_type="text/markdown",
|
|
11
|
+
author='videosdk',
|
|
12
|
+
author_email='sdk@videosdk.live',
|
|
13
|
+
license='MIT',
|
|
14
|
+
packages=setuptools.find_packages(exclude=["example"]),
|
|
15
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .exceptions import SDKError, InternalServerError, InvalidMeetingConfigError, MeetingError, MeetingInitializationError
|
|
2
|
+
from .event_handler import MeetingEventHandler, ParticipantEventHandler
|
|
3
|
+
from .participant import Participant
|
|
4
|
+
from .videosdk import MeetingConfig, VideoSDK
|
|
5
|
+
from .stream import Stream
|
|
6
|
+
from .meeting import Meeting
|
|
7
|
+
from .custom_audio_track import CustomAudioTrack
|
|
8
|
+
from .custom_video_track import CustomVideoTrack
|
|
9
|
+
|
|
10
|
+
__version__ = "0.0.1"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
class Events(Enum):
|
|
4
|
+
ADD_PEER = "ADD_PEER"
|
|
5
|
+
REMOVE_PEER = "REMOVE_PEER"
|
|
6
|
+
ADD_PRODUCER = "ADD_PRODUCER"
|
|
7
|
+
UPDATE_PRODUCER = "UPDATE_PRODUCER"
|
|
8
|
+
REMOVE_PRODUCER = "REMOVE_PRODUCER"
|
|
9
|
+
ADD_CONSUMER = "ADD_CONSUMER"
|
|
10
|
+
REMOVE_CONSUMER = "REMOVE_CONSUMER"
|
|
11
|
+
PARTICIPANT_MEDIA_STATE_CHANGED = "PARTICIPANT_MEDIA_STATE_CHANGED"
|
|
12
|
+
CHAT_MESSAGE = "CHAT_MESSAGE"
|
|
13
|
+
SET_ROOM_ACTIVE_SPEAKER = "SET_ROOM_ACTIVE_SPEAKER"
|
|
14
|
+
ENTRY_REQUESTED = "ENTRY_REQUESTED"
|
|
15
|
+
ENTRY_RESPONDED = "ENTRY_RESPONDED"
|
|
16
|
+
MEETING_JOINED = "MEETING_JOINED"
|
|
17
|
+
MEETING_LEFT = "MEETING_LEFT"
|
|
18
|
+
RECORDING_STATE_CHANGED = "RECORDING_STATE_CHANGED"
|
|
19
|
+
RECORDING_STARTED = "RECORDING_STARTED"
|
|
20
|
+
RECORDING_STOPPED = "RECORDING_STOPPED"
|
|
21
|
+
LIVESTREAM_STATE_CHANGED = "LIVESTREAM_STATE_CHANGED"
|
|
22
|
+
LIVESTREAM_STARTED = "LIVESTREAM_STARTED"
|
|
23
|
+
LIVESTREAM_STOPPED = "LIVESTREAM_STOPPED"
|
|
24
|
+
HLS_STATE_CHANGED = "HLS_STATE_CHANGED"
|
|
25
|
+
HLS_STARTED = "HLS_STARTED"
|
|
26
|
+
HLS_STOPPED = "HLS_STOPPED"
|
|
27
|
+
TRANSCRIPTION_STATE_CHANGED = "TRANSCRIPTION_STATE_CHANGED"
|
|
28
|
+
TRANSCRIPTION_TEXT = "TRANSCRIPTION_TEXT"
|
|
29
|
+
WHITEBOARD_STARTED = "WHITEBOARD_STARTED"
|
|
30
|
+
WHITEBOARD_STOPPED = "WHITEBOARD_STOPPED"
|
|
31
|
+
VIDEO_STATE_CHANGED = "VIDEO_STATE_CHANGED"
|
|
32
|
+
VIDEO_SEEKED = "VIDEO_SEEKED"
|
|
33
|
+
PIN_STATE_CHANGED = "PIN_STATE_CHANGED"
|
|
34
|
+
MIC_REQUESTED = "MIC_REQUESTED"
|
|
35
|
+
WEBCAM_REQUESTED = "WEBCAM_REQUESTED"
|
|
36
|
+
CONNECTION_OPEN = "CONNECTION_OPEN"
|
|
37
|
+
CONNECTION_CLOSE = "CONNECTION_CLOSE"
|
|
38
|
+
CONNECTION_PARTICIPANT_JOIN = "CONNECTION_PARTICIPANT_JOIN"
|
|
39
|
+
SWITCH_ROOM = "SWITCH_ROOM"
|
|
40
|
+
CONNECTION_CHAT_MESSAGE = "CONNECTION_CHAT_MESSAGE"
|
|
41
|
+
CONNECTION_PARTICIPANT_LEFT = "CONNECTION_PARTICIPANT_LEFT"
|
|
42
|
+
PUBSUB_MESSAGE = "PUBSUB_MESSAGE"
|
|
43
|
+
PEER_MODE_CHANGED = "PEER_MODE_CHANGED"
|
|
44
|
+
MEETING_STATE_CHANGED = "MEETING_STATE_CHANGED"
|
|
45
|
+
VIDEO_QUALITY_CHANGED = "VIDEO_QUALITY_CHANGED"
|
|
46
|
+
ADD_CHARACTER = "ADD_CHARACTER"
|
|
47
|
+
INIT_CHARACTER = "INIT_CHARACTER"
|
|
48
|
+
REMOVE_CHARACTER = "REMOVE_CHARACTER"
|
|
49
|
+
CHARACTER_STATE_CHANGED = "CHARACTER_STATE_CHANGED"
|
|
50
|
+
CHARACTER_TEXT = "CHARACTER_TEXT"
|
|
51
|
+
ERROR = "ERROR"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class VideoSDKEvents(Enum):
|
|
55
|
+
EV_ERROR = "error"
|
|
56
|
+
EV_MEETING_JOINED = "meeting-joined"
|
|
57
|
+
EV_MEETING_LEFT = "meeting-left"
|
|
58
|
+
EV_PARTICIPANT_MODE_CHANGED = "participant-mode-changed"
|
|
59
|
+
EV_PARTICIPANT_JOINED = "participant-joined"
|
|
60
|
+
EV_PARTICIPANT_LEFT = "participant-left"
|
|
61
|
+
EV_SPEAKER_CHANGED = "speaker-changed"
|
|
62
|
+
EV_PRESENTER_CHANGED = "presenter-changed"
|
|
63
|
+
EV_MAIN_PARTICIPANT_CHANGED = "main-participant-changed"
|
|
64
|
+
EV_CHAT_MESSAGE = "chat-message"
|
|
65
|
+
EV_ENTRY_REQUESTED = "entry-requested"
|
|
66
|
+
EV_ENTRY_RESPONDED = "entry-responded"
|
|
67
|
+
EV_RECORDING_STATE_CHANGED = "recording-state-changed"
|
|
68
|
+
EV_RECORDING_STARTED = "recording-started"
|
|
69
|
+
EV_RECORDING_STOPPED = "recording-stopped"
|
|
70
|
+
EV_LIVESTREAM_STATE_CHANGED = "livestream-state-changed"
|
|
71
|
+
EV_LIVESTREAM_STARTED = "livestream-started"
|
|
72
|
+
EV_LIVESTREAM_STOPPED = "livestream-stopped"
|
|
73
|
+
EV_HLS_STATE_CHANGED = "hls-state-changed"
|
|
74
|
+
EV_HLS_STARTED = "hls-started"
|
|
75
|
+
EV_HLS_STOPPED = "hls-stopped"
|
|
76
|
+
EV_WHITEBOARD_STARTED = "whiteboard-started"
|
|
77
|
+
EV_WHITEBOARD_STOPPED = "whiteboard-stopped"
|
|
78
|
+
EV_VIDEO_STATE_CHANGED = "video-state-changed"
|
|
79
|
+
EV_VIDEO_SEEKED = "video-seeked"
|
|
80
|
+
EV_MIC_REQUESTED = "mic-requested"
|
|
81
|
+
EV_WEBCAM_REQUESTED = "webcam-requested"
|
|
82
|
+
|
|
83
|
+
EV_PIN_STATE_CHANGED = "pin-state-changed"
|
|
84
|
+
|
|
85
|
+
EV_CONNECTION_OPEN = "connection-open"
|
|
86
|
+
EV_CONNECTION_CLOSE = "connection-close"
|
|
87
|
+
EV_SWITCH_MEETING = "switch-meeting"
|
|
88
|
+
|
|
89
|
+
EV_MEETING_STATE_CHANGE = "meeting-state-changed"
|
|
90
|
+
|
|
91
|
+
EV_TRANSCRIPTION_STATE_CHANGED = "transcription-state-changed"
|
|
92
|
+
EV_TRANSCRIPTION_TEXT = "transcription-text"
|
|
93
|
+
|
|
94
|
+
EV_CHARACTER_JOINED = "character-joined"
|
|
95
|
+
EV_CHARACTER_LEFT = "character-left"
|
|
96
|
+
|
|
97
|
+
# Participant
|
|
98
|
+
EV_STREAM_ENABLED = "stream-enabled"
|
|
99
|
+
EV_STREAM_DISABLED = "stream-disabled"
|
|
100
|
+
EV_MEDIA_STATUS_CHANGED = "media-status-changed"
|
|
101
|
+
EV_VIDEO_QUALITY_CHANGED = "video-quality-changed"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import fractions
|
|
3
|
+
import time
|
|
4
|
+
from vsaiortc.mediastreams import MediaStreamError, MediaStreamTrack
|
|
5
|
+
from av import AudioFrame
|
|
6
|
+
from av.frame import Frame
|
|
7
|
+
from av.packet import Packet
|
|
8
|
+
|
|
9
|
+
AUDIO_PTIME = 0.020
|
|
10
|
+
|
|
11
|
+
class CustomAudioTrack(MediaStreamTrack):
|
|
12
|
+
"""
|
|
13
|
+
A dummy audio track which reads silence.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
kind = "audio"
|
|
17
|
+
|
|
18
|
+
_start: float
|
|
19
|
+
_timestamp: int
|
|
20
|
+
|
|
21
|
+
async def recv(self) -> Frame:
|
|
22
|
+
"""
|
|
23
|
+
Receive the next :class:`~av.audio.frame.AudioFrame`.
|
|
24
|
+
|
|
25
|
+
The base implementation just reads silence, subclass
|
|
26
|
+
:class:`AudioStreamTrack` to provide a useful implementation.
|
|
27
|
+
"""
|
|
28
|
+
if self.readyState != "live":
|
|
29
|
+
raise MediaStreamError
|
|
30
|
+
|
|
31
|
+
sample_rate = 8000
|
|
32
|
+
samples = int(AUDIO_PTIME * sample_rate)
|
|
33
|
+
|
|
34
|
+
if hasattr(self, "_timestamp"):
|
|
35
|
+
self._timestamp += samples
|
|
36
|
+
wait = self._start + (self._timestamp / sample_rate) - time.time()
|
|
37
|
+
await asyncio.sleep(wait)
|
|
38
|
+
else:
|
|
39
|
+
self._start = time.time()
|
|
40
|
+
self._timestamp = 0
|
|
41
|
+
|
|
42
|
+
frame = AudioFrame(format="s16", layout="mono", samples=samples)
|
|
43
|
+
for p in frame.planes:
|
|
44
|
+
p.update(bytes(p.buffer_size))
|
|
45
|
+
frame.pts = self._timestamp
|
|
46
|
+
frame.sample_rate = sample_rate
|
|
47
|
+
frame.time_base = fractions.Fraction(1, sample_rate)
|
|
48
|
+
|
|
49
|
+
return frame
|
|
50
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import fractions
|
|
3
|
+
import time
|
|
4
|
+
from typing import Tuple
|
|
5
|
+
from vsaiortc.mediastreams import MediaStreamError, MediaStreamTrack
|
|
6
|
+
from av import VideoFrame
|
|
7
|
+
from av.frame import Frame
|
|
8
|
+
|
|
9
|
+
AUDIO_PTIME = 0.020 # default 20ms audio packetization
|
|
10
|
+
VIDEO_CLOCK_RATE = 90000
|
|
11
|
+
VIDEO_PTIME = 1 / 30 # 30fps
|
|
12
|
+
VIDEO_TIME_BASE = fractions.Fraction(1, VIDEO_CLOCK_RATE)
|
|
13
|
+
|
|
14
|
+
class CustomVideoTrack(MediaStreamTrack):
|
|
15
|
+
"""
|
|
16
|
+
A dummy video track which reads green frames.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
kind = "video"
|
|
20
|
+
|
|
21
|
+
_start: float
|
|
22
|
+
_timestamp: int
|
|
23
|
+
|
|
24
|
+
async def next_timestamp(self) -> Tuple[int, fractions.Fraction]:
|
|
25
|
+
if self.readyState != "live":
|
|
26
|
+
raise MediaStreamError
|
|
27
|
+
|
|
28
|
+
if hasattr(self, "_timestamp"):
|
|
29
|
+
self._timestamp += int(VIDEO_PTIME * VIDEO_CLOCK_RATE)
|
|
30
|
+
wait = self._start + (self._timestamp / VIDEO_CLOCK_RATE) - time.time()
|
|
31
|
+
await asyncio.sleep(wait)
|
|
32
|
+
else:
|
|
33
|
+
self._start = time.time()
|
|
34
|
+
self._timestamp = 0
|
|
35
|
+
return self._timestamp, VIDEO_TIME_BASE
|
|
36
|
+
|
|
37
|
+
async def recv(self) -> Frame:
|
|
38
|
+
"""
|
|
39
|
+
Receive the next :class:`~av.video.frame.VideoFrame`.
|
|
40
|
+
|
|
41
|
+
The base implementation just reads a 640x480 green frame at 30fps,
|
|
42
|
+
subclass :class:`VideoStreamTrack` to provide a useful implementation.
|
|
43
|
+
"""
|
|
44
|
+
pts, time_base = await self.next_timestamp()
|
|
45
|
+
|
|
46
|
+
frame = VideoFrame(width=640, height=480)
|
|
47
|
+
for p in frame.planes:
|
|
48
|
+
p.update(bytes(p.buffer_size))
|
|
49
|
+
frame.pts = pts
|
|
50
|
+
frame.time_base = time_base
|
|
51
|
+
return frame
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import final
|
|
3
|
+
|
|
4
|
+
class BaseEvent:
|
|
5
|
+
"""
|
|
6
|
+
VideoSDK BaseEvent Class
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
@final
|
|
10
|
+
def handle_event(self, action, data):
|
|
11
|
+
method_name = {
|
|
12
|
+
# Base Event Handlers
|
|
13
|
+
"error": "on_error",
|
|
14
|
+
|
|
15
|
+
# Meeting Event Handlers
|
|
16
|
+
"meeting-joined": "on_meeting_joined",
|
|
17
|
+
"meeting-left": "on_meeting_left",
|
|
18
|
+
"participant-mode-changed": "on_participant_mode_changed",
|
|
19
|
+
"participant-joined": "on_participant_joined",
|
|
20
|
+
"participant-left": "on_participant_left",
|
|
21
|
+
"speaker-changed": "on_speaker_changed",
|
|
22
|
+
"presenter-changed": "on_presenter_changed",
|
|
23
|
+
"main-participant-changed": "on_main_participant_changed",
|
|
24
|
+
"chat-message": "on_chat_message",
|
|
25
|
+
"entry-requested": "on_entry_requested",
|
|
26
|
+
"entry-responded": "on_entry_responded",
|
|
27
|
+
"recording-state-changed": "on_recording_state_changed",
|
|
28
|
+
"recording-started": "on_recording_started",
|
|
29
|
+
"recording-stopped": "on_recording_stopped",
|
|
30
|
+
"livestream-state-changed": "on_livestream_state_changed",
|
|
31
|
+
"livestream-started": "on_livestream_started",
|
|
32
|
+
"livestream-stopped": "on_livestream_stopped",
|
|
33
|
+
"hls-state-changed": "on_hls_state_changed",
|
|
34
|
+
"hls-started": "on_hls_started",
|
|
35
|
+
"hls-stopped": "on_hls_stopped",
|
|
36
|
+
"whiteboard-started": "on_whiteboard_started",
|
|
37
|
+
"whiteboard-stopped": "on_whiteboard_stopped",
|
|
38
|
+
"video-state-changed": "on_video_state_changed",
|
|
39
|
+
"video-seeked": "on_video_seeked",
|
|
40
|
+
"mic-requested": "on_mic_requested",
|
|
41
|
+
"webcam-requested": "on_webcam_requested",
|
|
42
|
+
"pin-state-changed": "on_pin_state_changed",
|
|
43
|
+
"connection-open": "on_connection_open",
|
|
44
|
+
"connection-close": "on_connection_close",
|
|
45
|
+
"switch-meeting": "on_switch_meeting",
|
|
46
|
+
"meeting-state-changed": "on_meeting_state_change",
|
|
47
|
+
"transcription-state-changed": "on_transcription_state_changed",
|
|
48
|
+
"transcription-text": "on_transcription_text",
|
|
49
|
+
|
|
50
|
+
# Participant Event Handlers
|
|
51
|
+
"stream-enabled": "on_stream_enabled",
|
|
52
|
+
"stream-disabled": "on_stream_disabled",
|
|
53
|
+
"media-status-changed": "on_media_status_changed",
|
|
54
|
+
"video-quality-changed": "on_video_quality_changed"
|
|
55
|
+
}.get(action, None)
|
|
56
|
+
|
|
57
|
+
if method_name is None:
|
|
58
|
+
logging.debug(f"unimplemented event handler {action}")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
method = getattr(self, method_name, None)
|
|
62
|
+
if method:
|
|
63
|
+
method(data)
|
|
64
|
+
else:
|
|
65
|
+
logging.debug(f"No method found for {method_name}")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MeetingEventHandler(BaseEvent):
|
|
69
|
+
def on_error(self, data):
|
|
70
|
+
"""
|
|
71
|
+
Handle error event.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def on_meeting_joined(self, data):
|
|
75
|
+
"""
|
|
76
|
+
Handle meeting joined event.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def on_meeting_left(self, data):
|
|
80
|
+
"""
|
|
81
|
+
Handle meeting left event.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def on_participant_mode_changed(self, data):
|
|
85
|
+
"""
|
|
86
|
+
Handle participant mode changed event.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def on_participant_joined(self, data):
|
|
90
|
+
"""
|
|
91
|
+
Handle participant joined event.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def on_participant_left(self, data):
|
|
95
|
+
"""
|
|
96
|
+
Handle participant left event.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def on_speaker_changed(self, data):
|
|
100
|
+
"""
|
|
101
|
+
Handle speaker changed event.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def on_presenter_changed(self, data):
|
|
105
|
+
"""
|
|
106
|
+
Handle presenter changed event.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def on_main_participant_changed(self, data):
|
|
110
|
+
"""
|
|
111
|
+
Handle main participant changed event.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def on_chat_message(self, data):
|
|
115
|
+
"""
|
|
116
|
+
Handle chat message event.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def on_entry_requested(self, data):
|
|
120
|
+
"""
|
|
121
|
+
Handle entry requested event.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
def on_entry_responded(self, data):
|
|
125
|
+
"""
|
|
126
|
+
Handle entry responded event.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def on_recording_state_changed(self, data):
|
|
130
|
+
"""
|
|
131
|
+
Handle recording state changed event.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
def on_recording_started(self, data):
|
|
135
|
+
"""
|
|
136
|
+
Handle recording started event.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def on_recording_stopped(self, data):
|
|
140
|
+
"""
|
|
141
|
+
Handle recording stopped event.
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
def on_livestream_state_changed(self, data):
|
|
145
|
+
"""
|
|
146
|
+
Handle livestream state changed event.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def on_livestream_started(self, data):
|
|
150
|
+
"""
|
|
151
|
+
Handle livestream started event.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
def on_livestream_stopped(self, data):
|
|
155
|
+
"""
|
|
156
|
+
Handle livestream stopped event.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def on_hls_state_changed(self, data):
|
|
160
|
+
"""
|
|
161
|
+
Handle HLS state changed event.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
def on_hls_started(self, data):
|
|
165
|
+
"""
|
|
166
|
+
Handle HLS started event.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
def on_hls_stopped(self, data):
|
|
170
|
+
"""
|
|
171
|
+
Handle HLS stopped event.
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
def on_whiteboard_started(self, data):
|
|
175
|
+
"""
|
|
176
|
+
Handle whiteboard started event.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
def on_whiteboard_stopped(self, data):
|
|
180
|
+
"""
|
|
181
|
+
Handle whiteboard stopped event.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
def on_video_state_changed(self, data):
|
|
185
|
+
"""
|
|
186
|
+
Handle video state changed event.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
def on_video_seeked(self, data):
|
|
190
|
+
"""
|
|
191
|
+
Handle video seeked event.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def on_mic_requested(self, data):
|
|
195
|
+
"""
|
|
196
|
+
Handle microphone requested event.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
def on_webcam_requested(self, data):
|
|
200
|
+
"""
|
|
201
|
+
Handle webcam requested event.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
def on_pin_state_changed(self, data):
|
|
205
|
+
"""
|
|
206
|
+
Handle pin state changed event.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def on_connection_open(self, data):
|
|
210
|
+
"""
|
|
211
|
+
Handle connection open event.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
def on_connection_close(self, data):
|
|
215
|
+
"""
|
|
216
|
+
Handle connection close event.
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
def on_switch_meeting(self, data):
|
|
220
|
+
"""
|
|
221
|
+
Handle switch meeting event.
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
def on_meeting_state_change(self, data):
|
|
225
|
+
"""
|
|
226
|
+
Handle meeting state change event.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
def on_transcription_state_changed(self, data):
|
|
230
|
+
"""
|
|
231
|
+
Handle transcription state changed event.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
def on_transcription_text(self, data):
|
|
235
|
+
"""
|
|
236
|
+
Handle transcription text event.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class ParticipantEventHandler(BaseEvent):
|
|
241
|
+
def on_stream_enabled(self, data)->None:
|
|
242
|
+
"""
|
|
243
|
+
Handle Participant stream enabled event.
|
|
244
|
+
"""
|
|
245
|
+
def on_stream_disabled(self, data)->None:
|
|
246
|
+
"""
|
|
247
|
+
Handle Participant stream enabled event.
|
|
248
|
+
"""
|
|
249
|
+
def on_media_status_changed(self, data)->None:
|
|
250
|
+
"""
|
|
251
|
+
Handle Participant stream enabled event.
|
|
252
|
+
"""
|
|
253
|
+
def on_video_quality_changed(self, data)->None:
|
|
254
|
+
"""
|
|
255
|
+
Handle Participant stream enabled event.
|
|
256
|
+
"""
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class SDKError(Exception):
|
|
2
|
+
"""Base class for all SDK exceptions."""
|
|
3
|
+
pass
|
|
4
|
+
|
|
5
|
+
class InternalServerError(SDKError):
|
|
6
|
+
"""Raised when there is an unhandled error error."""
|
|
7
|
+
def __init__(self, message="Internal Server Error"):
|
|
8
|
+
self.message = message
|
|
9
|
+
super().__init__(self.message)
|
|
10
|
+
|
|
11
|
+
class MeetingInitializationError(SDKError):
|
|
12
|
+
"""Raised when there is an error in meeting initialization."""
|
|
13
|
+
def __init__(self, message="Failed to initialize meeting"):
|
|
14
|
+
self.message = message
|
|
15
|
+
super().__init__(self.message)
|
|
16
|
+
|
|
17
|
+
class InvalidMeetingConfigError(SDKError):
|
|
18
|
+
"""Raised when the meeting configuration is invalid."""
|
|
19
|
+
def __init__(self, message="Invalid meeting configuration"):
|
|
20
|
+
self.message = message
|
|
21
|
+
super().__init__(self.message)
|
|
22
|
+
|
|
23
|
+
class ValidationError(SDKError):
|
|
24
|
+
"""Raised when the Validation Failed."""
|
|
25
|
+
def __init__(self, message="Validation failed"):
|
|
26
|
+
self.message = message
|
|
27
|
+
super().__init__(self.message)
|
|
28
|
+
|
|
29
|
+
class RTCError(SDKError):
|
|
30
|
+
"""Raised when there is RTC error or server side error."""
|
|
31
|
+
def __init__(self, message="Error in RTC"):
|
|
32
|
+
self.message = message
|
|
33
|
+
super().__init__(self.message)
|
|
34
|
+
|
|
35
|
+
class MeetingError:
|
|
36
|
+
"""class of meeting error."""
|
|
37
|
+
code: int
|
|
38
|
+
type: str
|
|
39
|
+
message: str
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .pymediasoup import *
|