Skip to main content

Tryx

PyPI version Python License Docs

Language: English | 简体中文 | Bahasa Indonesia

Tryx is a Python automation library powered by Rust and PyO3. It provides a Python-friendly API on top of the whatsapp-rust crate, with async support, persistent sessions, and access to advanced WhatsApp Web protocol features.

Tryx is an independent project. It is not affiliated with WhatsApp, Meta, or their official products.


English

What Is Tryx?

Tryx helps Python developers build WhatsApp automation tools without writing Rust directly. The core protocol logic runs in Rust for performance, while the public interface stays ergonomic for Python applications.

Use Tryx when you need:

  • WhatsApp Web automation from Python.
  • Persistent login sessions with SQLite, PostgreSQL, or MySQL.
  • Async APIs for bots, workers, dashboards, and internal tools.
  • Access to contacts, groups, newsletters, status, privacy, profile, labels, comments, events, and lower-level protocol helpers.

Highlights

  • Rust core, Python API - protocol logic is implemented in Rust and exposed through PyO3.
  • Async first - designed for asyncio applications.
  • Persistent sessions - reuse device sessions through a database-backed store.
  • Broad API surface - exposes common and advanced client namespaces.
  • Typed Python stubs - includes .pyi files for better editor support.

Installation

pip install tryx

For local development:

git clone https://github.com/krypton-byte/tryx.git
cd tryx
git submodule update --init --recursive
uv sync --group dev
uv run maturin develop

Quick Start

import asyncio

from tryx.backend import SqliteStore
from tryx.client import Tryx, TryxClient
from tryx.events import EvMessage, EvPairingQrCode

backend = SqliteStore("whatsapp.db")
app = Tryx(backend)


@app.on(EvPairingQrCode)
async def on_pairing_qr(_client: TryxClient, event: EvPairingQrCode) -> None:
    print("Scan this QR code with WhatsApp:")
    print(event.code)


@app.on(EvMessage)
async def on_message(client: TryxClient, event: EvMessage) -> None:
    text = (event.data.get_text() or "").strip()
    if text.lower() == "ping":
        await client.send_text(event.data.message_info.source.chat, "pong", quoted=event)


async def main() -> None:
    await app.run()


asyncio.run(main())

Runtime Client Namespaces

The runtime TryxClient object exposes several namespaces so the API stays organized:

Namespace Purpose
contact Contact lookup and contact-related helpers.
chat_actions Chat utilities such as mute, archive, pin, mark read, clear chat, and save contact.
groups Group creation, metadata, members, invites, membership requests, and admin settings.
community Community-related operations.
newsletter Newsletter info, messages, mute settings, edits, and revoke operations.
status Status posting, lookup, and related helpers.
chatstate Typing, recording, paused, and presence-style chat state updates.
blocking Block and unblock contacts.
polls Poll creation and voting helpers.
presence Presence subscriptions and availability updates.
privacy Privacy settings and related controls.
profile Profile name, status text, and picture operations.
labels Label management for chats and messages.
comments Comment-related protocol helpers.
events Event response helpers and event-oriented operations.
advanced Lifecycle waits, diagnostics, and lower-level protocol escape hatches.

Storage Backends

Tryx supports three storage tiers:

Tier Backend Use case
Built-in SqliteStore("whatsapp.db") Local development and simple deployments.
Native FFI FfiStoreProtocol High-throughput external stores such as PostgreSQL.
Pure Python StoreBase subclass Custom async stores such as Redis, MongoDB, or DynamoDB.

SQLite is usually enough for local development. Native FFI or a custom Python backend is better when several workers or deployment environments need shared session state.

VoIP: Audio and Video Calls

Tryx provides a Rust-backed bridge for WhatsApp audio and video calls. After the client is connected, use client.voip. Protocol handling, RTP/WebRTC, encryption, codecs, and call orchestration run in whatsapp-rust; Python supplies media through asynchronous source and sink adapters.

Features

  • One-to-one audio calls through voip.call().
  • One-to-one video calls through voip.video_call().
  • Group calls with optional video through voip.group_call().
  • Call-link joining through voip.join_call_link() with audio or video media.
  • Hangup, wait, mute/unmute, video, participant, approval, and screen-sharing controls.
  • Native Rust playback for WAV, MP3, OGG, Vorbis, and PCM audio files.
  • Native FFmpeg playback producing H.264 Annex-B video access units.
  • Python adapters for microphones, speakers, cameras, codecs, TTS, DSP, and custom pipelines.

Media Contract

Media Kontrak
Audio Mono signed PCM16 little-endian, 16,000 Hz, 960 samples / 1,920 bytes per frame, 60 ms
Video H.264 Annex-B access unit represented by VideoFrame

AudioSource.frames() must yield exactly 1,920 bytes per frame. AudioSink.write() receives the same format. VideoFrame carries data, timestamp_us, duration_us, keyframe, optional dimensions, and orientation.

Minimal Audio Adapters

from collections.abc import AsyncIterator
from tryx.media import AudioSink, AudioSource, validate_audio_frame
class Microphone(AudioSource):
    async def frames(self) -> AsyncIterator[bytes]:
        while True:
            frame = await read_microphone_frame()
            yield validate_audio_frame(frame)
class Speaker(AudioSink):
    async def write(self, frame: bytes) -> None:
        validate_audio_frame(frame)
        await play_speaker_frame(frame)

Replace the two backend functions with PyAudio, sounddevice, ALSA, CoreAudio, or another device library.

One-to-One Audio Call

from tryx.types import JID
async def start_audio_call(client, phone_number: str):
    peer = JID(phone_number + "@s.whatsapp.net")
    call = await client.voip.call(peer, Microphone(), Speaker())
    print("call started:", call.call_id)
    call.set_muted(True)
    call.set_muted(False)
    await call.wait_ended()

Use await call.hangup() to end a call explicitly. Keep the CallHandle alive and await wait_ended() for deterministic cleanup.

Video Call

from tryx.media import VideoPlayer
async def start_video_call(client, peer, video_sink):
    video_source = VideoPlayer(fps=15)
    video_source.play("sample.mp4")
    call = await client.voip.video_call(
        peer, Microphone(), Speaker(), video_source, video_sink
    )
    await call.wait_ended()
    video_source.stop()

VideoPlayer accepts 1–60 FPS and defaults to 15. FFmpeg must be in PATH; missing files and missing FFmpeg produce explicit errors.

Group Calls and Call Links

call = await client.voip.group_call(
    peers=[peer_a, peer_b],
    audio_source=Microphone(),
    audio_sink=Speaker(),
)
await call.invite_participant(peer_c)
await call.ring_participant(peer_c)
await call.set_approval_required(True)
linked = await client.voip.join_call_link(
    "https://call.whatsapp.com/your-token",
    "audio",
    Microphone(),
    Speaker(),
)

group_call() accepts optional video source/sink pairs. join_call_link() accepts a token or URL and media audio or video.

Incoming Calls

IncomingCallEvent exposes call_id, peer, is_video, accept(audio_source, audio_sink), and reject(). Accept or reject it only once because the invitation is consumed.

@app.on(EvIncomingCall)
async def on_incoming_call(_client, event):
    if event.is_video:
        await event.reject()
        return
    call = await event.accept(Microphone(), Speaker())
    await call.wait_ended()

Use the incoming-call event exported by the installed package version.

Native AudioPlayer

AudioPlayer decodes files in Rust and normalizes them to mono PCM16 at 16 kHz.

from tryx.media import AudioPlayer
player = AudioPlayer(buffer_frames=3)
player.play("intro.mp3", mode="replace")
call = await client.voip.call(peer, player, Speaker())
player.pause()
player.resume()
player.enqueue("next.wav")
player.skip()
player.clear_queue()
player.stop()

Modes are replace, queue, and interrupt. buffer_frames defaults to 3 and is capped at 30. States are idle, playing, and paused; non-16 kHz audio uses linear interpolation.

Internal Data Flow and Backpressure

Python source/sink -> PyO3 bridge + bounded async channel
                    -> whatsapp-rust VoIP facade
                    -> WaCore call engine -> RTP/SRTP/WebRTC
                    -> WhatsApp call network

Inbound media follows the reverse path: transport decrypts and decodes, the bridge creates PCM16 or VideoFrame, and the Python sink receives it. Bounded channels prevent unbounded queues; audio defaults to three frames, about 180 ms before network and codec overhead. Slow sinks cause asynchronous backpressure instead of CPU spin-waiting.

Audio commands wait for the manager result and propagate errors to Python. VideoPlayer.stop() cancels its FFmpeg task, which kills and reaps the child process instead of leaving an orphan.

Lifecycle and Troubleshooting

  • Start calls only after Tryx is connected; use one native player per active call.
  • Stop players when cancelling a call and release them after wait_ended().
  • Send only mono PCM16 16 kHz frames of exactly 1,920 bytes.
  • Video sources must emit H.264 Annex-B, not an MP4 container.
  • For invalid audio sizes, chunk or resample into 960 samples.
  • For high latency, use buffer_frames=2 or 3.
  • Install FFmpeg and verify it with ffmpeg -version when video playback fails.

Development

Useful commands:

cargo check
cargo test --lib
env UV_CACHE_DIR=/tmp/uv-cache uv run pytest -q
uv run maturin develop
uv run maturin build --release

Project layout:

.
├── libs/whatsapp-rust/   # Rust protocol crate submodule
├── src/                  # Rust and PyO3 bindings
├── python/tryx/          # Python package and type stubs
├── examples/             # Example automation scripts
├── docs/                 # Documentation site
└── tests/                # Python test suite

Links


简体中文

Tryx 是什么?

Tryx 是一个基于 Rust 和 PyO3 的 Python WhatsApp 自动化库。底层协议能力来自 whatsapp-rust crate,Python 侧提供更易用的异步 API,适合构建机器人、后台任务、内部工具和自动化服务。

Tryx 适合以下场景:

  • 使用 Python 操作 WhatsApp Web。
  • 通过 SQLite、PostgreSQL 或 MySQL 持久化登录会话。
  • asyncio 项目中构建机器人或自动化流程。
  • 使用联系人、群组、频道、状态、隐私、资料、标签、评论、事件和高级协议能力。

主要特点

  • Rust 核心,Python 调用 - 协议逻辑在 Rust 中运行,Python 通过 PyO3 调用。
  • 异步优先 - 适合 asyncio 应用。
  • 会话持久化 - 可以复用已登录的 WhatsApp 设备会话。
  • API 覆盖面更广 - 暴露常用功能和高级功能命名空间。
  • 类型提示支持 - 提供 .pyi 文件,提升编辑器补全体验。

安装

pip install tryx

本地开发:

git clone https://github.com/krypton-byte/tryx.git
cd tryx
git submodule update --init --recursive
uv sync --group dev
uv run maturin develop

快速开始

import asyncio

from tryx.backend import SqliteStore
from tryx.client import Tryx, TryxClient
from tryx.events import EvMessage, EvPairingQrCode

backend = SqliteStore("whatsapp.db")
app = Tryx(backend)


@app.on(EvPairingQrCode)
async def on_pairing_qr(_client: TryxClient, event: EvPairingQrCode) -> None:
    print("Scan this QR code with WhatsApp:")
    print(event.code)


@app.on(EvMessage)
async def on_message(client: TryxClient, event: EvMessage) -> None:
    text = (event.data.get_text() or "").strip()
    if text.lower() == "ping":
        await client.send_text(event.data.message_info.source.chat, "pong", quoted=event)


async def main() -> None:
    await app.run()


asyncio.run(main())

Client 命名空间

运行时 TryxClient 对象按功能拆分为多个命名空间:

命名空间 用途
contact 联系人查询和联系人相关工具。
chat_actions 聊天操作,例如静音、归档、置顶、标记已读、清空聊天和保存联系人。
groups 群组创建、信息、成员、邀请、入群请求和管理员设置。
community 社区相关操作。
newsletter 频道信息、消息、静音设置、编辑和撤回。
status 状态发布、查询和相关工具。
chatstate 输入中、录音中、暂停等聊天状态。
blocking 拉黑和取消拉黑联系人。
polls 投票创建和投票操作。
presence 在线状态订阅和可用性更新。
privacy 隐私设置和控制。
profile 资料名称、状态文本和头像操作。
labels 聊天和消息标签管理。
comments 评论相关协议工具。
events 事件响应和事件相关操作。
advanced 生命周期等待、诊断和更底层的协议能力。

存储后端

Tryx 支持三种会话存储方式:

类型 后端 使用场景
内置 SqliteStore("whatsapp.db") 本地开发和简单部署。
Native FFI FfiStoreProtocol 高吞吐外部存储,例如 PostgreSQL。
纯 Python StoreBase 子类 自定义异步存储,例如 Redis、MongoDB 或 DynamoDB。

本地开发通常使用 SQLite 即可。如果多个 worker 或部署环境需要共享会话状态,建议使用 Native FFI 或自定义 Python 后端。

VoIP:音频和视频通话

Tryx 提供基于 Rust 的 WhatsApp 音频和视频通话桥接层。客户端连接后,可以通过 client.voip 使用 API。协议处理、RTP/WebRTC、加密、编解码器和通话编排由 whatsapp-rust 执行;Python 通过异步 source 和 sink adapter 提供媒体数据。

功能

  • 使用 voip.call() 发起一对一音频通话。
  • 使用 voip.video_call() 发起一对一视频通话。
  • 使用 voip.group_call() 发起带可选视频的群组通话。
  • 使用 voip.join_call_link() 加入音频或视频 call link。
  • 支持挂断、等待结束、静音/取消静音、开始/停止视频。
  • 支持邀请、响铃、参与者审批,以及允许或拒绝等待中的用户。
  • 支持 start_screen_share() 和 stop_screen_share() 屏幕共享。
  • Rust 原生播放 WAV、MP3、OGG、Vorbis 和 PCM 音频文件。
  • 通过 FFmpeg 原生播放视频并输出 H.264 Annex-B access unit。
  • 支持用于麦克风、扬声器、摄像头、编解码器、TTS、DSP 和自定义媒体管线的 Python adapter。

媒体契约

媒体 契约
音频 单声道 signed PCM16 little-endian,16,000 Hz,每帧 960 个 sample / 1,920 字节,60 ms
视频 通过 VideoFrame 表示的 H.264 Annex-B access unit

AudioSource.frames() 必须每次产生恰好 1,920 字节。AudioSink.write() 接收相同的 PCM 格式。VideoFrame 包含 data、timestamp_us、duration_us、keyframe、可选的 width 和 height,以及 orientation。

最小音频 Adapter

from collections.abc import AsyncIterator
from tryx.media import AudioSink, AudioSource, validate_audio_frame
class Microphone(AudioSource):
    async def frames(self) -> AsyncIterator[bytes]:
        while True:
            frame = await read_microphone_frame()
            yield validate_audio_frame(frame)
class Speaker(AudioSink):
    async def write(self, frame: bytes) -> None:
        validate_audio_frame(frame)
        await play_speaker_frame(frame)

请将两个设备函数替换为 PyAudio、sounddevice、ALSA、CoreAudio 或其他音频设备库的实现。

一对一音频通话

from tryx.types import JID
async def start_audio_call(client, phone_number: str):
    peer = JID(phone_number + "@s.whatsapp.net")
    call = await client.voip.call(peer, Microphone(), Speaker())
    print("call started:", call.call_id)
    call.set_muted(True)
    call.set_muted(False)
    await call.wait_ended()

使用 await call.hangup() 主动结束通话。通话期间请保持 CallHandle,并等待 wait_ended(),以便媒体资源能够稳定清理。

视频通话

from tryx.media import VideoPlayer
async def start_video_call(client, peer, video_sink):
    video_source = VideoPlayer(fps=15)
    video_source.play("sample.mp4")
    call = await client.voip.video_call(
        peer, Microphone(), Speaker(), video_source, video_sink
    )
    await call.wait_ended()
    video_source.stop()

VideoPlayer 支持 1–60 FPS,默认值为 15。系统必须在 PATH 中提供 FFmpeg;文件不存在或 FFmpeg 不可用时,play() 会返回明确错误。

群组通话和 Call Link

call = await client.voip.group_call(
    peers=[peer_a, peer_b],
    audio_source=Microphone(),
    audio_sink=Speaker(),
)
await call.invite_participant(peer_c)
await call.ring_participant(peer_c)
await call.set_approval_required(True)
linked = await client.voip.join_call_link(
    "https://call.whatsapp.com/your-token",
    "audio",
    Microphone(),
    Speaker(),
)

group_call() 可以接收可选的 video source/sink。join_call_link() 可以接收 token 或 URL,并使用 media="audio" 或 media="video"。

来电

IncomingCallEvent 提供 call_id、peer、is_video、accept(audio_source, audio_sink) 和 reject()。一个 event 只能 accept 或 reject 一次,因为底层来电邀请在操作后会被消费。

@app.on(EvIncomingCall)
async def on_incoming_call(_client, event):
    if event.is_video:
        await event.reject()
        return
    call = await event.accept(Microphone(), Speaker())
    await call.wait_ended()

请使用当前安装版本导出的来电 event 名称。

Rust 原生 AudioPlayer

AudioPlayer 在 Rust 中解码文件,并将其标准化为 16 kHz 单声道 PCM16。

from tryx.media import AudioPlayer
player = AudioPlayer(buffer_frames=3)
player.play("intro.mp3", mode="replace")
call = await client.voip.call(peer, player, Speaker())
player.pause()
player.resume()
player.enqueue("next.wav")
player.skip()
player.clear_queue()
player.stop()

播放模式为 replace、queue 和 interrupt。buffer_frames 默认 3,最大限制为 30。播放器状态为 idle、playing 和 paused。非 16 kHz 音频使用线性插值转换。

内部数据流和背压

Python source/sink -> PyO3 bridge + bounded async channel
                    -> whatsapp-rust VoIP facade
                    -> WaCore call engine -> RTP/SRTP/WebRTC
                    -> WhatsApp call network

接收媒体沿反方向流动:transport 解密并解码,bridge 将数据转换为 PCM16 或 VideoFrame,再交给 Python sink。bounded channel 防止队列无限增长;音频默认缓存 3 帧,即在网络和 codec 开销之前约 180 ms。sink 较慢时 producer 会异步等待,而不是消耗 CPU 自旋等待。

AudioPlayer command 会等待 manager 的结果,并将错误传递给 Python。VideoPlayer.stop() 会取消 FFmpeg task,由该 task kill 并回收 child process,避免留下孤儿进程。

生命周期和故障排查

  • 只有在 Tryx 连接成功后才开始通话;每个活动通话使用一个 native player。
  • 取消通话时停止 player,并在 wait_ended() 后释放资源。
  • 只能发送恰好 1,920 字节的单声道 PCM16 16 kHz 音频帧。
  • 视频 source 必须输出 H.264 Annex-B,不能直接输出 MP4 container。
  • 音频尺寸错误时,将音频切分或重采样为 960 samples。
  • 延迟过高时使用 buffer_frames=2 或 3。
  • 视频播放失败时安装 FFmpeg,并使用 ffmpeg -version 验证 PATH。

开发命令

cargo check
cargo test --lib
env UV_CACHE_DIR=/tmp/uv-cache uv run pytest -q
uv run maturin develop
uv run maturin build --release

相关链接


Bahasa Indonesia

Apa Itu Tryx?

Tryx adalah library otomasi WhatsApp untuk Python yang dibangun dengan Rust dan PyO3. Logika protokol berjalan di Rust melalui whatsapp-rust, sedangkan API publiknya dibuat agar nyaman digunakan dari Python.

Tryx cocok untuk:

  • Membuat otomasi WhatsApp Web dari Python.
  • Menyimpan sesi login dengan SQLite, PostgreSQL, atau MySQL.
  • Membangun bot, worker, dashboard, dan tool internal berbasis asyncio.
  • Mengakses fitur kontak, grup, newsletter, status, privasi, profil, label, komentar, event, dan helper protokol tingkat lanjut.

Fitur Utama

  • Core Rust, API Python - performa dan logika protokol ditangani Rust, pemakaian tetap sederhana dari Python.
  • Async first - dirancang untuk aplikasi asyncio.
  • Sesi persisten - sesi WhatsApp dapat dipakai ulang melalui database.
  • API luas - namespace umum dan advanced sudah diexpose.
  • Type stub Python - tersedia .pyi untuk autocomplete dan type checking yang lebih baik.

Instalasi

pip install tryx

Untuk development lokal:

git clone https://github.com/krypton-byte/tryx.git
cd tryx
git submodule update --init --recursive
uv sync --group dev
uv run maturin develop

Mulai Cepat

import asyncio

from tryx.backend import SqliteStore
from tryx.client import Tryx, TryxClient
from tryx.events import EvMessage, EvPairingQrCode

backend = SqliteStore("whatsapp.db")
app = Tryx(backend)


@app.on(EvPairingQrCode)
async def on_pairing_qr(_client: TryxClient, event: EvPairingQrCode) -> None:
    print("Scan this QR code with WhatsApp:")
    print(event.code)


@app.on(EvMessage)
async def on_message(client: TryxClient, event: EvMessage) -> None:
    text = (event.data.get_text() or "").strip()
    if text.lower() == "ping":
        await client.send_text(event.data.message_info.source.chat, "pong", quoted=event)


async def main() -> None:
    await app.run()


asyncio.run(main())

Namespace Client

Objek runtime TryxClient dibagi menjadi beberapa namespace agar API lebih rapi:

Namespace Fungsi
contact Helper untuk kontak dan pencarian kontak.
chat_actions Operasi chat seperti mute, archive, pin, mark read, clear chat, dan save contact.
groups Pembuatan grup, metadata, member, invite, request membership, dan pengaturan admin.
community Operasi terkait komunitas.
newsletter Info newsletter, pesan, mute, edit, dan revoke.
status Posting status, lookup status, dan helper terkait status.
chatstate State chat seperti typing, recording, dan paused.
blocking Block dan unblock kontak.
polls Membuat poll dan mengirim vote.
presence Subscribe presence dan update availability.
privacy Pengaturan privasi.
profile Nama profil, status teks, dan foto profil.
labels Manajemen label untuk chat dan pesan.
comments Helper protokol terkait komentar.
events Helper response dan operasi berbasis event.
advanced Wait lifecycle, diagnostik, dan akses protokol tingkat lanjut.

Storage Backend

Tryx mendukung tiga tipe storage untuk menyimpan sesi WhatsApp:

Tipe Backend Kegunaan
Built-in SqliteStore("whatsapp.db") Development lokal dan deployment sederhana.
Native FFI FfiStoreProtocol Store eksternal throughput tinggi seperti PostgreSQL.
Pure Python subclass StoreBase Store async custom seperti Redis, MongoDB, atau DynamoDB.

SQLite cukup untuk development lokal. Native FFI atau backend Python custom lebih cocok jika sesi perlu dipakai bersama oleh beberapa worker atau environment deployment.

VoIP: Panggilan Audio dan Video

Tryx menyediakan bridge VoIP berbasis Rust untuk panggilan audio dan video WhatsApp. Setelah client tersambung, API tersedia melalui client.voip. Protocol, RTP/WebRTC, enkripsi, codec, dan orkestrasi call berjalan di whatsapp-rust; Python menyediakan media melalui adapter source dan sink asynchronous.

Fitur

  • Panggilan audio 1:1 melalui voip.call().
  • Panggilan video 1:1 melalui voip.video_call().
  • Group call dengan video opsional melalui voip.group_call().
  • Bergabung ke call link melalui voip.join_call_link() dengan media audio atau video.
  • Kontrol hangup, wait, mute/unmute, video, peserta, approval, dan screen sharing.
  • Playback file audio native Rust untuk WAV, MP3, OGG, Vorbis, dan PCM.
  • Playback video native melalui FFmpeg dengan output H.264 Annex-B access unit.
  • Adapter Python untuk microphone, speaker, camera, codec, TTS, DSP, dan pipeline media custom.

Kontrak Media

Media Kontrak
Audio Mono signed PCM16 little-endian, 16.000 Hz, 960 sample / 1.920 byte per frame, 60 ms
Video H.264 Annex-B access unit melalui VideoFrame

AudioSource.frames() harus menghasilkan async iterator dengan tepat 1.920 byte untuk setiap frame. AudioSink.write() menerima format PCM yang sama. VideoFrame berisi data, timestamp_us, duration_us, keyframe, dimensi opsional, dan orientation.

Adapter Audio Minimal

    from collections.abc import AsyncIterator
    from tryx.media import AudioSink, AudioSource, validate_audio_frame

    class Microphone(AudioSource):
        async def frames(self) -> AsyncIterator[bytes]:
            while True:
                frame = await read_microphone_frame()
                yield validate_audio_frame(frame)

    class Speaker(AudioSink):
        async def write(self, frame: bytes) -> None:
            validate_audio_frame(frame)
            await play_speaker_frame(frame)

Ganti fungsi perangkat tersebut dengan implementasi PyAudio, sounddevice, ALSA, CoreAudio, atau library perangkat lain.

Panggilan Audio 1:1

    from tryx.types import JID

    async def start_audio_call(client, phone_number: str):
        peer = JID(phone_number + "@s.whatsapp.net")
        call = await client.voip.call(peer, Microphone(), Speaker())
        print("call started:", call.call_id)
        call.set_muted(True)
        call.set_muted(False)
        await call.wait_ended()

Gunakan await call.hangup() untuk mengakhiri call secara eksplisit. Pertahankan CallHandle selama call aktif dan tunggu wait_ended() agar cleanup media berjalan deterministik.

Panggilan Video

    from tryx.media import VideoPlayer

    async def start_video_call(client, peer, video_sink):
        video_source = VideoPlayer(fps=15)
        video_source.play("sample.mp4")
        call = await client.voip.video_call(
            peer, Microphone(), Speaker(), video_source, video_sink
        )
        await call.wait_ended()
        video_source.stop()

VideoPlayer mendukung 1–60 FPS dengan default 15. FFmpeg harus tersedia di PATH. File yang tidak ditemukan atau FFmpeg yang tidak tersedia akan menghasilkan error yang jelas.

Group Call dan Call Link

    call = await client.voip.group_call(
        peers=[peer_a, peer_b],
        audio_source=Microphone(),
        audio_sink=Speaker(),
    )
    await call.invite_participant(peer_c)
    await call.ring_participant(peer_c)
    await call.set_approval_required(True)

    linked = await client.voip.join_call_link(
        "https://call.whatsapp.com/your-token",
        "audio",
        Microphone(),
        Speaker(),
    )

group_call() menerima video source dan sink secara opsional. join_call_link() menerima token atau URL dengan media audio atau video.

Panggilan Masuk

IncomingCallEvent menyediakan call_id, peer, is_video, accept(audio_source, audio_sink), dan reject(). Event hanya boleh di-accept atau reject satu kali karena invitation akan dikonsumsi.

    @app.on(EvIncomingCall)
    async def on_incoming_call(_client, event):
        if event.is_video:
            await event.reject()
            return
        call = await event.accept(Microphone(), Speaker())
        await call.wait_ended()

Gunakan nama event incoming-call yang diexport oleh versi package yang terpasang.

AudioPlayer Native

AudioPlayer mendecode file di Rust dan menormalisasikannya menjadi mono PCM16 16 kHz.

    from tryx.media import AudioPlayer

    player = AudioPlayer(buffer_frames=3)
    player.play("intro.mp3", mode="replace")
    call = await client.voip.call(peer, player, Speaker())
    player.pause()
    player.resume()
    player.enqueue("next.wav")
    player.skip()
    player.clear_queue()
    player.stop()

Mode playback adalah replace, queue, dan interrupt. buffer_frames default 3 dan dibatasi maksimal 30 frame. State player adalah idle, playing, atau paused. Audio non-16 kHz diproses dengan interpolasi linear.

Alur Internal dan Backpressure

Python source/sink -> PyO3 bridge + bounded async channel
                    -> whatsapp-rust VoIP facade
                    -> WaCore call engine -> RTP/SRTP/WebRTC
                    -> WhatsApp call network

Media masuk berjalan terbalik: transport mendekripsi dan mendecode, bridge mengubahnya menjadi PCM16 atau VideoFrame, kemudian sink Python menerimanya. Bounded channel mencegah queue tumbuh tanpa batas. Buffer audio default 3 frame, sekitar 180 ms sebelum overhead jaringan dan codec. Jika sink lambat, producer menunggu secara asynchronous tanpa spin-wait CPU.

Command AudioPlayer menunggu hasil manager dan meneruskan error ke Python. VideoPlayer.stop() membatalkan task FFmpeg; task tersebut membunuh dan mereap child process agar tidak meninggalkan proses yatim.

Lifecycle dan Troubleshooting

  • Mulai call setelah Tryx tersambung dan gunakan satu native player untuk setiap call aktif.
  • Hentikan player saat call dibatalkan dan lepaskan setelah wait_ended().
  • Kirim hanya frame mono PCM16 16 kHz dengan ukuran tepat 1.920 byte.
  • Video source harus menghasilkan H.264 Annex-B, bukan MP4 container.
  • Jika ukuran audio salah, lakukan chunk atau resample menjadi 960 sample.
  • Jika latency tinggi, gunakan buffer_frames=2 atau 3.
  • Jika video gagal, instal FFmpeg dan verifikasi dengan ffmpeg -version.

Development

Command yang umum dipakai:

cargo check
cargo test --lib
env UV_CACHE_DIR=/tmp/uv-cache uv run pytest -q
uv run maturin develop
uv run maturin build --release

Struktur project:

.
├── libs/whatsapp-rust/   # Submodule crate protokol Rust
├── src/                  # Binding Rust dan PyO3
├── python/tryx/          # Package Python dan type stub
├── examples/             # Contoh script otomasi
├── docs/                 # Situs dokumentasi
└── tests/                # Test suite Python

Link Penting


License

This project is licensed under the terms of the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tryx-1.0.3.tar.gz (10.0 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

tryx-1.0.3-cp38-abi3-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.8+Windows x86-64

tryx-1.0.3-cp38-abi3-win32.whl (5.6 MB view details)

Uploaded CPython 3.8+Windows x86

tryx-1.0.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.6 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

tryx-1.0.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl (6.3 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ s390x

tryx-1.0.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl (6.7 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ i686

tryx-1.0.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.6 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

tryx-1.0.3-cp38-abi3-macosx_11_0_arm64.whl (5.7 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

tryx-1.0.3-cp38-abi3-macosx_10_12_x86_64.whl (6.0 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

tryx-1.0.3-cp38-abi3-android_24_x86_64.whl (6.7 MB view details)

Uploaded Android API level 24+ x86-64CPython 3.8+

tryx-1.0.3-cp38-abi3-android_24_arm64_v8a.whl (6.6 MB view details)

Uploaded Android API level 24+ ARM64 v8aCPython 3.8+

File details

Details for the file tryx-1.0.3.tar.gz.

File metadata

  • Download URL: tryx-1.0.3.tar.gz
  • Upload date:
  • Size: 10.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3.tar.gz
Algorithm Hash digest
SHA256 8ba9d789bcbb01fdc146889fcdb63562b79adce764b749eac66e9d70b2ca628c
MD5 e634fba993636d86be7af80371bd5d15
BLAKE2b-256 f8006c486d066f8e2b76e9cf26ce8eeceeb9e28c0a3df99d5f666a060ed74509

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 2a68809de714bf752a3ee2123209c20c4e08b679361f8cf8e11d2e8b20359906
MD5 849526db9fa34ab85a3ff7788ea9c744
BLAKE2b-256 8d61d3d23058645c13eaf13cea190c28d3d1ab23ce51e2a43fa6d91cd84d7a72

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-win32.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-win32.whl
  • Upload date:
  • Size: 5.6 MB
  • Tags: CPython 3.8+, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-win32.whl
Algorithm Hash digest
SHA256 4c8aefbe2710e23e1dbdb958d5bc8d5f5c18bcdc9723c30f1f10a40e1aa89e1d
MD5 d442183defeb5e01b736c871ca650f49
BLAKE2b-256 0f879d6320c6d378a12e26203a92b528e366dbec3b0c7fde6c4a990f08e8db5f

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 6.6 MB
  • Tags: CPython 3.8+, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 517b6a50c4ca2cf9d9b808068f5d710009aad8300600a172ff5fed62abdb3f4a
MD5 21aa1220849e86e9ab1ffd945ec6fab2
BLAKE2b-256 fc4c8ea0c093f05d603ac52f2f77d5939ede7892d574f4f9daa9bfd06acc309f

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
  • Upload date:
  • Size: 6.3 MB
  • Tags: CPython 3.8+, manylinux: glibc 2.17+ s390x
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 59a19cc69b92be44f3dbd10fc9b5e4aff15cab689aadf49385cd2deba7927a63
MD5 b0b9411782d677f640b8142727b32af5
BLAKE2b-256 a6944e06f024b97f9b21c8a068e3f35dda2116d68c06fd7df1b0775e8743f6bf

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl
  • Upload date:
  • Size: 6.7 MB
  • Tags: CPython 3.8+, manylinux: glibc 2.17+ i686
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 b573fb45f4a80940adbfa818b57cb9e5b7b9135cb600c7d53ac62ce2ea833153
MD5 18b1392cbc22218c92a269dcdf87f95a
BLAKE2b-256 06bc3d62ae5bd3a796c239fb164bbc8c0e50530a4025ec31eff025c2b07f9668

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
  • Upload date:
  • Size: 6.6 MB
  • Tags: CPython 3.8+, manylinux: glibc 2.17+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 69736f0fe1d5598972d88b61876eedb7daca9a8be6e6f10722832ca0a786db57
MD5 fa16da35d1d7d1326f6513ec923b8668
BLAKE2b-256 29b6529d0baa6701905d44e3e74ed2fc1fe2e9d217cf780f8b7278af02e9030f

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 5.7 MB
  • Tags: CPython 3.8+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ccc4e7da2f407b79588b2896733e8b42e0d71697823740721ff1f97440e19950
MD5 5289e8ed0680ef4363142c6f422b780d
BLAKE2b-256 c64dd4e69479510809b006598fdf5de338e9942c6b8c9e66340bb91f7e4563d8

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 6.0 MB
  • Tags: CPython 3.8+, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 336504f1664817fa770a92273670e845988b35174d8b037946bac96013c57310
MD5 7da6bd764b68e39d4ce2ff2b687f9ef8
BLAKE2b-256 31588544ea0b5725d63965d98a5a38cfb8753923449cc042a8ed0f79075753fd

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-android_24_x86_64.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-android_24_x86_64.whl
  • Upload date:
  • Size: 6.7 MB
  • Tags: Android API level 24+ x86-64, CPython 3.8+
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-android_24_x86_64.whl
Algorithm Hash digest
SHA256 b5784cd9c8b3db486b014a13659f15e28447b90dfde45f1e00faea5546fb11c7
MD5 9df034dff0f5e0c26478b4cb95c173f0
BLAKE2b-256 4cbbccffb19c2cc2a18c241e73de66d0d0390dd4c0fe3a815d15ed561f67466d

See more details on using hashes here.

File details

Details for the file tryx-1.0.3-cp38-abi3-android_24_arm64_v8a.whl.

File metadata

  • Download URL: tryx-1.0.3-cp38-abi3-android_24_arm64_v8a.whl
  • Upload date:
  • Size: 6.6 MB
  • Tags: Android API level 24+ ARM64 v8a, CPython 3.8+
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tryx-1.0.3-cp38-abi3-android_24_arm64_v8a.whl
Algorithm Hash digest
SHA256 5a04c8cd26fdc6e6cfec1e3b0a6abcfb5f7fe05218d715e401a7c82621a41023
MD5 e74fd1a536edb15a75d3375e0cb652c9
BLAKE2b-256 d46c67c72481f8be3b148f6e1e97be1c209815e9313a47557811b313a05a3589

See more details on using hashes here.

Release history Release notifications | RSS feed

1.1.1

11 files

This release

1.0.3 This release

11 files

0.6.4

32 files

0.6.3

32 files

0.5.1

32 files

0.4.0

32 files

0.3.0

94 files

0.2.0

11 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page