Call flows
WeChat VoIP calling involves multiple parties; the sequence diagrams below are important for understanding who does what.
The diagrams label key English identifiers and parameters for cross-checking with the API documentation.
Scenario 1: Mini Program calls the device (before answer)
Note: In this scenario, before answer, the device has not yet established a TiRTC connection to the Tange platform. Therefore, note the following:
- Mini Program cancels the call
Because there is no TiRTC link to the platform yet, the Mini Program must ask the business server to notify the device to cancel.
- Device rejects
User reject, device busy, or other pre-answer end paths should report the reason through the device-side service request TiRtcServiceRequest("/v1/wxvoip/reject", ...). At this point the device has not established a TiRTC connection, so it cannot use the command channel to send the hang-up command (cmdw=0x2001).
hangup_reason uses the same hang-up reason values as WeChat VoIP Calling Commands: use 5 for busy and 7 for user reject. Request body fields come from the wxa_join_voip_room payload delivered by the business server; see Device integration.
FAQ
- Why is there “Mini Program cancels” but no “device cancels” in this scenario?
Here the Mini Program is the caller; the device only answers or rejects, it does not “cancel the outgoing call” in the same sense.
Scenario 2: Device calls the Mini Program (before answer)
Note: In this scenario, the device is the caller. The flow is:
- Device calls the business server
POST /v1/voip/device/call, which internally calls WeChatiot/voip/call. - The Mini Program rings; once the user answers, WeChat sends
join_voip_roomto the business server. - The business server processes the callback and pushes
call_incomingto the device. - The device calls
TiRtcWhipConnectto join the room; after connecting successfully, it receivescmdw=0x2000(both sides established), and enters the call directly since WeChat has already set up the room.
Therefore:
- Device aborts the call before answer: the device cancels locally (no TiRTC connection yet); after answer, the device sends the hang-up command (
cmdw=0x2001). - Mini Program rejects: delivered by the cloud as the hang-up command (
cmdw=0x2001) to the device.
In call (after answer)
The following applies whether the Mini Program or the device placed the call.
- Connected: After
TiRtcWhipConnectsucceeds, the device receivescmdw=0x2000from the platform, meaning both sides are established. This applies to both scenarios — whether the device is the callee or the caller. - Device hang-up during the call: Same pattern as device abort when the device was the caller.
- Mini Program hang-up during the call: Same pattern as Mini Program reject when the device was the caller.
Media and stream_id
After connect, send and receive audio/video per Real-time audio and video.
WeChat VoIP calling stream_id convention:
- Audio:
stream_id = 10 - Video:
stream_id = 11
Next steps
Additional conventions
- The caller may include custom fields in
payload(e.g.wxa_fromto identify the caller side,call_idas a unique call identifier). WeChat and Tange Cloud pass this through transparently without interpreting it. The device useswxa_fromto distinguish an incoming call from a callback ring.
Reference Implementation
tirtc-server-example is an open-source reference project built on top of these docs and the Tange Cloud SDK. It demonstrates the complete four-party interaction of WeChat VoIP calling and serves as a starting point for your own development:
| Module | Description |
|---|---|
voip-server | Business server (Go): handles WeChat callbacks, calls Tange Cloud Token API, MQTT device downlink |
device-sim-c / device-sim-py | Device simulator (C / Python): WHIP connection, signaling, G.711a audio streaming |
weixin-mini-program | WeChat Mini Program: VoIP plugin integration, device authorization binding, calling UI |
user-server / device-server | User & device management (Go): login, binding, MQTT credential issuance |
The device communicates with the business server over an MQTT persistent connection, using ClientID sn_{device_id}. Key topics:
| Topic | QoS | Description |
|---|---|---|
device/sn_{device_id}/cmd | 1 | Command channel: call_incoming (incoming call, device must reply ACK) |
device/sn_{device_id}/notify | 1 | Notification channel: call_cancel, callers_update (authorization change) |
The project covers both call scenarios (Mini Program initiated / device initiated), incoming call rejection, in-call hangup, and audio streaming — ready to run and debug.