Fishjam Python Server SDK

Ad Ad Ad

Fishjam Python Server SDK

Python server SDK for the Fishjam.

Read the docs here

Installation

pip install fishjam-server-sdk

Usage

The SDK exports two main classes for interacting with Fishjam server: FishjamClient and FishjamNotifier.

FishjamClient wraps http REST api calls, while FishjamNotifier is responsible for receiving real-time updates from the server.

FishjamClient

Create a FishjamClient instance, providing the fishjam server address and api token

from fishjam import FishjamClient

fishjam_client = FishjamClient(fishjam_id="<fishjam_id>", management_token="<management_token>")

You can use it to interact with Fishjam to manage rooms and peers

# Create a room
options = RoomOptions(video_codec="h264", webhook_url="http://localhost:5000/webhook")
room = fishjam_client.create_room(options=options)

# Room(components=[], config=RoomConfig(max_peers=None, video_codec=<RoomConfigVideoCodec.H264: 'h264'>, webhook_url='http://localhost:5000/webhook'), id='1d905478-ccfc-44d6-a6e7-8ccb1b38d955', peers=[])

# Add peer to the room
peer, token = fishjam_client.create_peer(room.id)

# Peer(id='b1232c7e-c969-4450-acdf-ea24f3cdd7f6', status=<PeerStatus.DISCONNECTED: 'disconnected'>, type='webrtc'), 'M8TUGhj-L11KpyG-2zBPIo'

All methods in FishjamClient may raise one of the exceptions deriving from fishjam.errors.HTTPError. They are defined in fishjam.errors.

FishjamNotifier

FishjamNotifier allows for receiving real-time updates from the Fishjam Server.

You can read more about notifications in the Fishjam Docs.

Create FishjamNotifier instance

from fishjam import FishjamNotifier

fishjam_notifier = FishjamNotifier(fishjam_id='<fishjam_id>', management_token='<management_token>')

Then define a handler for incoming messages

@notifier.on_server_notification
def handle_notification(server_notification):
    print(f'Received a notification: {server_notification}')

After that you can start the notifier

async def test_notifier():
    notifier_task = asyncio.create_task(fishjam_notifier.connect())

    # Wait for notifier to be ready to receive messages
    await fishjam_notifier.wait_ready()

    # Create a room to trigger a server notification
    fishjam_client = FishjamClient()
    fishjam_client.create_room()

    await notifier_task

asyncio.run(test_notifier())

# Received a notification: ServerMessageRoomCreated(room_id='69a3fd1a-6a4d-47bc-ae54-0c72b0d05e29')

License

Licensed under the Apache License, Version 2.0

Fishjam is created by Software Mansion

Since 2012 Software Mansion is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues. We can help you build your next dream product – Hire us.

Software Mansion

 1""".. include:: ../README.md"""
 2
 3# pylint: disable=locally-disabled, no-name-in-module, import-error
 4
 5# Exceptions and Server Messages
 6
 7# API
 8# pylint: disable=locally-disabled, no-name-in-module, import-error
 9
10# Exceptions and Server Messages
11from fishjam import agent, errors, events, integrations, peer, room, version
12from fishjam._openapi_client.models import PeerMetadata
13
14# API
15from fishjam._webhook_notifier import decode_server_notifications, receive_binary
16from fishjam._ws_notifier import FishjamNotifier
17from fishjam.api._fishjam_client import (
18    AgentOptions,
19    AgentOutputOptions,
20    FishjamClient,
21    MoqAccess,
22    Peer,
23    PeerOptions,
24    PeerOptionsVapi,
25    Room,
26    RoomOptions,
27)
28from fishjam.errors import InvalidFishjamCredentialsError, MissingFishjamIdError
29
30__version__ = version.__version__
31
32__all__ = [
33    "FishjamClient",
34    "FishjamNotifier",
35    "decode_server_notifications",
36    "receive_binary",
37    "PeerMetadata",
38    "PeerOptions",
39    "PeerOptionsVapi",
40    "RoomOptions",
41    "AgentOptions",
42    "AgentOutputOptions",
43    "Room",
44    "Peer",
45    "MoqAccess",
46    "MissingFishjamIdError",
47    "InvalidFishjamCredentialsError",
48    "events",
49    "errors",
50    "room",
51    "peer",
52    "agent",
53    "integrations",
54]
55
56
57__docformat__ = "restructuredtext"
class FishjamClient(fishjam.api._client.Client):
160class FishjamClient(Client):
161    """Allows for managing rooms."""
162
163    def __init__(
164        self,
165        fishjam_id: str,
166        management_token: str,
167    ):
168        """Create a FishjamClient instance.
169
170        Does not contact the Fishjam backend — use :meth:`create_and_verify`
171        or :meth:`check_credentials` to verify credentials live.
172
173        Args:
174            fishjam_id: The unique identifier for the Fishjam instance.
175            management_token: The token used for authenticating management operations.
176        """
177        super().__init__(fishjam_id=fishjam_id, management_token=management_token)
178
179    @classmethod
180    def create_and_verify(
181        cls, *, fishjam_id: str, management_token: str
182    ) -> "FishjamClient":
183        """Construct a FishjamClient and verify its credentials against the backend.
184
185        Args:
186            fishjam_id: The unique identifier for the Fishjam instance.
187            management_token: The token used for authenticating management operations.
188
189        Returns:
190            FishjamClient: A client whose credentials have been verified.
191
192        Raises:
193            InvalidFishjamCredentialsError: If the token is rejected.
194        """
195        client = cls(fishjam_id=fishjam_id, management_token=management_token)
196        client.check_credentials()
197        return client
198
199    def check_credentials(self) -> None:
200        """Verify the management token via a single ``/validate`` call.
201
202        Raises:
203            InvalidFishjamCredentialsError: If the token is rejected.
204        """
205        response = credentials_validate_credentials.sync_detailed(client=self.client)
206        self._handle_deprecation_header(response.headers)
207
208        if response.status_code == HTTPStatus.NOT_FOUND:
209            raise InvalidFishjamCredentialsError("Invalid Fishjam credentials")
210
211    def create_peer(
212        self,
213        room_id: str,
214        options: PeerOptions | None = None,
215    ) -> tuple[Peer, str]:
216        """Creates a peer in the room.
217
218        Args:
219            room_id: The ID of the room where the peer will be created.
220            options: Configuration options for the peer. Defaults to None.
221
222        Returns:
223            A tuple containing:
224                - Peer: The created peer object.
225                - str: The peer token needed to authenticate to Fishjam.
226        """
227        options = options or PeerOptions()
228
229        peer_metadata = self.__parse_peer_metadata(options.metadata)
230        peer_options = PeerOptionsWebRTC(
231            metadata=peer_metadata,
232            subscribe_mode=SubscribeMode(options.subscribe_mode),
233        )
234        body = PeerConfig(type_=PeerType.WEBRTC, options=peer_options)
235
236        resp = cast(
237            PeerDetailsResponse,
238            self._request(room_add_peer, room_id=room_id, body=body),
239        )
240
241        return (resp.data.peer, resp.data.token)
242
243    def create_agent(self, room_id: str, options: AgentOptions | None = None):
244        """Creates an agent in the room.
245
246        Args:
247            room_id: The ID of the room where the agent will be created.
248            options: Configuration options for the agent. Defaults to None.
249
250        Returns:
251            Agent: The created agent instance initialized with peer ID, room ID, token,
252                and Fishjam URL.
253        """
254        options = options or AgentOptions()
255        body = PeerConfig(
256            type_=PeerType.AGENT,
257            options=PeerOptionsAgent(
258                output=AgentOutput(
259                    audio_format=AudioFormat(options.output.audio_format),
260                    audio_sample_rate=AudioSampleRate(options.output.audio_sample_rate),
261                ),
262                subscribe_mode=SubscribeMode(options.subscribe_mode),
263            ),
264        )
265
266        resp = cast(
267            PeerDetailsResponse,
268            self._request(room_add_peer, room_id=room_id, body=body),
269        )
270
271        return Agent(resp.data.peer.id, room_id, resp.data.token, self._fishjam_url)
272
273    def create_vapi_agent(
274        self,
275        room_id: str,
276        options: PeerOptionsVapi,
277    ) -> Peer:
278        """Creates a vapi agent in the room.
279
280        Args:
281            room_id: The ID of the room where the vapi agent will be created.
282            options: Configuration options for the vapi peer.
283
284        Returns:
285            - Peer: The created peer object.
286        """
287        body = PeerConfig(type_=PeerType.VAPI, options=options)
288
289        resp = cast(
290            PeerDetailsResponse,
291            self._request(room_add_peer, room_id=room_id, body=body),
292        )
293
294        return resp.data.peer
295
296    def create_room(self, options: RoomOptions | None = None) -> Room:
297        """Creates a new room.
298
299        Args:
300            options: Configuration options for the room. Defaults to None.
301
302        Returns:
303            Room: The created Room object.
304        """
305        options = options or RoomOptions()
306
307        if options.video_codec is None:
308            codec = UNSET
309        else:
310            codec = VideoCodec(options.video_codec)
311
312        config = RoomConfig(
313            max_peers=options.max_peers,
314            video_codec=codec,
315            webhook_url=options.webhook_url,
316            room_type=RoomType(options.room_type),
317            public=options.public,
318            batch_webhook_notifications=options.batch_webhook_notifications,
319        )
320
321        room = cast(
322            RoomCreateDetailsResponse, self._request(room_create_room, body=config)
323        ).data.room
324
325        return Room(config=room.config, id=room.id, peers=room.peers)
326
327    def get_all_rooms(self) -> list[Room]:
328        """Returns list of all rooms.
329
330        Returns:
331            list[Room]: A list of all available Room objects.
332        """
333        rooms = cast(RoomsListingResponse, self._request(room_get_all_rooms)).data
334
335        return [
336            Room(config=room.config, id=room.id, peers=room.peers) for room in rooms
337        ]
338
339    def get_room(self, room_id: str) -> Room:
340        """Returns room with the given id.
341
342        Args:
343            room_id: The ID of the room to retrieve.
344
345        Returns:
346            Room: The Room object corresponding to the given ID.
347        """
348        room = cast(
349            RoomDetailsResponse, self._request(room_get_room, room_id=room_id)
350        ).data
351
352        return Room(config=room.config, id=room.id, peers=room.peers)
353
354    def delete_peer(self, room_id: str, peer_id: str) -> None:
355        """Deletes a peer from a room.
356
357        Args:
358            room_id: The ID of the room the peer belongs to.
359            peer_id: The ID of the peer to delete.
360        """
361        return self._request(room_delete_peer, id=peer_id, room_id=room_id)
362
363    def delete_room(self, room_id: str) -> None:
364        """Deletes a room.
365
366        Args:
367            room_id: The ID of the room to delete.
368        """
369        return self._request(room_delete_room, room_id=room_id)
370
371    def refresh_peer_token(self, room_id: str, peer_id: str) -> str:
372        """Refreshes a peer token.
373
374        Args:
375            room_id: The ID of the room.
376            peer_id: The ID of the peer whose token needs refreshing.
377
378        Returns:
379            str: The new peer token.
380        """
381        response = cast(
382            PeerRefreshTokenResponse,
383            self._request(room_refresh_token, id=peer_id, room_id=room_id),
384        )
385
386        return response.data.token
387
388    def create_livestream_viewer_token(self, room_id: str) -> str:
389        """Generates a viewer token for livestream rooms.
390
391        Args:
392            room_id: The ID of the livestream room.
393
394        Returns:
395            str: The generated viewer token.
396        """
397        response = cast(
398            ViewerToken, self._request(viewer_generate_viewer_token, room_id=room_id)
399        )
400
401        return response.token
402
403    def create_livestream_streamer_token(self, room_id: str) -> str:
404        """Generates a streamer token for livestream rooms.
405
406        Args:
407            room_id: The ID of the livestream room.
408
409        Returns:
410            str: The generated streamer token.
411        """
412        response = cast(
413            StreamerToken,
414            self._request(streamer_generate_streamer_token, room_id=room_id),
415        )
416
417        return response.token
418
419    def create_moq_access(
420        self,
421        publish_path: str | None = None,
422        subscribe_path: str | None = None,
423    ) -> MoqAccess:
424        """Generates MoQ relay connection details.
425
426        Args:
427            publish_path: Path the access grants publish access to.
428            subscribe_path: Path the access grants subscribe access to.
429
430        Returns:
431            MoqAccess: The relay connection details, containing the
432            ``connection_url`` (with the JWT embedded as a ``?jwt=`` query
433            parameter) and the ``token`` itself.
434        """
435        config = MoqAccessConfig(
436            publish_path=publish_path, subscribe_path=subscribe_path
437        )
438        response = cast(
439            MoqAccess,
440            self._request(moq_create_access, body=config),
441        )
442
443        return response
444
445    def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str):
446        """Subscribes a peer to all tracks of another peer.
447
448        Args:
449            room_id: The ID of the room.
450            peer_id: The ID of the subscribing peer.
451            target_peer_id: The ID of the peer to subscribe to.
452        """
453        self._request(
454            room_subscribe_peer,
455            room_id=room_id,
456            id=peer_id,
457            peer_id=target_peer_id,
458        )
459
460    def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]):
461        """Subscribes a peer to specific tracks of another peer.
462
463        Args:
464            room_id: The ID of the room.
465            peer_id: The ID of the subscribing peer.
466            track_ids: A list of track IDs to subscribe to.
467        """
468        self._request(
469            room_subscribe_tracks,
470            room_id=room_id,
471            id=peer_id,
472            body=SubscribeTracksBody(track_ids=track_ids),
473        )
474
475    def __parse_peer_metadata(self, metadata: dict | None) -> WebRTCMetadata:
476        peer_metadata = WebRTCMetadata()
477
478        if not metadata:
479            return peer_metadata
480
481        for key, value in metadata.items():
482            peer_metadata.additional_properties[key] = value
483
484        return peer_metadata

Allows for managing rooms.

FishjamClient(fishjam_id: str, management_token: str)
163    def __init__(
164        self,
165        fishjam_id: str,
166        management_token: str,
167    ):
168        """Create a FishjamClient instance.
169
170        Does not contact the Fishjam backend — use :meth:`create_and_verify`
171        or :meth:`check_credentials` to verify credentials live.
172
173        Args:
174            fishjam_id: The unique identifier for the Fishjam instance.
175            management_token: The token used for authenticating management operations.
176        """
177        super().__init__(fishjam_id=fishjam_id, management_token=management_token)

Create a FishjamClient instance.

Does not contact the Fishjam backend — use create_and_verify() or check_credentials() to verify credentials live.

Args:

  • fishjam_id: The unique identifier for the Fishjam instance.
  • management_token: The token used for authenticating management operations.
@classmethod
def create_and_verify(cls, *, fishjam_id: str, management_token: str) -> 'FishjamClient':
179    @classmethod
180    def create_and_verify(
181        cls, *, fishjam_id: str, management_token: str
182    ) -> "FishjamClient":
183        """Construct a FishjamClient and verify its credentials against the backend.
184
185        Args:
186            fishjam_id: The unique identifier for the Fishjam instance.
187            management_token: The token used for authenticating management operations.
188
189        Returns:
190            FishjamClient: A client whose credentials have been verified.
191
192        Raises:
193            InvalidFishjamCredentialsError: If the token is rejected.
194        """
195        client = cls(fishjam_id=fishjam_id, management_token=management_token)
196        client.check_credentials()
197        return client

Construct a FishjamClient and verify its credentials against the backend.

Args:

  • fishjam_id: The unique identifier for the Fishjam instance.
  • management_token: The token used for authenticating management operations.

Returns:

  • FishjamClient: A client whose credentials have been verified.

Raises:

  • InvalidFishjamCredentialsError: If the token is rejected.
def check_credentials(self) -> None:
199    def check_credentials(self) -> None:
200        """Verify the management token via a single ``/validate`` call.
201
202        Raises:
203            InvalidFishjamCredentialsError: If the token is rejected.
204        """
205        response = credentials_validate_credentials.sync_detailed(client=self.client)
206        self._handle_deprecation_header(response.headers)
207
208        if response.status_code == HTTPStatus.NOT_FOUND:
209            raise InvalidFishjamCredentialsError("Invalid Fishjam credentials")

Verify the management token via a single /validate call.

Raises:

  • InvalidFishjamCredentialsError: If the token is rejected.
def create_peer( self, room_id: str, options: PeerOptions | None = None) -> tuple[Peer, str]:
211    def create_peer(
212        self,
213        room_id: str,
214        options: PeerOptions | None = None,
215    ) -> tuple[Peer, str]:
216        """Creates a peer in the room.
217
218        Args:
219            room_id: The ID of the room where the peer will be created.
220            options: Configuration options for the peer. Defaults to None.
221
222        Returns:
223            A tuple containing:
224                - Peer: The created peer object.
225                - str: The peer token needed to authenticate to Fishjam.
226        """
227        options = options or PeerOptions()
228
229        peer_metadata = self.__parse_peer_metadata(options.metadata)
230        peer_options = PeerOptionsWebRTC(
231            metadata=peer_metadata,
232            subscribe_mode=SubscribeMode(options.subscribe_mode),
233        )
234        body = PeerConfig(type_=PeerType.WEBRTC, options=peer_options)
235
236        resp = cast(
237            PeerDetailsResponse,
238            self._request(room_add_peer, room_id=room_id, body=body),
239        )
240
241        return (resp.data.peer, resp.data.token)

Creates a peer in the room.

Args:

  • room_id: The ID of the room where the peer will be created.
  • options: Configuration options for the peer. Defaults to None.

Returns:

  • A tuple containing:
    • Peer: The created peer object.
    • str: The peer token needed to authenticate to Fishjam.
def create_agent( self, room_id: str, options: AgentOptions | None = None):
243    def create_agent(self, room_id: str, options: AgentOptions | None = None):
244        """Creates an agent in the room.
245
246        Args:
247            room_id: The ID of the room where the agent will be created.
248            options: Configuration options for the agent. Defaults to None.
249
250        Returns:
251            Agent: The created agent instance initialized with peer ID, room ID, token,
252                and Fishjam URL.
253        """
254        options = options or AgentOptions()
255        body = PeerConfig(
256            type_=PeerType.AGENT,
257            options=PeerOptionsAgent(
258                output=AgentOutput(
259                    audio_format=AudioFormat(options.output.audio_format),
260                    audio_sample_rate=AudioSampleRate(options.output.audio_sample_rate),
261                ),
262                subscribe_mode=SubscribeMode(options.subscribe_mode),
263            ),
264        )
265
266        resp = cast(
267            PeerDetailsResponse,
268            self._request(room_add_peer, room_id=room_id, body=body),
269        )
270
271        return Agent(resp.data.peer.id, room_id, resp.data.token, self._fishjam_url)

Creates an agent in the room.

Args:

  • room_id: The ID of the room where the agent will be created.
  • options: Configuration options for the agent. Defaults to None.

Returns:

  • Agent: The created agent instance initialized with peer ID, room ID, token, and Fishjam URL.
def create_vapi_agent( self, room_id: str, options: PeerOptionsVapi) -> Peer:
273    def create_vapi_agent(
274        self,
275        room_id: str,
276        options: PeerOptionsVapi,
277    ) -> Peer:
278        """Creates a vapi agent in the room.
279
280        Args:
281            room_id: The ID of the room where the vapi agent will be created.
282            options: Configuration options for the vapi peer.
283
284        Returns:
285            - Peer: The created peer object.
286        """
287        body = PeerConfig(type_=PeerType.VAPI, options=options)
288
289        resp = cast(
290            PeerDetailsResponse,
291            self._request(room_add_peer, room_id=room_id, body=body),
292        )
293
294        return resp.data.peer

Creates a vapi agent in the room.

Args:

  • room_id: The ID of the room where the vapi agent will be created.
  • options: Configuration options for the vapi peer.

- - Peer: The created peer object.

def create_room( self, options: RoomOptions | None = None) -> Room:
296    def create_room(self, options: RoomOptions | None = None) -> Room:
297        """Creates a new room.
298
299        Args:
300            options: Configuration options for the room. Defaults to None.
301
302        Returns:
303            Room: The created Room object.
304        """
305        options = options or RoomOptions()
306
307        if options.video_codec is None:
308            codec = UNSET
309        else:
310            codec = VideoCodec(options.video_codec)
311
312        config = RoomConfig(
313            max_peers=options.max_peers,
314            video_codec=codec,
315            webhook_url=options.webhook_url,
316            room_type=RoomType(options.room_type),
317            public=options.public,
318            batch_webhook_notifications=options.batch_webhook_notifications,
319        )
320
321        room = cast(
322            RoomCreateDetailsResponse, self._request(room_create_room, body=config)
323        ).data.room
324
325        return Room(config=room.config, id=room.id, peers=room.peers)

Creates a new room.

Args:

  • options: Configuration options for the room. Defaults to None.

Returns:

  • Room: The created Room object.
def get_all_rooms(self) -> list[Room]:
327    def get_all_rooms(self) -> list[Room]:
328        """Returns list of all rooms.
329
330        Returns:
331            list[Room]: A list of all available Room objects.
332        """
333        rooms = cast(RoomsListingResponse, self._request(room_get_all_rooms)).data
334
335        return [
336            Room(config=room.config, id=room.id, peers=room.peers) for room in rooms
337        ]

Returns list of all rooms.

Returns:

  • list[Room]: A list of all available Room objects.
def get_room(self, room_id: str) -> Room:
339    def get_room(self, room_id: str) -> Room:
340        """Returns room with the given id.
341
342        Args:
343            room_id: The ID of the room to retrieve.
344
345        Returns:
346            Room: The Room object corresponding to the given ID.
347        """
348        room = cast(
349            RoomDetailsResponse, self._request(room_get_room, room_id=room_id)
350        ).data
351
352        return Room(config=room.config, id=room.id, peers=room.peers)

Returns room with the given id.

Args:

  • room_id: The ID of the room to retrieve.

Returns:

  • Room: The Room object corresponding to the given ID.
def delete_peer(self, room_id: str, peer_id: str) -> None:
354    def delete_peer(self, room_id: str, peer_id: str) -> None:
355        """Deletes a peer from a room.
356
357        Args:
358            room_id: The ID of the room the peer belongs to.
359            peer_id: The ID of the peer to delete.
360        """
361        return self._request(room_delete_peer, id=peer_id, room_id=room_id)

Deletes a peer from a room.

Args:

  • room_id: The ID of the room the peer belongs to.
  • peer_id: The ID of the peer to delete.
def delete_room(self, room_id: str) -> None:
363    def delete_room(self, room_id: str) -> None:
364        """Deletes a room.
365
366        Args:
367            room_id: The ID of the room to delete.
368        """
369        return self._request(room_delete_room, room_id=room_id)

Deletes a room.

Args:

  • room_id: The ID of the room to delete.
def refresh_peer_token(self, room_id: str, peer_id: str) -> str:
371    def refresh_peer_token(self, room_id: str, peer_id: str) -> str:
372        """Refreshes a peer token.
373
374        Args:
375            room_id: The ID of the room.
376            peer_id: The ID of the peer whose token needs refreshing.
377
378        Returns:
379            str: The new peer token.
380        """
381        response = cast(
382            PeerRefreshTokenResponse,
383            self._request(room_refresh_token, id=peer_id, room_id=room_id),
384        )
385
386        return response.data.token

Refreshes a peer token.

Args:

  • room_id: The ID of the room.
  • peer_id: The ID of the peer whose token needs refreshing.

Returns:

  • str: The new peer token.
def create_livestream_viewer_token(self, room_id: str) -> str:
388    def create_livestream_viewer_token(self, room_id: str) -> str:
389        """Generates a viewer token for livestream rooms.
390
391        Args:
392            room_id: The ID of the livestream room.
393
394        Returns:
395            str: The generated viewer token.
396        """
397        response = cast(
398            ViewerToken, self._request(viewer_generate_viewer_token, room_id=room_id)
399        )
400
401        return response.token

Generates a viewer token for livestream rooms.

Args:

  • room_id: The ID of the livestream room.

Returns:

  • str: The generated viewer token.
def create_livestream_streamer_token(self, room_id: str) -> str:
403    def create_livestream_streamer_token(self, room_id: str) -> str:
404        """Generates a streamer token for livestream rooms.
405
406        Args:
407            room_id: The ID of the livestream room.
408
409        Returns:
410            str: The generated streamer token.
411        """
412        response = cast(
413            StreamerToken,
414            self._request(streamer_generate_streamer_token, room_id=room_id),
415        )
416
417        return response.token

Generates a streamer token for livestream rooms.

Args:

  • room_id: The ID of the livestream room.

Returns:

  • str: The generated streamer token.
def create_moq_access( self, publish_path: str | None = None, subscribe_path: str | None = None) -> MoqAccess:
419    def create_moq_access(
420        self,
421        publish_path: str | None = None,
422        subscribe_path: str | None = None,
423    ) -> MoqAccess:
424        """Generates MoQ relay connection details.
425
426        Args:
427            publish_path: Path the access grants publish access to.
428            subscribe_path: Path the access grants subscribe access to.
429
430        Returns:
431            MoqAccess: The relay connection details, containing the
432            ``connection_url`` (with the JWT embedded as a ``?jwt=`` query
433            parameter) and the ``token`` itself.
434        """
435        config = MoqAccessConfig(
436            publish_path=publish_path, subscribe_path=subscribe_path
437        )
438        response = cast(
439            MoqAccess,
440            self._request(moq_create_access, body=config),
441        )
442
443        return response

Generates MoQ relay connection details.

Args:

  • publish_path: Path the access grants publish access to.
  • subscribe_path: Path the access grants subscribe access to.

Returns:

  • MoqAccess: The relay connection details, containing the
  • connection_url (with the JWT embedded as a ?jwt= query
  • parameter) and the token itself.
def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str):
445    def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str):
446        """Subscribes a peer to all tracks of another peer.
447
448        Args:
449            room_id: The ID of the room.
450            peer_id: The ID of the subscribing peer.
451            target_peer_id: The ID of the peer to subscribe to.
452        """
453        self._request(
454            room_subscribe_peer,
455            room_id=room_id,
456            id=peer_id,
457            peer_id=target_peer_id,
458        )

Subscribes a peer to all tracks of another peer.

Args:

  • room_id: The ID of the room.
  • peer_id: The ID of the subscribing peer.
  • target_peer_id: The ID of the peer to subscribe to.
def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]):
460    def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]):
461        """Subscribes a peer to specific tracks of another peer.
462
463        Args:
464            room_id: The ID of the room.
465            peer_id: The ID of the subscribing peer.
466            track_ids: A list of track IDs to subscribe to.
467        """
468        self._request(
469            room_subscribe_tracks,
470            room_id=room_id,
471            id=peer_id,
472            body=SubscribeTracksBody(track_ids=track_ids),
473        )

Subscribes a peer to specific tracks of another peer.

Args:

  • room_id: The ID of the room.
  • peer_id: The ID of the subscribing peer.
  • track_ids: A list of track IDs to subscribe to.
Inherited Members
fishjam.api._client.Client
client
warnings_shown
class FishjamNotifier:
 33class FishjamNotifier:
 34    """Allows for receiving WebSocket messages from Fishjam."""
 35
 36    def __init__(
 37        self,
 38        fishjam_id: str,
 39        management_token: str,
 40    ):
 41        """Create a FishjamNotifier instance with an ID and management token."""
 42        websocket_url = get_fishjam_url(fishjam_id).replace("http", "ws")
 43        self._fishjam_url = f"{websocket_url}/socket/server/websocket"
 44        self._management_token: str = management_token
 45        self._websocket: client.ClientConnection | None = None
 46        self._ready: bool = False
 47
 48        self._ready_event: asyncio.Event | None = None
 49
 50        self._notification_handler: NotificationHandler | None = None
 51
 52    def on_server_notification(self, handler: NotificationHandler):
 53        """Decorator for defining a handler for Fishjam notifications.
 54
 55        Args:
 56            handler: The function to be registered as the notification handler.
 57
 58        Returns:
 59            NotificationHandler: The original handler function (unmodified).
 60        """
 61        self._notification_handler = handler
 62        return handler
 63
 64    async def connect(self):
 65        """Connects to Fishjam and listens for all incoming messages.
 66
 67        It runs until the connection isn't closed.
 68
 69        The incoming messages are handled by the functions defined using the
 70        `on_server_notification` decorator.
 71
 72        The handler have to be defined before calling `connect`,
 73        otherwise the messages won't be received.
 74        """
 75        async with client.connect(self._fishjam_url) as websocket:
 76            try:
 77                self._websocket = websocket
 78                await self._authenticate()
 79
 80                if self._notification_handler:
 81                    await self._subscribe_event(
 82                        event=ServerMessageEventType.EVENT_TYPE_SERVER_NOTIFICATION
 83                    )
 84
 85                self._ready = True
 86                if self._ready_event:
 87                    self._ready_event.set()
 88
 89                await self._receive_loop()
 90            finally:
 91                self._websocket = None
 92
 93    async def wait_ready(self) -> None:
 94        """Waits until the notifier is connected and authenticated to Fishjam.
 95
 96        If already connected, returns immediately.
 97        """
 98        if self._ready:
 99            return
100
101        if self._ready_event is None:
102            self._ready_event = asyncio.Event()
103
104        await self._ready_event.wait()
105
106    async def _authenticate(self):
107        if not self._websocket:
108            raise RuntimeError("Websocket is not connected")
109
110        msg = ServerMessage(
111            auth_request=ServerMessageAuthRequest(token=self._management_token)
112        )
113        await self._websocket.send(bytes(msg))
114
115        try:
116            message = await self._websocket.recv(decode=False)
117        except ConnectionClosed as exception:
118            if "invalid token" in str(exception):
119                raise RuntimeError("Invalid management token") from exception
120            raise
121
122        message = ServerMessage().parse(message)
123
124        _type, message = betterproto.which_one_of(message, "content")
125        assert isinstance(message, ServerMessageAuthenticated)
126
127    async def _receive_loop(self):
128        if not self._websocket:
129            raise RuntimeError("Websocket is not connected")
130        if not self._notification_handler:
131            raise RuntimeError("Notification handler is not defined")
132
133        while True:
134            message = await self._websocket.recv(decode=False)
135            message = ServerMessage().parse(message)
136            _which, message = betterproto.which_one_of(message, "content")
137
138            if isinstance(message, ALLOWED_NOTIFICATIONS):
139                res = self._notification_handler(message)
140                if inspect.isawaitable(res):
141                    await res
142
143    async def _subscribe_event(self, event: ServerMessageEventType):
144        if not self._websocket:
145            raise RuntimeError("Websocket is not connected")
146
147        request = ServerMessage(subscribe_request=ServerMessageSubscribeRequest(event))
148
149        await self._websocket.send(bytes(request))
150        message = cast(bytes, await self._websocket.recv())
151        message = ServerMessage().parse(message)
152        _which, message = betterproto.which_one_of(message, "content")
153        assert isinstance(message, ServerMessageSubscribeResponse)

Allows for receiving WebSocket messages from Fishjam.

FishjamNotifier(fishjam_id: str, management_token: str)
36    def __init__(
37        self,
38        fishjam_id: str,
39        management_token: str,
40    ):
41        """Create a FishjamNotifier instance with an ID and management token."""
42        websocket_url = get_fishjam_url(fishjam_id).replace("http", "ws")
43        self._fishjam_url = f"{websocket_url}/socket/server/websocket"
44        self._management_token: str = management_token
45        self._websocket: client.ClientConnection | None = None
46        self._ready: bool = False
47
48        self._ready_event: asyncio.Event | None = None
49
50        self._notification_handler: NotificationHandler | None = None

Create a FishjamNotifier instance with an ID and management token.

def on_server_notification( self, handler: Callable[[fishjam.events.ServerMessageRoomCreated | fishjam.events.ServerMessageRoomDeleted | fishjam.events.ServerMessageRoomCrashed | fishjam.events.ServerMessagePeerAdded | fishjam.events.ServerMessagePeerDeleted | fishjam.events.ServerMessagePeerConnected | fishjam.events.ServerMessagePeerDisconnected | fishjam.events.ServerMessagePeerMetadataUpdated | fishjam.events.ServerMessagePeerCrashed | fishjam.events.ServerMessageStreamerConnected | fishjam.events.ServerMessageStreamerDisconnected | fishjam.events.ServerMessageChannelAdded | fishjam.events.ServerMessageChannelRemoved | fishjam.events.ServerMessageViewerConnected | fishjam.events.ServerMessageViewerDisconnected | fishjam.events.ServerMessageTrackAdded | fishjam.events.ServerMessageTrackRemoved | fishjam.events.ServerMessageTrackMetadataUpdated], NoneType] | Callable[[fishjam.events.ServerMessageRoomCreated | fishjam.events.ServerMessageRoomDeleted | fishjam.events.ServerMessageRoomCrashed | fishjam.events.ServerMessagePeerAdded | fishjam.events.ServerMessagePeerDeleted | fishjam.events.ServerMessagePeerConnected | fishjam.events.ServerMessagePeerDisconnected | fishjam.events.ServerMessagePeerMetadataUpdated | fishjam.events.ServerMessagePeerCrashed | fishjam.events.ServerMessageStreamerConnected | fishjam.events.ServerMessageStreamerDisconnected | fishjam.events.ServerMessageChannelAdded | fishjam.events.ServerMessageChannelRemoved | fishjam.events.ServerMessageViewerConnected | fishjam.events.ServerMessageViewerDisconnected | fishjam.events.ServerMessageTrackAdded | fishjam.events.ServerMessageTrackRemoved | fishjam.events.ServerMessageTrackMetadataUpdated], Coroutine[Any, Any, None]]):
52    def on_server_notification(self, handler: NotificationHandler):
53        """Decorator for defining a handler for Fishjam notifications.
54
55        Args:
56            handler: The function to be registered as the notification handler.
57
58        Returns:
59            NotificationHandler: The original handler function (unmodified).
60        """
61        self._notification_handler = handler
62        return handler

Decorator for defining a handler for Fishjam notifications.

Args:

  • handler: The function to be registered as the notification handler.

Returns:

  • NotificationHandler: The original handler function (unmodified).
async def connect(self):
64    async def connect(self):
65        """Connects to Fishjam and listens for all incoming messages.
66
67        It runs until the connection isn't closed.
68
69        The incoming messages are handled by the functions defined using the
70        `on_server_notification` decorator.
71
72        The handler have to be defined before calling `connect`,
73        otherwise the messages won't be received.
74        """
75        async with client.connect(self._fishjam_url) as websocket:
76            try:
77                self._websocket = websocket
78                await self._authenticate()
79
80                if self._notification_handler:
81                    await self._subscribe_event(
82                        event=ServerMessageEventType.EVENT_TYPE_SERVER_NOTIFICATION
83                    )
84
85                self._ready = True
86                if self._ready_event:
87                    self._ready_event.set()
88
89                await self._receive_loop()
90            finally:
91                self._websocket = None

Connects to Fishjam and listens for all incoming messages.

It runs until the connection isn't closed.

The incoming messages are handled by the functions defined using the on_server_notification decorator.

The handler have to be defined before calling connect, otherwise the messages won't be received.

async def wait_ready(self) -> None:
 93    async def wait_ready(self) -> None:
 94        """Waits until the notifier is connected and authenticated to Fishjam.
 95
 96        If already connected, returns immediately.
 97        """
 98        if self._ready:
 99            return
100
101        if self._ready_event is None:
102            self._ready_event = asyncio.Event()
103
104        await self._ready_event.wait()

Waits until the notifier is connected and authenticated to Fishjam.

If already connected, returns immediately.

45def decode_server_notifications(binary: bytes) -> List[AllowedNotification]:
46    """Decode a received protobuf payload into a list of notifications.
47
48    Handles both single notifications and batches transparently: a single
49    notification is returned as a one-element list, a batch is unpacked into
50    its members (in order), and anything unsupported yields an empty list.
51
52    The available notifications are listed in the `fishjam.events` module.
53
54    Args:
55        binary: The raw binary data received from the webhook.
56
57    Returns:
58        list[AllowedNotification]: The decoded notifications, in order. Empty
59            when the payload carries no supported notification.
60    """
61    message = ServerMessage().parse(binary)
62    _which, content = betterproto.which_one_of(message, "content")
63
64    if isinstance(content, ServerMessageNotificationBatch):
65        return _unpack_batch(content)
66
67    if isinstance(content, ALLOWED_NOTIFICATIONS):
68        return [content]
69
70    return []

Decode a received protobuf payload into a list of notifications.

Handles both single notifications and batches transparently: a single notification is returned as a one-element list, a batch is unpacked into its members (in order), and anything unsupported yields an empty list.

The available notifications are listed in the fishjam.events module.

Args:

  • binary: The raw binary data received from the webhook.

Returns:

  • list[AllowedNotification]: The decoded notifications, in order. Empty when the payload carries no supported notification.
def receive_binary( binary: bytes) -> fishjam.events.ServerMessageRoomCreated | fishjam.events.ServerMessageRoomDeleted | fishjam.events.ServerMessageRoomCrashed | fishjam.events.ServerMessagePeerAdded | fishjam.events.ServerMessagePeerDeleted | fishjam.events.ServerMessagePeerConnected | fishjam.events.ServerMessagePeerDisconnected | fishjam.events.ServerMessagePeerMetadataUpdated | fishjam.events.ServerMessagePeerCrashed | fishjam.events.ServerMessageStreamerConnected | fishjam.events.ServerMessageStreamerDisconnected | fishjam.events.ServerMessageChannelAdded | fishjam.events.ServerMessageChannelRemoved | fishjam.events.ServerMessageViewerConnected | fishjam.events.ServerMessageViewerDisconnected | fishjam.events.ServerMessageTrackAdded | fishjam.events.ServerMessageTrackRemoved | fishjam.events.ServerMessageTrackMetadataUpdated | List[fishjam.events.ServerMessageRoomCreated | fishjam.events.ServerMessageRoomDeleted | fishjam.events.ServerMessageRoomCrashed | fishjam.events.ServerMessagePeerAdded | fishjam.events.ServerMessagePeerDeleted | fishjam.events.ServerMessagePeerConnected | fishjam.events.ServerMessagePeerDisconnected | fishjam.events.ServerMessagePeerMetadataUpdated | fishjam.events.ServerMessagePeerCrashed | fishjam.events.ServerMessageStreamerConnected | fishjam.events.ServerMessageStreamerDisconnected | fishjam.events.ServerMessageChannelAdded | fishjam.events.ServerMessageChannelRemoved | fishjam.events.ServerMessageViewerConnected | fishjam.events.ServerMessageViewerDisconnected | fishjam.events.ServerMessageTrackAdded | fishjam.events.ServerMessageTrackRemoved | fishjam.events.ServerMessageTrackMetadataUpdated] | None:
 73def receive_binary(
 74    binary: bytes,
 75) -> Union[AllowedNotification, List[AllowedNotification], None]:
 76    """Transforms a received protobuf notification into a notification instance.
 77
 78    .. deprecated::
 79        Use `decode_server_notifications` instead, which always returns a list
 80        and handles batched payloads with a single, consistent return type.
 81
 82    The available notifications are listed in `fishjam.events` module.
 83
 84    Args:
 85        binary: The raw binary data received from the webhook.
 86
 87    Returns:
 88        AllowedNotification: A single notification when the payload carries one.
 89        list[AllowedNotification]: The unpacked notifications, in order, when the
 90            payload is a batch (webhook batching enabled).
 91        None: When the payload is not a supported notification.
 92    """
 93    warnings.warn(
 94        "receive_binary is deprecated; use decode_server_notifications instead.",
 95        DeprecationWarning,
 96        stacklevel=2,
 97    )
 98
 99    message = ServerMessage().parse(binary)
100    _which, content = betterproto.which_one_of(message, "content")
101
102    if isinstance(content, ServerMessageNotificationBatch):
103        return _unpack_batch(content)
104
105    if isinstance(content, ALLOWED_NOTIFICATIONS):
106        return content
107
108    return None

Transforms a received protobuf notification into a notification instance.

Deprecated since version .

  • Use decode_server_notifications instead, which always returns a list
  • and handles batched payloads with a single, consistent return type.

The available notifications are listed in fishjam.events module.

Args:

  • binary: The raw binary data received from the webhook.

Returns:

  • AllowedNotification: A single notification when the payload carries one.
  • list[AllowedNotification]: The unpacked notifications, in order, when the payload is a batch (webhook batching enabled).
  • None: When the payload is not a supported notification.
class PeerMetadata:
13@_attrs_define
14class PeerMetadata:
15    """Custom metadata set by the peer
16
17    Example:
18        {'name': 'FishjamUser'}
19
20    """
21
22    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
23
24    def to_dict(self) -> dict[str, Any]:
25        field_dict: dict[str, Any] = {}
26        field_dict.update(self.additional_properties)
27
28        return field_dict
29
30    @classmethod
31    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
32        d = dict(src_dict)
33        peer_metadata = cls()
34
35        peer_metadata.additional_properties = d
36        return peer_metadata
37
38    @property
39    def additional_keys(self) -> list[str]:
40        return list(self.additional_properties.keys())
41
42    def __getitem__(self, key: str) -> Any:
43        return self.additional_properties[key]
44
45    def __setitem__(self, key: str, value: Any) -> None:
46        self.additional_properties[key] = value
47
48    def __delitem__(self, key: str) -> None:
49        del self.additional_properties[key]
50
51    def __contains__(self, key: str) -> bool:
52        return key in self.additional_properties

Custom metadata set by the peer

Example:

  • {'name': 'FishjamUser'}
PeerMetadata()
23def __init__(self, ):
24    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class PeerMetadata.

additional_properties: 'dict[str, Any]'
def to_dict(self) -> 'dict[str, Any]':
24    def to_dict(self) -> dict[str, Any]:
25        field_dict: dict[str, Any] = {}
26        field_dict.update(self.additional_properties)
27
28        return field_dict
@classmethod
def from_dict(cls: 'type[T]', src_dict: 'Mapping[str, Any]') -> 'T':
30    @classmethod
31    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
32        d = dict(src_dict)
33        peer_metadata = cls()
34
35        peer_metadata.additional_properties = d
36        return peer_metadata
additional_keys: 'list[str]'
38    @property
39    def additional_keys(self) -> list[str]:
40        return list(self.additional_properties.keys())
@dataclass
class PeerOptions:
118@dataclass
119class PeerOptions:
120    """Options specific to a WebRTC Peer.
121
122    Attributes:
123        metadata: Peer metadata.
124        subscribe_mode: Configuration of peer's subscribing policy.
125    """
126
127    metadata: dict[str, Any] | None = None
128    """Peer metadata"""
129    subscribe_mode: Literal["auto", "manual"] = "auto"
130    """Configuration of peer's subscribing policy"""

Options specific to a WebRTC Peer.

Attributes:

  • metadata: Peer metadata.
  • subscribe_mode: Configuration of peer's subscribing policy.
PeerOptions( metadata: dict[str, Any] | None = None, subscribe_mode: Literal['auto', 'manual'] = 'auto')
metadata: dict[str, Any] | None = None

Peer metadata

subscribe_mode: Literal['auto', 'manual'] = 'auto'

Configuration of peer's subscribing policy

class PeerOptionsVapi:
15@_attrs_define
16class PeerOptionsVapi:
17    """Options specific to the VAPI peer
18
19    Attributes:
20        api_key (str): VAPI API key
21        call_id (str): VAPI call ID
22        subscribe_mode (SubscribeMode | Unset): Configuration of peer's subscribing policy
23    """
24
25    api_key: str
26    call_id: str
27    subscribe_mode: SubscribeMode | Unset = UNSET
28
29    def to_dict(self) -> dict[str, Any]:
30        api_key = self.api_key
31
32        call_id = self.call_id
33
34        subscribe_mode: str | Unset = UNSET
35        if not isinstance(self.subscribe_mode, Unset):
36            subscribe_mode = self.subscribe_mode.value
37
38        field_dict: dict[str, Any] = {}
39
40        field_dict.update({
41            "apiKey": api_key,
42            "callId": call_id,
43        })
44        if subscribe_mode is not UNSET:
45            field_dict["subscribeMode"] = subscribe_mode
46
47        return field_dict
48
49    @classmethod
50    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
51        d = dict(src_dict)
52        api_key = d.pop("apiKey")
53
54        call_id = d.pop("callId")
55
56        _subscribe_mode = d.pop("subscribeMode", UNSET)
57        subscribe_mode: SubscribeMode | Unset
58        if isinstance(_subscribe_mode, Unset):
59            subscribe_mode = UNSET
60        else:
61            subscribe_mode = SubscribeMode(_subscribe_mode)
62
63        peer_options_vapi = cls(
64            api_key=api_key,
65            call_id=call_id,
66            subscribe_mode=subscribe_mode,
67        )
68
69        return peer_options_vapi

Options specific to the VAPI peer

Attributes:

  • api_key (str): VAPI API key
  • call_id (str): VAPI call ID
  • subscribe_mode (SubscribeMode | Unset): Configuration of peer's subscribing policy
PeerOptionsVapi( api_key: 'str', call_id: 'str', subscribe_mode: 'SubscribeMode | Unset' = <fishjam._openapi_client.types.Unset object>)
25def __init__(self, api_key, call_id, subscribe_mode=attr_dict['subscribe_mode'].default):
26    self.api_key = api_key
27    self.call_id = call_id
28    self.subscribe_mode = subscribe_mode

Method generated by attrs for class PeerOptionsVapi.

api_key: 'str'
call_id: 'str'
subscribe_mode: 'SubscribeMode | Unset'
def to_dict(self) -> 'dict[str, Any]':
29    def to_dict(self) -> dict[str, Any]:
30        api_key = self.api_key
31
32        call_id = self.call_id
33
34        subscribe_mode: str | Unset = UNSET
35        if not isinstance(self.subscribe_mode, Unset):
36            subscribe_mode = self.subscribe_mode.value
37
38        field_dict: dict[str, Any] = {}
39
40        field_dict.update({
41            "apiKey": api_key,
42            "callId": call_id,
43        })
44        if subscribe_mode is not UNSET:
45            field_dict["subscribeMode"] = subscribe_mode
46
47        return field_dict
@classmethod
def from_dict(cls: 'type[T]', src_dict: 'Mapping[str, Any]') -> 'T':
49    @classmethod
50    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
51        d = dict(src_dict)
52        api_key = d.pop("apiKey")
53
54        call_id = d.pop("callId")
55
56        _subscribe_mode = d.pop("subscribeMode", UNSET)
57        subscribe_mode: SubscribeMode | Unset
58        if isinstance(_subscribe_mode, Unset):
59            subscribe_mode = UNSET
60        else:
61            subscribe_mode = SubscribeMode(_subscribe_mode)
62
63        peer_options_vapi = cls(
64            api_key=api_key,
65            call_id=call_id,
66            subscribe_mode=subscribe_mode,
67        )
68
69        return peer_options_vapi
@dataclass
class RoomOptions:
 81@dataclass
 82class RoomOptions:
 83    """Description of a room options.
 84
 85    Attributes:
 86        max_peers: Maximum amount of peers allowed into the room.
 87        video_codec: Enforces video codec for each peer in the room.
 88        webhook_url: URL where Fishjam notifications will be sent.
 89        room_type: The use-case of the room. If not provided, this defaults
 90            to conference.
 91        public: True if livestream viewers can omit specifying a token.
 92        batch_webhook_notifications: If true, webhook notifications for this room
 93            are coalesced into a single NotificationBatch per HTTP send instead
 94            of one request per notification.
 95    """
 96
 97    max_peers: int | None = None
 98    """Maximum amount of peers allowed into the room"""
 99    video_codec: Literal["h264", "vp8"] | None = None
100    """Enforces video codec for each peer in the room"""
101    webhook_url: str | None = None
102    """URL where Fishjam notifications will be sent"""
103    room_type: Literal[
104        "conference",
105        "audio_only",
106        "livestream",
107        "full_feature",
108        "broadcaster",
109        "audio_only_livestream",
110    ] = "conference"
111    """The use-case of the room. If not provided, this defaults to conference."""
112    public: bool = False
113    """True if livestream viewers can omit specifying a token."""
114    batch_webhook_notifications: bool = False
115    """Coalesce webhook notifications into a single NotificationBatch per send."""

Description of a room options.

Attributes:

  • max_peers: Maximum amount of peers allowed into the room.
  • video_codec: Enforces video codec for each peer in the room.
  • webhook_url: URL where Fishjam notifications will be sent.
  • room_type: The use-case of the room. If not provided, this defaults to conference.
  • public: True if livestream viewers can omit specifying a token.
  • batch_webhook_notifications: If true, webhook notifications for this room are coalesced into a single NotificationBatch per HTTP send instead of one request per notification.
RoomOptions( max_peers: int | None = None, video_codec: Literal['h264', 'vp8'] | None = None, webhook_url: str | None = None, room_type: Literal['conference', 'audio_only', 'livestream', 'full_feature', 'broadcaster', 'audio_only_livestream'] = 'conference', public: bool = False, batch_webhook_notifications: bool = False)
max_peers: int | None = None

Maximum amount of peers allowed into the room

video_codec: Literal['h264', 'vp8'] | None = None

Enforces video codec for each peer in the room

webhook_url: str | None = None

URL where Fishjam notifications will be sent

room_type: Literal['conference', 'audio_only', 'livestream', 'full_feature', 'broadcaster', 'audio_only_livestream'] = 'conference'

The use-case of the room. If not provided, this defaults to conference.

public: bool = False

True if livestream viewers can omit specifying a token.

batch_webhook_notifications: bool = False

Coalesce webhook notifications into a single NotificationBatch per send.

@dataclass
class AgentOptions:
146@dataclass
147class AgentOptions:
148    """Options specific to an Agent Peer.
149
150    Attributes:
151        output: Configuration for the agent's output options.
152        subscribe_mode: Configuration of peer's subscribing policy.
153    """
154
155    output: AgentOutputOptions = field(default_factory=AgentOutputOptions)
156
157    subscribe_mode: Literal["auto", "manual"] = "auto"

Options specific to an Agent Peer.

Attributes:

  • output: Configuration for the agent's output options.
  • subscribe_mode: Configuration of peer's subscribing policy.
AgentOptions( output: AgentOutputOptions = <factory>, subscribe_mode: Literal['auto', 'manual'] = 'auto')
subscribe_mode: Literal['auto', 'manual'] = 'auto'
@dataclass
class AgentOutputOptions:
133@dataclass
134class AgentOutputOptions:
135    """Options of the desired format of audio tracks going from Fishjam to the agent.
136
137    Attributes:
138        audio_format: The format of the audio stream (e.g., 'pcm16').
139        audio_sample_rate: The sample rate of the audio stream.
140    """
141
142    audio_format: Literal["pcm16"] = "pcm16"
143    audio_sample_rate: Literal[16000, 24000] = 16000

Options of the desired format of audio tracks going from Fishjam to the agent.

Attributes:

  • audio_format: The format of the audio stream (e.g., 'pcm16').
  • audio_sample_rate: The sample rate of the audio stream.
AgentOutputOptions( audio_format: Literal['pcm16'] = 'pcm16', audio_sample_rate: Literal[16000, 24000] = 16000)
audio_format: Literal['pcm16'] = 'pcm16'
audio_sample_rate: Literal[16000, 24000] = 16000
@dataclass
class Room:
63@dataclass
64class Room:
65    """Description of the room state.
66
67    Attributes:
68        config: Room configuration.
69        id: Room ID.
70        peers: List of all peers.
71    """
72
73    config: RoomConfig
74    """Room configuration"""
75    id: str
76    """Room ID"""
77    peers: list[Peer]
78    """List of all peers"""

Description of the room state.

Attributes:

  • config: Room configuration.
  • id: Room ID.
  • peers: List of all peers.
Room( config: fishjam._openapi_client.models.room_config.RoomConfig, id: str, peers: list[Peer])
config: fishjam._openapi_client.models.room_config.RoomConfig

Room configuration

id: str

Room ID

peers: list[Peer]

List of all peers

class Peer:
 23@_attrs_define
 24class Peer:
 25    """Describes peer status
 26
 27    Attributes:
 28        id (str): Assigned peer id Example: 4a1c1164-5fb7-425d-89d7-24cdb8fff1cf.
 29        metadata (None | PeerMetadata): Custom metadata set by the peer Example: {'name': 'FishjamUser'}.
 30        status (PeerStatus): Informs about the peer status Example: disconnected.
 31        subscribe_mode (SubscribeMode): Configuration of peer's subscribing policy
 32        subscriptions (Subscriptions): Describes peer's subscriptions in manual mode
 33        tracks (list[Track]): List of all peer's tracks
 34        type_ (PeerType): Peer type Example: webrtc.
 35    """
 36
 37    id: str
 38    metadata: None | PeerMetadata
 39    status: PeerStatus
 40    subscribe_mode: SubscribeMode
 41    subscriptions: Subscriptions
 42    tracks: list[Track]
 43    type_: PeerType
 44    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
 45
 46    def to_dict(self) -> dict[str, Any]:
 47        from ..models.peer_metadata import PeerMetadata
 48
 49        id = self.id
 50
 51        metadata: dict[str, Any] | None
 52        if isinstance(self.metadata, PeerMetadata):
 53            metadata = self.metadata.to_dict()
 54        else:
 55            metadata = self.metadata
 56
 57        status = self.status.value
 58
 59        subscribe_mode = self.subscribe_mode.value
 60
 61        subscriptions = self.subscriptions.to_dict()
 62
 63        tracks = []
 64        for tracks_item_data in self.tracks:
 65            tracks_item = tracks_item_data.to_dict()
 66            tracks.append(tracks_item)
 67
 68        type_ = self.type_.value
 69
 70        field_dict: dict[str, Any] = {}
 71        field_dict.update(self.additional_properties)
 72        field_dict.update({
 73            "id": id,
 74            "metadata": metadata,
 75            "status": status,
 76            "subscribeMode": subscribe_mode,
 77            "subscriptions": subscriptions,
 78            "tracks": tracks,
 79            "type": type_,
 80        })
 81
 82        return field_dict
 83
 84    @classmethod
 85    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 86        from ..models.peer_metadata import PeerMetadata
 87        from ..models.subscriptions import Subscriptions
 88        from ..models.track import Track
 89
 90        d = dict(src_dict)
 91        id = d.pop("id")
 92
 93        def _parse_metadata(data: object) -> None | PeerMetadata:
 94            if data is None:
 95                return data
 96            try:
 97                if not isinstance(data, dict):
 98                    raise TypeError()
 99                componentsschemas_peer_metadata_type_0 = PeerMetadata.from_dict(data)
100
101                return componentsschemas_peer_metadata_type_0
102            except (TypeError, ValueError, AttributeError, KeyError):
103                pass
104            return cast(None | PeerMetadata, data)
105
106        metadata = _parse_metadata(d.pop("metadata"))
107
108        status = PeerStatus(d.pop("status"))
109
110        subscribe_mode = SubscribeMode(d.pop("subscribeMode"))
111
112        subscriptions = Subscriptions.from_dict(d.pop("subscriptions"))
113
114        tracks = []
115        _tracks = d.pop("tracks")
116        for tracks_item_data in _tracks:
117            tracks_item = Track.from_dict(tracks_item_data)
118
119            tracks.append(tracks_item)
120
121        type_ = PeerType(d.pop("type"))
122
123        peer = cls(
124            id=id,
125            metadata=metadata,
126            status=status,
127            subscribe_mode=subscribe_mode,
128            subscriptions=subscriptions,
129            tracks=tracks,
130            type_=type_,
131        )
132
133        peer.additional_properties = d
134        return peer
135
136    @property
137    def additional_keys(self) -> list[str]:
138        return list(self.additional_properties.keys())
139
140    def __getitem__(self, key: str) -> Any:
141        return self.additional_properties[key]
142
143    def __setitem__(self, key: str, value: Any) -> None:
144        self.additional_properties[key] = value
145
146    def __delitem__(self, key: str) -> None:
147        del self.additional_properties[key]
148
149    def __contains__(self, key: str) -> bool:
150        return key in self.additional_properties

Describes peer status

Attributes:

  • id (str): Assigned peer id Example: 4a1c1164-5fb7-425d-89d7-24cdb8fff1cf.
  • metadata (None | PeerMetadata): Custom metadata set by the peer Example: {'name': 'FishjamUser'}.
  • status (PeerStatus): Informs about the peer status Example: disconnected.
  • subscribe_mode (SubscribeMode): Configuration of peer's subscribing policy
  • subscriptions (Subscriptions): Describes peer's subscriptions in manual mode
  • tracks (list[Track]): List of all peer's tracks
  • type_ (PeerType): Peer type Example: webrtc.
Peer( id: 'str', metadata: 'None | PeerMetadata', status: 'PeerStatus', subscribe_mode: 'SubscribeMode', subscriptions: 'Subscriptions', tracks: 'list[Track]', type_: 'PeerType')
30def __init__(self, id, metadata, status, subscribe_mode, subscriptions, tracks, type_):
31    self.id = id
32    self.metadata = metadata
33    self.status = status
34    self.subscribe_mode = subscribe_mode
35    self.subscriptions = subscriptions
36    self.tracks = tracks
37    self.type_ = type_
38    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class Peer.

id: 'str'
metadata: 'None | PeerMetadata'
status: 'PeerStatus'
subscribe_mode: 'SubscribeMode'
subscriptions: 'Subscriptions'
tracks: 'list[Track]'
type_: 'PeerType'
additional_properties: 'dict[str, Any]'
def to_dict(self) -> 'dict[str, Any]':
46    def to_dict(self) -> dict[str, Any]:
47        from ..models.peer_metadata import PeerMetadata
48
49        id = self.id
50
51        metadata: dict[str, Any] | None
52        if isinstance(self.metadata, PeerMetadata):
53            metadata = self.metadata.to_dict()
54        else:
55            metadata = self.metadata
56
57        status = self.status.value
58
59        subscribe_mode = self.subscribe_mode.value
60
61        subscriptions = self.subscriptions.to_dict()
62
63        tracks = []
64        for tracks_item_data in self.tracks:
65            tracks_item = tracks_item_data.to_dict()
66            tracks.append(tracks_item)
67
68        type_ = self.type_.value
69
70        field_dict: dict[str, Any] = {}
71        field_dict.update(self.additional_properties)
72        field_dict.update({
73            "id": id,
74            "metadata": metadata,
75            "status": status,
76            "subscribeMode": subscribe_mode,
77            "subscriptions": subscriptions,
78            "tracks": tracks,
79            "type": type_,
80        })
81
82        return field_dict
@classmethod
def from_dict(cls: 'type[T]', src_dict: 'Mapping[str, Any]') -> 'T':
 84    @classmethod
 85    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
 86        from ..models.peer_metadata import PeerMetadata
 87        from ..models.subscriptions import Subscriptions
 88        from ..models.track import Track
 89
 90        d = dict(src_dict)
 91        id = d.pop("id")
 92
 93        def _parse_metadata(data: object) -> None | PeerMetadata:
 94            if data is None:
 95                return data
 96            try:
 97                if not isinstance(data, dict):
 98                    raise TypeError()
 99                componentsschemas_peer_metadata_type_0 = PeerMetadata.from_dict(data)
100
101                return componentsschemas_peer_metadata_type_0
102            except (TypeError, ValueError, AttributeError, KeyError):
103                pass
104            return cast(None | PeerMetadata, data)
105
106        metadata = _parse_metadata(d.pop("metadata"))
107
108        status = PeerStatus(d.pop("status"))
109
110        subscribe_mode = SubscribeMode(d.pop("subscribeMode"))
111
112        subscriptions = Subscriptions.from_dict(d.pop("subscriptions"))
113
114        tracks = []
115        _tracks = d.pop("tracks")
116        for tracks_item_data in _tracks:
117            tracks_item = Track.from_dict(tracks_item_data)
118
119            tracks.append(tracks_item)
120
121        type_ = PeerType(d.pop("type"))
122
123        peer = cls(
124            id=id,
125            metadata=metadata,
126            status=status,
127            subscribe_mode=subscribe_mode,
128            subscriptions=subscriptions,
129            tracks=tracks,
130            type_=type_,
131        )
132
133        peer.additional_properties = d
134        return peer
additional_keys: 'list[str]'
136    @property
137    def additional_keys(self) -> list[str]:
138        return list(self.additional_properties.keys())
class MoqAccess:
13@_attrs_define
14class MoqAccess:
15    """Connection details for a MoQ relay client
16
17    Attributes:
18        connection_url (str): Relay connection URL with the JWT embedded as a `?jwt=` query parameter. Pass directly to
19            a MoQ client SDK. Example: https://relay.fishjam.io/abc123?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....
20        token (str): JWT authorizing the MoQ relay connection, also embedded in `connection_url` Example: eyJhbGciOiJIUz
21            I1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZmlzaGphbSIsInB1dCI6WyJteS1zdHJlYW0iXSwiZ2V0IjpbXSwiaWF0IjoxNzEzMzYwMDAwLCJle
22            HAiOjE3MTMzNjM2MDB9.abc123.
23    """
24
25    connection_url: str
26    token: str
27    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
28
29    def to_dict(self) -> dict[str, Any]:
30        connection_url = self.connection_url
31
32        token = self.token
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update({
37            "connection_url": connection_url,
38            "token": token,
39        })
40
41        return field_dict
42
43    @classmethod
44    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
45        d = dict(src_dict)
46        connection_url = d.pop("connection_url")
47
48        token = d.pop("token")
49
50        moq_access = cls(
51            connection_url=connection_url,
52            token=token,
53        )
54
55        moq_access.additional_properties = d
56        return moq_access
57
58    @property
59    def additional_keys(self) -> list[str]:
60        return list(self.additional_properties.keys())
61
62    def __getitem__(self, key: str) -> Any:
63        return self.additional_properties[key]
64
65    def __setitem__(self, key: str, value: Any) -> None:
66        self.additional_properties[key] = value
67
68    def __delitem__(self, key: str) -> None:
69        del self.additional_properties[key]
70
71    def __contains__(self, key: str) -> bool:
72        return key in self.additional_properties

Connection details for a MoQ relay client

Attributes:

  • connection_url (str): Relay connection URL with the JWT embedded as a ?jwt= query parameter. Pass directly to a MoQ client SDK. Example: https://relay.fishjam.io/abc123?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....
  • token (str): JWT authorizing the MoQ relay connection, also embedded in connection_url Example: eyJhbGciOiJIUz I1NiIsInR5cCI6IkpXVCJ9.eyJyb290IjoiZmlzaGphbSIsInB1dCI6WyJteS1zdHJlYW0iXSwiZ2V0IjpbXSwiaWF0IjoxNzEzMzYwMDAwLCJle HAiOjE3MTMzNjM2MDB9.abc123.
MoqAccess(connection_url: 'str', token: 'str')
25def __init__(self, connection_url, token):
26    self.connection_url = connection_url
27    self.token = token
28    self.additional_properties = __attr_factory_additional_properties()

Method generated by attrs for class MoqAccess.

connection_url: 'str'
token: 'str'
additional_properties: 'dict[str, Any]'
def to_dict(self) -> 'dict[str, Any]':
29    def to_dict(self) -> dict[str, Any]:
30        connection_url = self.connection_url
31
32        token = self.token
33
34        field_dict: dict[str, Any] = {}
35        field_dict.update(self.additional_properties)
36        field_dict.update({
37            "connection_url": connection_url,
38            "token": token,
39        })
40
41        return field_dict
@classmethod
def from_dict(cls: 'type[T]', src_dict: 'Mapping[str, Any]') -> 'T':
43    @classmethod
44    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
45        d = dict(src_dict)
46        connection_url = d.pop("connection_url")
47
48        token = d.pop("token")
49
50        moq_access = cls(
51            connection_url=connection_url,
52            token=token,
53        )
54
55        moq_access.additional_properties = d
56        return moq_access
additional_keys: 'list[str]'
58    @property
59    def additional_keys(self) -> list[str]:
60        return list(self.additional_properties.keys())
class MissingFishjamIdError(builtins.ValueError):
 8class MissingFishjamIdError(ValueError):
 9    def __init__(self) -> None:
10        super().__init__("Fishjam ID is required")

Inappropriate argument value (of correct type).

Inherited Members
builtins.BaseException
with_traceback
add_note
args
class InvalidFishjamCredentialsError(fishjam.errors.HTTPError):
80class InvalidFishjamCredentialsError(HTTPError):
81    def __init__(self, errors):
82        """@private"""
83        super().__init__(errors)
Inherited Members
builtins.BaseException
with_traceback
add_note
args