# TWP Softphone — Mobile App Flutter-based VoIP softphone client for the Twilio WordPress Plugin. Uses the Twilio Voice SDK (WebRTC) to make and receive calls via the Android Telecom framework. ## Requirements - Flutter 3.29+ (tested with 3.41.4) - Android device/tablet (API 26+) - TWP WordPress plugin installed and configured on server - Twilio account with Voice capability ## Quick Start ```bash cd mobile flutter pub get flutter build apk --debug adb install build/app/outputs/flutter-apk/app-debug.apk ``` ## Server Setup The app connects to your WordPress site running the TWP plugin. The server must have: 1. **TWP Plugin** installed and activated 2. **Twilio credentials** configured (Account SID, Auth Token) 3. **At least one Twilio phone number** purchased 4. **A WordPress user** with agent permissions ### SSE (Server-Sent Events) — Apache + PHP-FPM The app uses SSE for real-time updates (queue changes, agent status). On Apache with PHP-FPM, `mod_proxy_fcgi` buffers output by default, which breaks SSE streaming. **Fix** — Create a config file on the web server: ```bash echo 'ProxyPassMatch "^/wp-json/twilio-mobile/v1/stream/events$" "unix:/run/php-fpm/www.sock|fcgi://localhost/path/to/wordpress/index.php" flushpackets=on' > /etc/httpd/conf.d/twp-sse.conf httpd -t && systemctl restart httpd ``` > **Adjust the paths:** > - Socket path must match your PHP-FPM config (check `grep fcgi /etc/httpd/conf.d/php.conf`) > - Document root must match your WordPress installation path **Diagnosis** — If the green connection dot stays red: ```bash # Check current PHP-FPM proxy config grep -r "fcgi\|php-fpm" /etc/httpd/conf.d/ # Check if flushpackets is configured grep -r "flushpackets" /etc/httpd/conf.d/ # Test SSE endpoint (should stream data continuously, not hang) curl -N -H "Authorization: Bearer YOUR_TOKEN" \ https://your-site.com/wp-json/twilio-mobile/v1/stream/events ``` **Notes:** - `flushpackets=on` is a `ProxyPassMatch` directive — it **cannot** go in `.htaccess` - If using **nginx** instead of Apache, the `X-Accel-Buffering: no` header (already in the PHP code) handles this automatically - The app automatically falls back to 5-second polling if SSE fails, so the app still works without this config — just with higher latency ## App Setup (Android) ### First Launch 1. Open the app and enter your server URL (e.g., `https://phone.cloud-hosting.io`) 2. Log in with your WordPress credentials 3. Grant permissions when prompted: - Microphone (required for calls) - Phone/Call (required for Android Telecom integration) ### Phone Account Android requires a registered and **enabled** phone account for VoIP apps. The app registers automatically, but enabling must be done manually: 1. If prompted, tap **"Open Settings"** to go to Android's Phone Account settings 2. Find **"TWP Softphone"** in the list and toggle it **ON** 3. Return to the app If you skipped this step, tap the orange warning card on the dashboard. > **Path:** Settings → Apps → Default apps → Phone → Calling accounts → TWP Softphone ### Making Calls 1. Tap the phone FAB (bottom right) to open the dialer 2. Enter the phone number 3. Caller ID is auto-selected from your Twilio numbers 4. Tap **Call** — the Android system call screen (InCallUI) handles the active call ### Receiving Calls Incoming calls appear via Android's native call UI. Answer/reject using the standard Android interface. > **Note:** FCM push notifications are required for receiving calls when the app is in the background. This requires `google-services.json` in `android/app/`. ### Queue Management - View assigned queues on the dashboard - Tap a queue with waiting calls to see callers - Tap **Accept** to take a call from the queue ### Agent Status Toggle between **Available**, **Busy**, and **Offline** using the status bar at the top of the dashboard. ## Development ### Project Structure ``` lib/ ├── config/ # App configuration ├── models/ # Data models (CallInfo, QueueState, AgentStatus, User) ├── providers/ # State management (AuthProvider, CallProvider, AgentProvider) ├── screens/ # UI screens (Login, Dashboard, Settings, ActiveCall) ├── services/ # API/SDK services (VoiceService, SseService, ApiClient, AuthService) ├── widgets/ # Reusable widgets (Dialpad, QueueCard, AgentStatusToggle) └── main.dart # App entry point ``` ### Running Tests ```bash flutter test ``` 34 tests covering CallInfo, QueueState, and CallProvider. ### Building ```bash # Debug APK flutter build apk --debug # Release APK (requires signing config) flutter build apk --release ``` ### ADB Deployment (WiFi) ```bash # Connect to device adb connect DEVICE_IP:PORT # Install adb install -r build/app/outputs/flutter-apk/app-debug.apk # Launch adb shell am start -n io.cloudhosting.twp.twp_softphone/.MainActivity # View logs adb logcat -s flutter ``` ### Key Dependencies | Package | Purpose | |---------|---------| | `twilio_voice` | Twilio Voice SDK (WebRTC calling) | | `provider` | State management | | `dio` | HTTP client (REST API, SSE) | | `firebase_messaging` | FCM push for incoming calls | | `flutter_secure_storage` | Secure token storage | ## Troubleshooting | Problem | Solution | |---------|----------| | Green dot stays red | SSE buffering — see [Server Setup](#sse-server-sent-events--apache--php-fpm) | | "No registered phone account" | Enable phone account in Android Settings (see [Phone Account](#phone-account)) | | Calls fail with "Invalid callerId" | Server webhook needs phone number validation — check `handle_browser_voice` in `class-twp-webhooks.php` | | App hangs on login | Check server is reachable: `curl https://your-site.com/wp-json/twilio-mobile/v1/auth/login` | | No incoming calls | Ensure FCM is configured (`google-services.json`) and phone account is enabled |