unwahas / video
Video processing and management library for PHP / Laravel
Requires
- php: >=8.2
- illuminate/database: ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/support: ^10.0 || ^11.0 || ^12.0 || ^13.0
- inertiajs/inertia-laravel: ^2.0 || ^3.0
Requires (Dev)
- orchestra/testbench: ^8.0 || ^9.0 || ^10.0
- phpunit/phpunit: ^10.0 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Video processing and management library for PHP / Laravel with WebRTC signaling and room management.
Requirements
- PHP >= 8.2
- Laravel 10.x, 11.x, 12.x, or 13.x (
illuminate/database&illuminate/support) - Inertia.js Laravel
^2.0 || ^3.0(inertiajs/inertia-laravel) - Laravel Reverb (or any Pusher-compatible WebSocket server)
Installation
composer require unwahas/video
Laravel Integration
The package registers automatically via Laravel package discovery:
- Service Provider:
Unwahas\Video\VideoServiceProvider - Facade:
Unwahas\Video\Facades\Video(aliased asVideo)
If you don't use package auto-discovery, you can register them manually in config/app.php (or bootstrap/providers.php in Laravel 11+):
'providers' => [ Unwahas\Video\VideoServiceProvider::class, ], 'aliases' => [ 'Video' => Unwahas\Video\Facades\Video::class, ],
Scaffolding & Publishing to Your Application
Running the command below will publish all configurations, migrations, and scaffold the controllers, models, events, routes, channels, and React components directly into your Laravel application:
php artisan unwahas-video:install
# or alias:
php artisan unwahas-video:publish
What this command creates in your app:
config/video.phpdatabase/migrations/YYYY_MM_DD_HHMMSS_create_video_rooms_table.phpapp/Http/Controllers/VideoRoomController.phpapp/Models/VideoRoom.phpapp/Events/VideoSignalReceived.phpapp/Events/ReverbTestPing.phproutes/videoRouter.php(and links it intoroutes/web.php)routes/videoChannel.php(and links it intoroutes/channels.php)resources/js/lib/echo.ts(Laravel Echo & Reverb WebSocket client)resources/js/lib/format-date.ts(Indonesian locale clock formatter)resources/js/types/webrtc.ts(TypeScript types for WebRTC)resources/js/hooks/use-webrtc.ts(React WebRTC hook)resources/js/components/cctv-video-tile.tsx(CCTV Video Tile component)resources/js/components/cctv-video-grid.tsx(Dynamic CCTV Grid component)resources/js/components/cctv-video-grid-example.tsx(Complete CCTV Grid + useWebRTC example component)
Frontend NPM Requirements
Make sure your application has laravel-echo, pusher-js, and lucide-react installed:
npm install --save-dev laravel-echo pusher-js lucide-react
Command Options:
--force: Overwrite existing files in your application.--migrate: Automatically run database migrations after scaffolding.--no-routes: Do not automatically append require statements toroutes/web.phpandroutes/channels.php.
Example:
php artisan unwahas-video:install --migrate
Manual Individual Publishing via Tags
If you prefer to publish items individually using --tag=unwahas-video:
# Publish Everything in one tag php artisan vendor:publish --tag=unwahas-video # Or individually: php artisan vendor:publish --tag=unwahas-video-config php artisan vendor:publish --tag=unwahas-video-migrations php artisan vendor:publish --tag=unwahas-video-controller php artisan vendor:publish --tag=unwahas-video-model php artisan vendor:publish --tag=unwahas-video-events php artisan vendor:publish --tag=unwahas-video-routes php artisan vendor:publish --tag=unwahas-video-channels php artisan vendor:publish --tag=unwahas-video-js php artisan vendor:publish --tag=unwahas-video-react
⚠️ Important Note: Broadcast Channels Setup
WebRTC signaling (VideoRoomController::signal) and ping monitoring depend on Laravel's broadcast presence channels.
Automatic Channel Registration
The package registers these presence channels automatically (configured via 'load_channels' => true in config/video.php).
Manual Channel Registration (in routes/channels.php or routes/videoChannel.php)
If you prefer to define them directly in your application's routes/channels.php (or after publishing via php artisan vendor:publish --tag=video-channels into routes/videoChannel.php), ensure the following channels are authorized:
use Illuminate\Support\Facades\Broadcast; // Presence channel for video meeting room signaling (WebRTC offer, answer, ice-candidates) Broadcast::channel('video-room.{roomId}', function ($user, string $roomId): ?array { if (! $user) { return null; } return [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email ?? null, 'role' => $user->role ?? (method_exists($user, 'isDosen') && $user->isDosen() ? 'dosen' : 'mahasiswa'), ]; }); // Presence channel for Reverb WebSocket monitoring & ping health check Broadcast::channel('reverb-monitoring', function ($user): ?array { if (! $user) { return null; } return [ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email ?? null, 'role' => $user->role ?? (method_exists($user, 'isDosen') && $user->isDosen() ? 'dosen' : 'mahasiswa'), ]; });
Note: If your application also has exam monitoring, remember to register
Broadcast::channel('exam-room.{roomId}', ...)as well.
Routes
You can publish the default room routes or load them directly via config:
php artisan vendor:publish --tag=video-routes
Routes provided:
GET /rooms→rooms.indexPOST /rooms→rooms.storeGET /rooms/{slug}→rooms.showPOST /rooms/{slug}/start→rooms.startPOST /rooms/{slug}/end→rooms.endGET /rooms/{slug}/status→rooms.statusPOST /rooms/signal→rooms.signal
Usage & Models
Video Facade
use Video; // or use Unwahas\Video\Facades\Video; $version = Video::version(); // "1.0.x"
VideoRoom Model
use Unwahas\Video\Models\VideoRoom; $room = VideoRoom::create([ 'name' => 'Ruang Kuliah', 'slug' => 'ruang-kuliah', 'is_started' => true, 'started_at' => now(), 'user_id' => $user->id, ]); // Helper methods: $room->startRoom(); // Sets is_started = true and started_at = now() $room->endRoom(); // Sets is_started = false
React WebRTC Hook (useWebRTC)
The library provides a production-ready React hook for WebRTC mesh networking, audio/video toggle, screen sharing, resolution switching (720p, 480p, 360p, 240p), and dual-path signaling (Echo presence whisper + HTTP fallback).
Publishing to React frontend:
php artisan vendor:publish --tag=unwahas-video-react
Files created:
resources/js/hooks/use-webrtc.tsresources/js/types/webrtc.tsresources/js/lib/echo.tsresources/js/lib/format-date.tsresources/js/components/cctv-video-tile.tsxresources/js/components/cctv-video-grid.tsxresources/js/components/cctv-video-grid-example.tsx
React WebRTC Hook Example:
import { useWebRTC } from '@/hooks/use-webrtc'; export function VideoRoomComponent({ room, currentUser }) { const { localStream, remoteStreams, peers, isAudioEnabled, isVideoEnabled, isScreenSharing, activeScreenShareUserId, toggleAudio, toggleVideo, toggleScreenShare, videoQuality, changeVideoQuality, connectionStatus, errorMessage, } = useWebRTC({ roomSlug: room.slug, channelName: `video-room.${room.slug}`, currentUser: { id: String(currentUser.id), name: currentUser.name, role: currentUser.role, }, }); // ... render local and remote video elements }
CCTV Video Grid Example (CctvVideoGrid + useWebRTC):
The package includes a ready-to-use CCTV examination/monitoring grid (CctvVideoGrid) and an example implementation (CctvVideoGridExample):
import React from 'react'; import { CctvVideoGrid } from '@/components/cctv-video-grid'; import { useWebRTC } from '@/hooks/use-webrtc'; import type { RoomUser } from '@/types/webrtc'; export function CctvVideoGridExample() { const currentUser: RoomUser = { id: 'dosen-1', name: 'Dr. Budi Santoso', role: 'dosen', }; const { localStream, remoteStreams, peers, isAudioEnabled, isVideoEnabled, toggleAudio, toggleVideo, connectionStatus, } = useWebRTC({ roomSlug: 'uas-pemrograman-web', channelName: 'video-room.uas-pemrograman-web', currentUser, }); return ( <div className="space-y-4 p-4"> {/* Control Bar Header */} <div className="flex items-center justify-between rounded-lg bg-neutral-900 p-3 text-white"> <div> <h2 className="text-lg font-bold">UAS Pemrograman Web - CCTV Monitor</h2> <p className="text-xs text-neutral-400"> Status: <span className="font-semibold text-emerald-400">{connectionStatus}</span> | Peserta: {peers.length} </p> </div> <div className="flex gap-2"> <button type="button" onClick={toggleAudio} className={`rounded px-3 py-1.5 text-xs font-semibold ${ isAudioEnabled ? 'bg-emerald-600' : 'bg-rose-600' }`} > {isAudioEnabled ? 'Mic Aktif' : 'Mic Bisu'} </button> <button type="button" onClick={toggleVideo} className={`rounded px-3 py-1.5 text-xs font-semibold ${ isVideoEnabled ? 'bg-emerald-600' : 'bg-rose-600' }`} > {isVideoEnabled ? 'Kamera Aktif' : 'Kamera Mati'} </button> </div> </div> {/* Render Base CCTV Grid Component */} <CctvVideoGrid localStream={localStream} remoteStreams={remoteStreams} displayedPeers={peers} currentUserName={currentUser.name} /> </div> ); }
Testing
composer test # or ./vendor/bin/phpunit
License
The MIT License (MIT).