diff --git a/docs/explanation/livestreams.mdx b/docs/explanation/livestreams.mdx
index d0f7c5d9..3fd869bb 100644
--- a/docs/explanation/livestreams.mdx
+++ b/docs/explanation/livestreams.mdx
@@ -41,15 +41,15 @@ By default, created livestreams are `private`, to prevent possible bugs.
```python
- from fishjam import FishjamClient
+ from fishjam import FishjamClient, RoomOptions
fishjam_client = FishjamClient(
fishjam_id=fishjam_id,
management_token=management_token,
- );
+ )
- private_room = fishjam_client.create_room(room_type="livestream") # [!code highlight]
- public_room = fishjam_client.create_room(room_type="livestream", public=True) # [!code highlight]
+ private_room = fishjam_client.create_room(RoomOptions(room_type="livestream")) # [!code highlight]
+ public_room = fishjam_client.create_room(RoomOptions(room_type="livestream", public=True)) # [!code highlight]
```
@@ -93,14 +93,14 @@ Note that for development purposes, you can [use the Sandbox API to generate a v
```python
- from fishjam import FishjamClient
+ from fishjam import FishjamClient, RoomOptions
fishjam_client = FishjamClient(
fishjam_id=fishjam_id,
management_token=management_token,
- );
+ )
- private_room = fishjam_client.create_room(room_type="livestream")
+ private_room = fishjam_client.create_room(RoomOptions(room_type="livestream"))
viewer_token = fishjam_client.create_livestream_viewer_token(private_room.id) # [!code highlight]
```
diff --git a/docs/how-to/backend/fastapi-example.mdx b/docs/how-to/backend/fastapi-example.mdx
index dd886255..51869ac9 100644
--- a/docs/how-to/backend/fastapi-example.mdx
+++ b/docs/how-to/backend/fastapi-example.mdx
@@ -77,8 +77,9 @@ It doesn't interact with the FastAPI library per se, just start the event loop a
```python
import asyncio
from fishjam import FishjamNotifier
+from fishjam.events import ServerMessagePeerAdded
-notifier = FishjamNotifier(server_address=fishjam_id, server_api_token=management_token)
+notifier = FishjamNotifier(fishjam_id=fishjam_id, management_token=management_token)
@notifier.on_server_notification
def handle_notification(notification):
diff --git a/docs/how-to/backend/server-setup.mdx b/docs/how-to/backend/server-setup.mdx
index 8d303cba..356c9d72 100644
--- a/docs/how-to/backend/server-setup.mdx
+++ b/docs/how-to/backend/server-setup.mdx
@@ -276,6 +276,7 @@ It sets up a websocket connection with a Fishjam instance and provides a simple
```python
import asyncio
from fishjam import FishjamNotifier
+ from fishjam.events import ServerMessageRoomCreated
notifier = FishjamNotifier(fishjam_id, management_token)
diff --git a/docs/how-to/backend/whip-whep.mdx b/docs/how-to/backend/whip-whep.mdx
index 8c3ef4e4..a5b61c6c 100644
--- a/docs/how-to/backend/whip-whep.mdx
+++ b/docs/how-to/backend/whip-whep.mdx
@@ -71,14 +71,14 @@ You can read about this in detail in [Production Livestreaming with Server SDKs]
```python
- from fishjam import FishjamClient
+ from fishjam import FishjamClient, RoomOptions
fishjam_client = FishjamClient(
fishjam_id=fishjam_id,
management_token=management_token,
- );
+ )
- room = fishjam_client.create_room(room_type="livestream")
+ room = fishjam_client.create_room(RoomOptions(room_type="livestream"))
streamer_token = fishjam_client.create_livestream_streamer_token(room.id) # [!code highlight]
```
@@ -150,14 +150,14 @@ You can read about this in detail in [Production Livestreaming with Server SDKs]
```python
- from fishjam import FishjamClient
+ from fishjam import FishjamClient, RoomOptions
fishjam_client = FishjamClient(
fishjam_id=fishjam_id,
management_token=management_token,
- );
+ )
- room = fishjam_client.create_room(room_type="livestream", public=False)
+ room = fishjam_client.create_room(RoomOptions(room_type="livestream", public=False))
# ...
diff --git a/docs/integrations/gemini-live-integration.mdx b/docs/integrations/gemini-live-integration.mdx
index 33518a1e..bc0f138f 100644
--- a/docs/integrations/gemini-live-integration.mdx
+++ b/docs/integrations/gemini-live-integration.mdx
@@ -227,50 +227,53 @@ Fishjam handles raw bytes, while Google GenAI SDKs often expect Base64 strings.
Now we connect the websocket loops. We need to forward incoming Fishjam audio to Google, and forward incoming Google audio to Fishjam.
```python
import asyncio
- from fishjam.integrations.gemini import GeminiIntegration
from google.genai.types import Blob, Modality
+ from fishjam.integrations.gemini import GeminiIntegration
GEMINI_MODEL = "gemini-2.5-flash-native-audio-preview-12-2025"
- async with agent.connect() as fishjam_session:
-
- # Use our preset to match the required audio format (24kHz)
- outgoing_track = await fishjam_session.add_track(GeminiIntegration.GEMINI_OUTPUT_AUDIO_SETTINGS)
-
- async with gen_ai.aio.live.connect(
- model=GEMINI_MODEL,
- config={"response_modalities": [Modality.AUDIO]}
- ) as gemini_session:
-
- # Fishjam -> Google
- async def forward_audio_to_gemini():
- async for track_data in fishjam_session.receive():
- await gemini_session.send_realtime_input(audio=Blob(
- mime_type=GeminiIntegration.GEMINI_AUDIO_MIME_TYPE,
- data=track_data.data
- ))
-
- # Google -> Fishjam
- async def forward_audio_to_fishjam():
- async for msg in gemini_session.receive():
- server_content = msg.server_content
-
- if server_content is None:
- continue
-
- if server_content.interrupted:
- await outgoing_track.interrupt()
-
- if server_content.model_turn and server_content.model_turn.parts:
- for part in server_content.model_turn.parts:
- if part.inline_data and part.inline_data.data:
- await outgoing_track.send_chunk(part.inline_data.data)
-
- # Run both loops concurrently
- await asyncio.gather(
- forward_audio_to_gemini(),
- forward_audio_to_fishjam()
- )
+ async def run():
+ async with agent.connect() as fishjam_session:
+
+ # Use our preset to match the required audio format (24kHz)
+ outgoing_track = await fishjam_session.add_track(GeminiIntegration.GEMINI_OUTPUT_AUDIO_SETTINGS)
+
+ async with gen_ai.aio.live.connect(
+ model=GEMINI_MODEL,
+ config={"response_modalities": [Modality.AUDIO]}
+ ) as gemini_session:
+
+ # Fishjam -> Google
+ async def forward_audio_to_gemini():
+ async for track_data in fishjam_session.receive():
+ await gemini_session.send_realtime_input(audio=Blob(
+ mime_type=GeminiIntegration.GEMINI_AUDIO_MIME_TYPE,
+ data=track_data.data
+ ))
+
+ # Google -> Fishjam
+ async def forward_audio_to_fishjam():
+ async for msg in gemini_session.receive():
+ server_content = msg.server_content
+
+ if server_content is None:
+ continue
+
+ if server_content.interrupted:
+ await outgoing_track.interrupt()
+
+ if server_content.model_turn and server_content.model_turn.parts:
+ for part in server_content.model_turn.parts:
+ if part.inline_data and part.inline_data.data:
+ await outgoing_track.send_chunk(part.inline_data.data)
+
+ # Run both loops concurrently
+ await asyncio.gather(
+ forward_audio_to_gemini(),
+ forward_audio_to_fishjam()
+ )
+
+ asyncio.run(run())
```
diff --git a/docs/integrations/vapi-integration.mdx b/docs/integrations/vapi-integration.mdx
index 397bed25..c8684887 100644
--- a/docs/integrations/vapi-integration.mdx
+++ b/docs/integrations/vapi-integration.mdx
@@ -50,7 +50,7 @@ You will need:
```bash
- pip install fishjam-server-sdk vapi
+ pip install fishjam-server-sdk vapi_server_sdk
```
diff --git a/docs/tutorials/agents.mdx b/docs/tutorials/agents.mdx
index aa751d6f..9087dc0a 100644
--- a/docs/tutorials/agents.mdx
+++ b/docs/tutorials/agents.mdx
@@ -108,19 +108,23 @@ However, it's likely that in your scenario you'll want to use the [Selective Sub
```python
- from fishjam import FishjamClient
- from fishjam.agent import AgentResponseTrackData
+ import asyncio
+ from fishjam import FishjamClient, AgentOptions
+ from fishjam.agent import IncomingTrackData
fishjam_client = FishjamClient(fishjam_id, management_token)
agent_options = AgentOptions(subscribe_mode="auto")
- agent = fishjam_client.create_agent(room_id)
+ agent = fishjam_client.create_agent(room_id, agent_options)
- # the agent will disconnect once you exit the context
- async with agent.connect() as session:
- async for track_data in session.receive():
- # process the incoming data
- pass
+ async def run():
+ # the agent will disconnect once you exit the context
+ async with agent.connect() as session:
+ async for track_data in session.receive():
+ # process the incoming data
+ pass
+
+ asyncio.run(run())
```
@@ -239,28 +243,33 @@ You can interrupt the currently played audio chunk. See the example below.
```python
- from fishjam import FishjamClient
- from fishjam.agent import AgentResponseTrackData, OutgoingAudioTrackOptions, TrackEncoding
+ import asyncio
+ from fishjam import FishjamClient, AgentOptions
+ from fishjam.agent import OutgoingAudioTrackOptions
+ from fishjam.events import TrackEncoding
fishjam_client = FishjamClient(fishjam_id, management_token)
agent_options = AgentOptions(subscribe_mode="auto")
- agent = fishjam_client.create_agent(room_id)
+ agent = fishjam_client.create_agent(room_id, agent_options)
+
+ track_options = OutgoingAudioTrackOptions(encoding=TrackEncoding.TRACK_ENCODING_PCM16)
- track_options = OutgoingAudioTrackOptions(encoding=TrackEncoding.PCM16)
+ async def run():
+ # the agent will disconnect once you exit the context
+ async with agent.connect() as session:
+ outgoing_track = await session.add_track(track_options)
- # the agent will disconnect once you exit the context
- async with agent.connect() as session:
- outgoing_track = session.create_track(track_options)
+ # that's a dummy chatbot
+ async for chatbot_data in chatbot.receive():
+ await outgoing_track.send_chunk(chatbot_data)
- # that's a dummy chatbot
- async for chatbot_data in chatbot.receive():
- outgoing_track.send_chunk(chatbot_data)
+ # you're able to interrupt the currently played audio chunk
+ # [!code highlight:1]
+ await outgoing_track.interrupt()
- # you're able to interrupt the currently played audio chunk
- # [!code highlight:1]
- ongoing_track.interrupt()
+ asyncio.run(run())
```
@@ -321,18 +330,21 @@ Video frame capture is rate-limited to one frame per second per track.
agent = fishjam_client.create_agent(room_id)
- async with agent.connect() as session:
- # Request a frame
- # [!code highlight:1]
- await session.capture_image(track_id)
-
- # Captured frames arrive as IncomingTrackImage messages
- async for message in session.receive():
- match message:
- case IncomingTrackImage() as msg if msg.track_id == track_id:
- data = msg.data
- # process the image data
- pass
+ async def run():
+ async with agent.connect() as session:
+ # Request a frame
+ # [!code highlight:1]
+ await session.capture_image(track_id)
+
+ # Captured frames arrive as IncomingTrackImage messages
+ async for message in session.receive():
+ match message:
+ case IncomingTrackImage() as msg if msg.track_id == track_id:
+ data = msg.data
+ # process the image data
+ pass
+
+ asyncio.run(run())
```
@@ -365,9 +377,14 @@ After you're done using an agent, you can disconnect it from the room.
```python
- # the agent will disconnect once you exit the context
- async with agent.connect() as session:
- pass
+ import asyncio
+
+ async def run():
+ # the agent will disconnect once you exit the context
+ async with agent.connect() as session:
+ pass
+
+ asyncio.run(run())
```
diff --git a/docs/tutorials/backend-quick-start.mdx b/docs/tutorials/backend-quick-start.mdx
index 0c423d2b..a711f38b 100644
--- a/docs/tutorials/backend-quick-start.mdx
+++ b/docs/tutorials/backend-quick-start.mdx
@@ -354,6 +354,7 @@ Build a simple HTTP endpoint that your client apps can call:
```python
import os
from fastapi import FastAPI, HTTPException
+ from pydantic import BaseModel
from fishjam import FishjamClient, PeerOptions
app = FastAPI()
diff --git a/docs/tutorials/livestreaming.mdx b/docs/tutorials/livestreaming.mdx
index a1cca7af..eb80db0d 100644
--- a/docs/tutorials/livestreaming.mdx
+++ b/docs/tutorials/livestreaming.mdx
@@ -429,15 +429,15 @@ Our backend needs to do three things to be ready for streaming:
```python
- from fishjam import FishjamClient
+ from fishjam import FishjamClient, RoomOptions
fishjam_client = FishjamClient(
fishjam_id=fishjam_id,
management_token=management_token,
- );
+ )
# 1.
- room = fishjam_client.create_room(room_type="livestream")
+ room = fishjam_client.create_room(RoomOptions(room_type="livestream"))
# 2.
streamer_token = fishjam_client.create_livestream_streamer_token(room.id)
# 3.
diff --git a/scripts/prepare.sh b/scripts/prepare.sh
index 12a8fb52..bee5f0ac 100755
--- a/scripts/prepare.sh
+++ b/scripts/prepare.sh
@@ -7,8 +7,8 @@ echo $ROOTDIR
cd $ROOTDIR
printf "Synchronising submodules... "
-git submodule sync >>/dev/null
-git submodule update --init --remote >>/dev/null
+git submodule sync --recursive >>/dev/null
+git submodule update --init --recursive >>/dev/null
# cd packages/web-client-sdk/
# yarn && yarn build