Files
voice-call-service/README.md
2026-05-29 01:06:47 +03:00

7.7 KiB

Intaleq Voice Call Signaling Backend (API Key & Session Pre-creation)

Production-ready WebRTC signaling server in Node.js for the Intaleq ride-hailing application. Coordinates secure peer-to-peer audio calls between driver and passenger during active rides only. Sessions are pre-created by the main application backend over an authenticated HTTP endpoint, allowing mobile clients to connect using temporary session IDs without dealing with JWTs.

Prerequisites

  • Node.js 20+ (for local development)
  • Docker and Docker Compose (for production deployments)
  • Nginx (acting as reverse proxy for WSS upgrade and SSL termination)
  • Let's Encrypt (for SSL certificates)

Local Development

  1. Clone and Navigate Ensure you are in the voice-call-service directory.

  2. Setup Configuration Copy the example environment file and configure variables:

    cp .env.example .env
    

    Note: Ensure API_KEY is at least 32 characters long.

  3. Install Dependencies

    npm install
    
  4. Run Server Since Node.js 20.6.0+, you can load .env files natively using the --env-file flag:

    node --env-file=.env cmd/server/main.js
    

    The signaling server will start and bind locally to 127.0.0.1:47880.

Docker Deployment

Deploying with Docker isolates dependencies and bounds resources to 128MB.

  1. Deploy Command Run the deployment automation script:

    ./deploy.sh
    

    This script will verify your configuration, build a secure multi-stage container running under user node (UID 1000), deploy it in host networking mode, and verify the service's health.

  2. Manual Docker Compose Commands Alternatively, you can build and run it manually:

    docker-compose up -d --build
    

Nginx Configuration

An Nginx configuration block should be configured on your CloudPanel/hosting server for calls.intaleqapp.com. It proxies connections to localhost and processes WebSocket handshakes:

server {
    listen 80;
    server_name calls.intaleqapp.com;

    location / {
        proxy_pass http://127.0.0.1:47880;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Headers
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Read timeout management
        proxy_read_timeout 120s;
        proxy_send_timeout 120s;
    }
}

Environment Variables

Variable Description Default
SERVER_ADDR Local binding interface and port 127.0.0.1:47880
API_KEY Secret key for authenticating HTTP session creation None (min 32 chars)
LOG_LEVEL Level of logging output (debug, info, warn, error) info
MAX_MESSAGE_BYTES Maximum payload size allowed for WebSocket frames 4096
HEARTBEAT_INTERVAL Keepalive ping interval 20s
HEARTBEAT_TIMEOUT Connection death timeout 30s
SESSION_DURATION Hard limit on call length before auto-termination 60s
RATE_LIMIT_PER_MIN Maximum connections allowed per IP per minute 10
ENVIRONMENT Target environment designation production
DB_HOST MySQL database host address 127.0.0.1
DB_PORT MySQL database connection port 3306
DB_DATABASE MySQL database name callDB
DB_USERNAME MySQL database username None
DB_PASSWORD MySQL database password None

Database Logging

The signaling server integrates with a MySQL database to log call connectivity metrics. The system automatically creates a call_logs table on startup (defined in database.sql).

Call Logs Schema

Column Type Description
id INT Primary Key, Auto Increment
session_id VARCHAR(36) Unique Ephemeral Session ID
ride_id VARCHAR(255) Active Ride ID
driver_id VARCHAR(255) Registered Driver ID
passenger_id VARCHAR(255) Registered Passenger ID
status VARCHAR(50) Call state (created, active, ended)
initiated_by VARCHAR(255) User ID of the participant who started the connection (sent first offer)
end_reason VARCHAR(255) Call termination reason (e.g., user_terminated, max_duration_reached, disconnect_driver, disconnect_passenger)
created_at TIMESTAMP Time when session was pre-created
connected_at TIMESTAMP Time when both parties connected and call started
ended_at TIMESTAMP Time when call was terminated

HTTP Session Pre-creation API

The main application backend (PHP) registers a session before allowing call access.

Create Call Session

  • Route: POST /sessions
  • Headers:
    • X-API-Key: YOUR_API_KEY_HERE
    • Content-Type: application/json
  • Request Body:
    {
      "ride_id": "ride_456",
      "driver_id": "user_123",
      "passenger_id": "user_789"
    }
    
  • Response Body (200 OK):
    {
      "session_id": "3b2e7c4f-95a2-4a0b-99f6-fc935d0a4461",
      "ride_id": "ride_456",
      "expires_in": 60
    }
    

WebSocket Protocol Reference

Clients communicate with the backend at ws://calls.intaleqapp.com/ws.

Client-to-Server Messages

  1. Authenticate (MUST be sent first)
    {
      "type": "authenticate", 
      "session_id": "3b2e7c4f-95a2-4a0b-99f6-fc935d0a4461",
      "user_id": "user_123"
    }
    
  2. Offer WebRTC Payload
    {"type": "offer", "sdp": "v=0\r\n..."}
    
  3. Answer WebRTC Payload
    {"type": "answer", "sdp": "v=0\r\n..."}
    
  4. ICE Candidate WebRTC Payload
    {"type": "ice_candidate", "candidate": {"candidate": "...", "sdpMid": "0", "sdpMLineIndex": 0}}
    
  5. Heartbeat
    {"type": "heartbeat"}
    
  6. End Call
    {"type": "end_call"}
    

Server-to-Client Messages

  1. Authentication Success Alert
    {"type": "authenticated", "user_id": "user_123"}
    
  2. Session Joined (Active status)
    {"type": "session_joined", "session_id": "sess_abc", "ride_id": "ride_456"}
    
  3. Peer Joined Notification
    {"type": "participant_joined", "role": "passenger"}
    
  4. Relayed WebRTC Offer
    {"type": "offer", "sdp": "v=0\r\n..."}
    
  5. Relayed WebRTC Answer
    {"type": "answer", "sdp": "v=0\r\n..."}
    
  6. Relayed ICE Candidate
    {"type": "ice_candidate", "candidate": {"candidate": "...", "sdpMid": "0", "sdpMLineIndex": 0}}
    
  7. Peer Disconnected Alert
    {"type": "participant_left", "role": "driver"}
    
  8. Call Duration Timeout Alert
    {"type": "call_timeout", "reason": "max_duration_reached"}
    
  9. Call Terminated Alert
    {"type": "call_ended", "reason": "user_terminated"}
    
  10. Heartbeat Reply (Pong)
    {"type": "pong"}
    
  11. Unauthorized Connection Error
    {"type": "unauthorized", "reason": "session_not_found"}
    
  12. General Error Message
    {"type": "error", "code": "session_not_found", "message": "No active session for this ride"}
    

Security Notes

  1. Access Control Only your trusted main backend can create call sessions, verified via the X-API-Key header. Mobile clients only receive the ephemeral session_id and can only authenticate under their pre-registered user_id context.

  2. Encryption SSL (WSS) is terminated at Nginx. Internal network loops (from Nginx to 47880) run local loopbacks.