A web-based iPhone-style dialer application built with React and SignalWire SDK for making and receiving WebRTC calls.
- ✅ iPhone-style dialer UI with dark theme
- ✅ Outbound calling with DTMF tones
- ✅ Inbound call reception with full-screen UI
- ✅ Automatic token refresh (at 80% of token lifetime)
- ✅ Call controls (mute, speaker, keypad)
- ✅ Real-time call duration display
- ✅ In-call DTMF keypad support
- ✅ Keyboard input for DTMF during calls
- ✅ Microphone permission handling
- ✅ Error boundaries for graceful error handling
- ✅ Whimsical ringtone for incoming calls
- ✅ Connection status indicator
- Node.js 18+ and npm
- Python 3.9+
- SignalWire account with Fabric resources
- Modern web browser with WebRTC support
cd backend
# Create virtual environment
python -m venv venv
# Activate virtual environment
# On macOS/Linux:
source venv/bin/activate
# On Windows:
# venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Create .env file from example
cp .env.example .envEdit backend/.env with your SignalWire credentials:
SPACE_NAME=your-space.signalwire.com
PROJECT_ID=your-project-id
AUTH_TOKEN=your-auth-token
PORT=5001
FRONTEND_URL=http://localhost:5173cd frontend
# Install dependencies
npm installStart the backend server:
cd backend
source venv/bin/activate # If not already activated
python app.pyThe backend will run on http://localhost:5001
In a new terminal, start the frontend:
cd frontend
npm run devThe frontend will run on http://localhost:5173
- Open
http://localhost:5173in your browser - Grant microphone permissions when prompted
- Wait for SignalWire connection to establish
- Enter a phone number and press the green call button to make a call
- Incoming calls will show a full-screen notification
GET /- Health check endpointGET /health- Detailed health check with configuration statusPOST /api/auth/token- Generate subscriber token for WebRTC accessPOST /api/auth/refresh- Refresh subscriber tokenPOST /api/auth/validate- Validate token (placeholder endpoint)POST /api/calls/dial- Initiate outbound callPOST /api/calls/answer/{call_id}- Answer incoming callPOST /api/calls/end/{call_id}- End active callPOST /api/calls/reject/{call_id}- Reject incoming callGET /api/calls/{call_id}- Get call detailsGET /api/calls/- Get all calls (call history)
frontend/
├── src/
│ ├── components/ # React components
│ │ ├── Dialer.tsx # Main dialer interface with state management
│ │ ├── DialPad.tsx # Number pad with DTMF tone generation
│ │ ├── CallScreen.tsx # Active call UI with controls
│ │ ├── IncomingCall.tsx # Full-screen incoming call notification
│ │ └── ErrorBoundary.tsx # Error handling wrapper component
│ ├── hooks/ # Custom React hooks
│ │ ├── useSignalWire.ts # SignalWire SDK integration & WebRTC management
│ │ └── useCallStore.ts # Zustand store for global call state
│ ├── services/ # Service layer
│ │ ├── api.ts # Backend API client with axios
│ │ ├── signalwire.ts # SignalWire client wrapper
│ │ └── tones.ts # Audio tone generation (DTMF & ringtones)
│ ├── styles/ # CSS files
│ │ └── globals.css # Global styles and Tailwind imports
│ ├── types/ # TypeScript definitions
│ │ └── index.ts # Shared type definitions
│ ├── App.tsx # Root application component
│ └── main.tsx # Application entry point
├── vite.config.ts # Vite configuration with proxy setup
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Frontend dependencies
backend/
├── api/ # API blueprints
│ ├── __init__.py # Blueprint initialization
│ ├── auth.py # Authentication endpoints
│ └── calls.py # Call management endpoints
├── utils/ # Utility modules
│ ├── __init__.py # Utils initialization
│ └── signalwire.py # SignalWire SDK wrapper
├── app.py # Flask application entry point
├── requirements.txt # Python dependencies
└── .env.example # Environment variables template
- Verify SignalWire credentials in
.env - Check that your SignalWire project has Fabric resources configured
- Ensure both backend and frontend are running
- Check browser console for errors
- Ensure microphone permissions are granted
- Check that no other application is using the microphone
- Try using headphones to avoid echo
The application automatically refreshes tokens at 80% of their lifetime (e.g., after 48 minutes for a 60-minute token). If you experience disconnections:
- Check backend logs for token generation errors
- Verify SignalWire API credentials
- Ensure stable network connection
- React 18 with TypeScript for type safety
- Vite as the build tool and dev server
- Tailwind CSS for styling
- Zustand for state management
- @signalwire/js SDK for WebRTC functionality
- Axios for API communication
- Lucide React for icons
- Flask web framework
- Flask-CORS for cross-origin support
- SignalWire Python SDK for token generation
- Python-dotenv for environment configuration
- Gunicorn for production deployment
For production deployment:
- Use environment variables for all sensitive configuration
- Enable HTTPS for both frontend and backend
- Configure proper CORS origins in backend
- Use a production WSGI server (e.g., Gunicorn) for Flask
- Build the React app:
npm run build - Serve static files with a web server (e.g., Nginx)
- Set up proper logging and monitoring
- Configure firewall rules for WebRTC media ports
MIT
For SignalWire-specific issues, consult the SignalWire documentation.
For application issues, check the logs in both backend and frontend consoles.