Pulse Phone docs
Calls, video and Live
5. Voice and calls
Start one voice script before the phone. It is found by itself:
| Voice script | Resource name | Calls | Speakerphone heard nearby |
|---|---|---|---|
| pma-voice | pma-voice |
yes | yes |
| mumble-voip | mumble-voip |
yes | yes |
| SaltyChat | saltychat |
yes | yes |
| TokoVOIP | tokovoip_script |
yes | no |
| YACA | yaca-voice |
yes | yes |
- To pin one, set
Config.Voice.backendinconfig/config.luato'pma','mumble','salty','toko'or'yaca'. The default'auto'is right for almost everyone. - Run exactly one voice script. Two at once (or esx_voice / mumble-voice next to one) is the usual cause of calls with no sound. The start-up check flags it.
- A company phone line: give a company in
Config.Servicesanumber. Calling it rings every on-duty member. - The Radio app does not work with YACA.
Video calls
Video calls use the in-game camera and your supported voice resource. Players do not need
physical webcams. For reliable connections between players on different networks, configure
an external video relay before opening your server to the public. Your hosting administrator
can follow Video relay configuration.
Run phone:health after setup and follow any corrective instructions it provides.
Group video calls
Pulse supports multi-participant video calling with four video seats by default. During a call, choose Add Person to invite someone. Each person can mute, change cameras or leave without restarting the call. Use the same voice resource and video relay setup as for two-person calls. Keep the default capacity for normal use; larger groups and custom settings are covered in the advanced integration guide.
Earpiece, speaker and Pulse Buds
Tap the audio control during a call to choose Earpiece, Speaker or equipped Pulse Buds. The selected route follows you when you swap or merge lines. The earpiece keeps the call private. Speakerphone shares the remote caller around the holder on the supported voice backends listed above. Wearing connected Pulse Buds routes the call privately and changes the accessory/hold behavior. With the default private-call setting, take the Buds out to use speakerphone. Removing them or exhausting their battery returns the audio route to the earpiece. These are in-game accessories; they do not change a player's computer audio device.
Call and video troubleshooting
| Symptom | What to check |
|---|---|
| Call has no sound | Start one supported voice resource before Pulse. Run phone:health; for pma-voice, enable call channels with setr voice_enableCalls 1. |
| Picture stays on the avatar | Run phone:health and check the video relay setup with your host. Follow advanced connection troubleshooting, then retry the call. |
| Mute or speaker is unavailable | Check the voice capability table. Take out Pulse Buds to use speakerphone with the default private-call setting. |
| Voice dependency restarts | The active call ends cleanly. Once the voice service is ready, place a new call. |
| Recording has no microphone sound | Enable audio recording in config/config.lua, allow FiveM's microphone permission and select an available input device. Voice calls use your voice resource's microphone settings. |
What each voice script supports beyond calls:
| pma-voice | mumble-voip | SaltyChat | TokoVOIP | YACA | |
|---|---|---|---|---|---|
Merged calls (up to Config.Calls.maxParties) |
yes | yes | yes | yes | yes |
| Mute on the call only | yes | yes | unavailable through this backend | unavailable through this backend | yes |
| Sound in a live video | yes | yes | no | no | no |
| The Radio app | yes | yes, see Radio below | yes | yes | no |
Live video
A player can go live with the front camera in the social app. Followers are notified and can watch, comment, like, follow and share the live into Messages. The picture goes phone to phone like a video call (the same video relay settings). The sound is the streamer's own microphone, carried by your voice script: viewers hear the streamer from anywhere on the map, the streamer never hears the viewers, and viewers never hear each other. The server decides who is a viewer.
On SaltyChat, TokoVOIP and YACA there is no listen-only route, so a live has picture and chat only, and viewers are told sound isn't available on this server.
| Setting | File | Default | |
|---|---|---|---|
Config.SocialLive.enabled |
config/apps.lua |
true |
live on or off |
Config.SocialLive.maxViewers |
config/apps.lua |
8 (1 to 20) |
viewers who get the picture. The streamer uploads one copy per viewer (about 0.5 to 1 Mbit/s each) |
Config.Voice.liveAudio |
config/config.lua |
'auto' |
false turns live sound off |
Config.Voice.liveMaxListeners |
config/config.lua |
32 (1 to 128) |
people in one live when it has sound |
With sound, a live holds liveMaxListeners people: the first maxViewers get the picture, the
rest hear the streamer and use the chat until a spot frees up. Without sound, a live holds
maxViewers people. Set the listener limit to suit your voice server capacity and the broadcaster's upload bandwidth.
Emergency calls (Smart 911)
Dialling 911, or pressing Emergency on the lock screen, opens a menu of Police, EMS and Fire. Only the services your server actually has are shown. The caller picks a reason (shots fired, vehicle crash ...) and whether to share their location (on by default).
Every on-duty member of the chosen service's jobs rings at once. The first to answer takes the
call, and the other phones stop ringing without a missed-call alert. Responders see the caller's
name and number, the reason, the street and area, and a Waypoint button. If nobody is on
duty, or nobody answers within ringSeconds, the caller can choose Send Emergency Text: a
dispatch alert with their location, and a message in the service's Services inbox.
Everything is in Config.Emergency in config/apps.lua: numbers, ringSeconds,
anonymous (false, 'optional' or true), shareLocation and dispatchOnCall (a dispatch
alert for every emergency call). Each entry in services has its jobs, enabled ('auto' shows
it only when one of its jobs exists; Fire uses this), the Services inbox (company), its reasons,
colour and dispatch code.
Duty is read from the framework: job.onduty on QBCore and Qbox, job.onDuty on ESX Legacy
(older ESX off-duty jobs such as offpolice also count as off duty), and the phone's own duty on
a standalone server. wasabi_police and wasabi_ambulance use the framework's duty, so they need no
setup. Dispatch alerts go through the dispatch script from section 7; without one, everyone
holding the service's jobs gets a phone notification. To add another dispatch script, copy one of
the bridge/server/dispatch_*.lua files (each is about a dozen lines).
Everything a responder is shown is read on the server. The caller's phone only sends the service, the reason and their two choices.
Payphones
On by default (config/apps.lua). Every payphone booth already in the world works; nothing is
spawned. A player needs no phone of their own, so a player with no phone, a dead one or no plan
can still use a booth.
- Using a booth. Walk up and use the ox_target / qb-target option, or press E at the
prompt. The keypad opens; the call goes through the phone's own call system, so the person
called sees an ordinary call. On the line, E opens the keypad again and X hangs up.
Walking more than
rangeaway, getting into a vehicle or dying drops the line (the server checks this too). - Money. The price (
price, 25) is taken before the call, from cash, the bank or either (pay,'either'by default). A call that can't be placed is refunded at once. WithrefundUnanswered = truea call that never connects is refunded when it ends. When the framework can't take the money the call is refused, never made free. Emergency numbers are free withemergencyFree = true, and 911 opens the same service menu as on the phone. - Calls to a booth. With
incoming = trueeach booth has its own number, shown on the keypad:numberPrefixplus digits worked out from where it stands, so it never changes. Calling it rings the booth for the player standing at it, who presses E to answer. SetcallerId = 'number'so the person called sees the booth's number and can call back. booths(optional). The server can't see world props, so by default it trusts the booth position the player's game reports. List your booths' positions inConfig.Payphone.boothsand the server only accepts a call within reach of one of them. Money taken for a call that never connected because of a crash or restart is paid back the next time the phone starts.
Known limits: only the player standing at a booth hears it ring; a call to a booth with nobody at
it is unavailable (it isn't held); a booth has no voicemail, so a message left for it is not kept;
and a booth number can match a real phone's number (555 plus four digits fits the default
format). When it does, the real phone rings. To rule that out, set Config.Numbers.prefixes to
area codes that don't start with the booth numberPrefix.
Radio
The Radio app (players install it from App Hub, on by default, config/apps.lua) tunes a player
into a radio frequency through the voice script you already run. Talking uses that voice script's
own radio push-to-talk key, and the app shows which key (pttHint overrides the text).
| Voice script | Radio |
|---|---|
| pma-voice, SaltyChat, TokoVOIP | yes, joined on the server |
| mumble-voip | yes, with a limit: it has no server API, so the phone checks the channel on the server and the player's own game joins it. The phone can't stop a player who calls mumble-voip's radio directly |
| YACA, or no voice script | no: the app opens and says radio is not available on this server |
Every join is decided on the server: the frequency is inside min to max, the player carries
the radio item when item is set, and a restricted channel only admits its jobs (a list of job
names, or job = minimum grade; a rule on a whole number also covers its decimals). The check runs
again every recheckSeconds, and a player who loses the job or the item is taken off the channel
and told why. presets are the quick buttons in the app; members shows who is on the channel
('names', 'count' or false). With pma-voice, registerChannelChecks = true also registers
the restricted channels with pma-voice's own channel checks, so no other script can put a player
on them either (off by default). To limit the whole app to some jobs, use Config.Apps.jobs as
for any other app.