alexhackney / lara-nimble
A comprehensive Laravel package for seamless integration with Nimble Streamer API. Manage streams, DVR, sessions, restreaming, and more with a clean, expressive Laravel interface.
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 2
pkg:composer/alexhackney/lara-nimble
Requires
- php: ^8.1|^8.2|^8.3
- guzzlehttp/guzzle: ^7.5
- illuminate/http: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.13
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.5|^11.0
This package is auto-updated.
Last update: 2025-12-15 21:31:00 UTC
README
A comprehensive Laravel package for seamless integration with Nimble Streamer API. Manage streams, DVR, sessions, restreaming, and more with a clean, expressive Laravel interface.
Developed by Alex Hackney
Features
- ✅ Stream Management: Create, configure, publish/unpublish, and monitor streams
- ✅ Session Management: Monitor and control active client sessions
- ✅ DVR Control: Manage archives, recordings, and playback
- ✅ Restreaming: Configure and manage restream targets
- ✅ Stream Pulling: Pull streams from external sources
- ✅ Server Management: Monitor server status, reload configuration, and sync
- ✅ Cache Control: Manage server cache and statistics
- 🚧 Icecast Integration: Manage Icecast server and inject metadata (coming soon)
- 🚧 Playlist Management: Create and control server playlists (coming soon)
- ✅ Real-Time Statistics: Get live stream stats including bandwidth, resolution, codecs, and more
- ✅ Protocol Support: RTMP, MPEG-TS, SRT, NDI, HLS, RTSP
- ✅ Test-Driven Development: Comprehensive test coverage with 127 tests
- ✅ Type Safety: Full PHP 8.1+ type hints and enums
- ✅ Laravel Integration: Service provider, facade, and configuration
Requirements
- PHP 8.1 or higher
- Laravel 10 or 11
- Nimble Streamer with API enabled
- Composer
Installation
Step 1: Install via Composer
composer require alexhackney/lara-nimble
Step 2: Publish Configuration
php artisan vendor:publish --provider="AlexHackney\LaraNimble\NimbleServiceProvider" --tag="nimble-config"
This will create a config/nimble.php file in your Laravel application.
Step 3: Configure Environment Variables
Minimal Configuration - Add only what you need to your .env file:
# Required: Your Nimble server hostname NIMBLE_HOST=your-nimble-server.com # Optional: Only if your Nimble server requires authentication NIMBLE_TOKEN=your-secret-token
That's it! The package uses sensible defaults for everything else.
Optional Overrides - Only add these if you need to change the defaults:
# Connection (defaults shown) NIMBLE_PORT=8082 # Default Nimble management port NIMBLE_PROTOCOL=http # Use 'https' for production # Timeouts (in seconds) NIMBLE_TIMEOUT=30 # Request timeout NIMBLE_CONNECT_TIMEOUT=10 # Connection timeout # Retry Logic NIMBLE_RETRY_TIMES=3 # Number of retry attempts NIMBLE_RETRY_SLEEP=100 # Milliseconds between retries # Debug/Logging NIMBLE_LOG_REQUESTS=false # Enable to log all requests NIMBLE_LOG_CHANNEL=stack # Laravel log channel # SSL (for self-signed certs in development only) NIMBLE_VERIFY_SSL=true # Set to false to disable SSL verification
Step 4: Enable Nimble API
Ensure your Nimble server has the API enabled. Edit /etc/nimble/nimble.conf:
management_port = 8082;
management_token = your-secret-token; # Optional but recommended
Restart Nimble after configuration changes:
sudo systemctl restart nimble
Usage
Stream Management
use AlexHackney\LaraNimble\Facades\Nimble; // List all streams $streams = Nimble::streams()->list(); foreach ($streams as $stream) { echo "Stream: {$stream->name} ({$stream->status->value})\n"; echo "Protocol: {$stream->protocol->value}\n"; echo "Viewers: {$stream->viewers}\n"; } // Get a specific stream $stream = Nimble::streams()->get('stream-123'); echo "Status: {$stream->status->value}"; // Publish a stream if (Nimble::streams()->publish('live', 'my-stream')) { echo "Stream published successfully!"; } else { echo "Failed to publish stream"; } // Unpublish a stream if (Nimble::streams()->unpublish('live', 'my-stream')) { echo "Stream unpublished successfully!"; } // Get stream statistics $stats = Nimble::streams()->statistics('stream-123'); echo "Bitrate: {$stats['bitrate']} kbps\n"; echo "Viewers: {$stats['viewers']}\n"; echo "Duration: {$stats['duration']} seconds\n";
Real-Time Stream Statistics
Get comprehensive, real-time statistics for active streams including bandwidth, resolution, codecs, protocol information, and publisher details. Perfect for monitoring dashboards and live stream health checks.
use AlexHackney\LaraNimble\Facades\Nimble; // Get real-time stats for a specific stream by stream key $stats = Nimble::streams()->liveStatus('my-stream-key'); if ($stats) { echo "Stream: {$stats->streamName}\n"; echo "Application: {$stats->application}\n"; echo "Protocol: {$stats->protocol}\n"; echo "Resolution: {$stats->resolution}\n"; echo "Video Codec: {$stats->videoCodec}\n"; echo "Audio Codec: {$stats->audioCodec}\n"; echo "Bandwidth: " . ($stats->bandwidth / 1000000) . " Mbps\n"; echo "Bitrate: {$stats->bitrate} kbps\n"; echo "FPS: {$stats->fps}\n"; echo "Viewers: {$stats->viewers}\n"; echo "Duration: {$stats->duration} seconds\n"; echo "Publisher IP: {$stats->publisherIp}\n"; echo "Publisher Port: {$stats->publisherPort}\n"; echo "Source URL: {$stats->sourceUrl}\n"; echo "Started: {$stats->startTime}\n"; } else { echo "Stream is not currently live\n"; } // Get real-time stats for ALL currently active streams $allStreams = Nimble::streams()->allLiveStreams(); foreach ($allStreams as $stream) { echo "Stream: {$stream->streamName}\n"; echo " Protocol: {$stream->protocol}\n"; echo " Resolution: {$stream->resolution}\n"; echo " Bandwidth: " . ($stream->bandwidth / 1000000) . " Mbps\n"; echo " Viewers: {$stream->viewers}\n"; echo "\n"; } // Example: Build a real-time monitoring dashboard $liveStreams = Nimble::streams()->allLiveStreams(); $dashboard = $liveStreams->map(function ($stream) { return [ 'name' => $stream->streamName, 'app' => $stream->application, 'status' => 'live', 'protocol' => $stream->protocol, 'quality' => $stream->resolution, 'codecs' => [ 'video' => $stream->videoCodec, 'audio' => $stream->audioCodec, ], 'network' => [ 'bandwidth_mbps' => round($stream->bandwidth / 1000000, 2), 'bitrate_kbps' => $stream->bitrate, 'publisher_ip' => $stream->publisherIp, ], 'metrics' => [ 'viewers' => $stream->viewers, 'fps' => $stream->fps, 'uptime_seconds' => $stream->duration, ], ]; }); return response()->json(['streams' => $dashboard]);
Use Cases for Real-Time Statistics:
- Live Monitoring: Display current stream health in admin dashboards
- Quality Alerts: Detect bitrate drops or resolution changes
- Viewer Analytics: Track real-time viewer counts
- Stream Discovery: List all currently active streams
- Protocol Monitoring: Track which protocols are being used (RTMP, SRT, NDI)
- Network Analysis: Monitor bandwidth usage and publisher connections
Session Management
use AlexHackney\LaraNimble\Facades\Nimble; // List all active sessions $sessions = Nimble::sessions()->list(); foreach ($sessions as $session) { echo "Session: {$session->id}\n"; echo "Client IP: {$session->clientIp}\n"; echo "Protocol: {$session->protocol}\n"; echo "Duration: {$session->duration} seconds\n"; } // Get a specific session $session = Nimble::sessions()->get('session-456'); echo "Stream: {$session->streamId}"; // Terminate a session if (Nimble::sessions()->terminate('session-456')) { echo "Session terminated successfully!"; } // Get session statistics $stats = Nimble::sessions()->statistics('session-456'); echo "Bytes transferred: {$stats['bytes_transferred']}\n";
DVR Management
use AlexHackney\LaraNimble\Facades\Nimble; // List all DVR archives $archives = Nimble::dvr()->listArchives(); foreach ($archives as $archive) { echo "Archive: {$archive->filename}\n"; echo "Stream: {$archive->streamId}\n"; echo "Size: {$archive->size} bytes\n"; echo "Duration: {$archive->duration} seconds\n"; } // Get a specific archive $archive = Nimble::dvr()->getArchive('archive-123'); echo "Path: {$archive->path}"; // Delete an archive if (Nimble::dvr()->deleteArchive('archive-123')) { echo "Archive deleted successfully!"; } // Configure DVR settings if (Nimble::dvr()->configure([ 'stream' => 'stream1', 'enabled' => true, 'path' => '/var/dvr/stream1', 'max_duration' => 3600, ])) { echo "DVR configured successfully!"; }
Restream Management
use AlexHackney\LaraNimble\Facades\Nimble; // List all restream targets $restreams = Nimble::restream()->list(); foreach ($restreams as $restream) { echo "Target: {$restream->targetUrl}\n"; echo "Protocol: {$restream->protocol}\n"; echo "Status: {$restream->status}\n"; echo "Enabled: " . ($restream->enabled ? 'Yes' : 'No') . "\n"; } // Get a specific restream target $restream = Nimble::restream()->get('restream-123'); echo "Target URL: {$restream->targetUrl}"; // Add a new restream target if (Nimble::restream()->add('stream-123', [ 'target_url' => 'rtmp://live.youtube.com/stream/key123', 'protocol' => 'rtmp', 'enabled' => true, ])) { echo "Restream target added successfully!"; } // Update a restream target if (Nimble::restream()->update('restream-123', [ 'enabled' => false, ])) { echo "Restream target updated!"; } // Delete a restream target if (Nimble::restream()->delete('restream-123')) { echo "Restream target deleted!"; }
Stream Pulling
use AlexHackney\LaraNimble\Facades\Nimble; // List all pull configurations $pulls = Nimble::pull()->list(); foreach ($pulls as $pull) { echo "Source: {$pull->sourceUrl}\n"; echo "Local: {$pull->localApp}/{$pull->localStream}\n"; echo "Protocol: {$pull->protocol}\n"; echo "Status: {$pull->status}\n"; } // Get a specific pull configuration $pull = Nimble::pull()->get('pull-123'); echo "Source URL: {$pull->sourceUrl}"; // Add a new pull configuration if (Nimble::pull()->add([ 'source_url' => 'rtmp://source.com/live/stream', 'local_app' => 'live', 'local_stream' => 'pulled-stream', 'protocol' => 'rtmp', 'enabled' => true, ])) { echo "Pull configuration added successfully!"; } // Update a pull configuration if (Nimble::pull()->update('pull-123', [ 'enabled' => false, ])) { echo "Pull configuration updated!"; } // Delete a pull configuration if (Nimble::pull()->delete('pull-123')) { echo "Pull configuration deleted!"; } // Get pull stream status $status = Nimble::pull()->status('pull-123'); echo "Uptime: {$status['uptime']} seconds\n"; echo "Bitrate: {$status['bitrate']} kbps\n";
Server Management
use AlexHackney\LaraNimble\Facades\Nimble; // Get server status $status = Nimble::server()->status(); echo "Status: {$status->status}\n"; echo "Version: {$status->version}\n"; echo "Uptime: {$status->uptime} seconds\n"; echo "Connections: {$status->connections}\n"; echo "Bandwidth In: {$status->bandwidth['in']} bytes\n"; echo "Bandwidth Out: {$status->bandwidth['out']} bytes\n"; // Reload server configuration if (Nimble::server()->reload()) { echo "Server configuration reloaded successfully!"; } // Sync with WMSPanel if (Nimble::server()->sync()) { echo "Synchronization completed!"; }
Cache Management
use AlexHackney\LaraNimble\Facades\Nimble; // Clear all cache if (Nimble::cache()->clear()) { echo "Cache cleared successfully!"; } // Clear specific cache type if (Nimble::cache()->clear('hls')) { echo "HLS cache cleared!"; } // Get cache statistics $stats = Nimble::cache()->statistics(); echo "Total Size: {$stats['total_size']} bytes\n"; echo "Items: {$stats['items']}\n"; echo "Hit Rate: {$stats['hit_rate']}\n"; echo "Miss Rate: {$stats['miss_rate']}\n"; // Configure cache settings if (Nimble::cache()->configure([ 'enabled' => true, 'max_size' => 2147483648, 'ttl' => 3600, ])) { echo "Cache configured successfully!"; }
Using in Controllers
<?php namespace App\Http\Controllers; use AlexHackney\LaraNimble\Facades\Nimble; use Illuminate\Http\JsonResponse; class StreamController extends Controller { public function index(): JsonResponse { $streams = Nimble::streams()->list(); return response()->json([ 'streams' => $streams->map->toArray(), ]); } public function publish(string $app, string $stream): JsonResponse { $success = Nimble::streams()->publish($app, $stream); return response()->json([ 'success' => $success, 'message' => $success ? 'Stream published' : 'Failed to publish stream', ]); } public function unpublish(string $app, string $stream): JsonResponse { $success = Nimble::streams()->unpublish($app, $stream); return response()->json([ 'success' => $success, 'message' => $success ? 'Stream unpublished' : 'Failed to unpublish stream', ]); } public function sessions(): JsonResponse { $sessions = Nimble::sessions()->list(); return response()->json([ 'sessions' => $sessions->map->toArray(), 'count' => $sessions->count(), ]); } }
Using in Jobs/Queues
<?php namespace App\Jobs; use AlexHackney\LaraNimble\Facades\Nimble; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class PublishStreamJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct( public string $app, public string $stream ) { } public function handle(): void { $success = Nimble::streams()->publish($this->app, $this->stream); if (!$success) { $this->fail('Failed to publish stream'); } } }
Configuration
The package is designed for minimal configuration. Only two settings are required in your .env:
NIMBLE_HOST=your-server.com # Required NIMBLE_TOKEN=your-token # Optional, only if server requires auth
All other settings have sensible defaults that work for most use cases. The config/nimble.php file shows all available options with their defaults:
return [ // Connection (only NIMBLE_HOST is required) 'host' => env('NIMBLE_HOST', 'localhost'), // Your Nimble server 'port' => env('NIMBLE_PORT', 8082), // Standard Nimble API port 'protocol' => env('NIMBLE_PROTOCOL', 'http'), // http or https // Authentication (optional) 'token' => env('NIMBLE_TOKEN'), // Only if server requires it // Request settings (rarely need changing) 'timeout' => env('NIMBLE_TIMEOUT', 30), // Seconds 'connect_timeout' => env('NIMBLE_CONNECT_TIMEOUT', 10), 'retry_times' => env('NIMBLE_RETRY_TIMES', 3), // Auto-retry failed requests 'retry_sleep' => env('NIMBLE_RETRY_SLEEP', 100), // Milliseconds // Logging (for debugging) 'log_requests' => env('NIMBLE_LOG_REQUESTS', false), 'log_channel' => env('NIMBLE_LOG_CHANNEL', 'stack'), // SSL (dev only - never disable in production) 'verify_ssl' => env('NIMBLE_VERIFY_SSL', true), ];
You only need to override these in .env if the defaults don't work for your setup.
Testing
The package includes comprehensive tests built with Test-Driven Development (TDD):
# Run all tests composer test # Run with coverage composer test-coverage # Run specific test suite vendor/bin/phpunit tests/Unit/Services/StreamServiceTest.php
Current Test Coverage:
- 127 tests
- 330 assertions
- Unit tests for all services, DTOs, and HTTP client
- Feature tests for Laravel integration
Troubleshooting
Connection Issues
If you're getting connection errors:
- Verify Nimble is running:
sudo systemctl status nimble - Check firewall allows port 8082
- Verify
NIMBLE_HOSTandNIMBLE_PORTin.env - Test API manually:
curl http://your-server:8082/manage/status
Authentication Errors
If you're getting 401/403 errors:
- Verify
management_tokenin/etc/nimble/nimble.confmatches yourNIMBLE_TOKEN - If not using authentication, remove
NIMBLE_TOKENfrom.env - Restart Nimble after config changes
SSL Verification Issues
For development/testing with self-signed certificates:
NIMBLE_VERIFY_SSL=false
Note: Never disable SSL verification in production!
API Documentation
For detailed Nimble API documentation, visit:
Development
Project Structure
lara-nimble/
├── src/
│ ├── Client/ # HTTP client & authentication
│ ├── DTOs/ # Data Transfer Objects
│ ├── Enums/ # Enums (protocols, statuses)
│ ├── Exceptions/ # Custom exceptions
│ ├── Facades/ # Laravel facades
│ ├── Services/ # Service classes
│ ├── Nimble.php # Main manager class
│ └── NimbleServiceProvider.php
├── tests/
│ ├── Feature/ # Laravel integration tests
│ └── Unit/ # Unit tests
└── config/
└── nimble.php # Package configuration
Contributing
This package is currently in active development. Contributions welcome!
- Follow PSR-12 coding standards
- Write tests for new features (TDD approach)
- Update documentation
- Ensure all tests pass:
composer test
Changelog
See CHANGELOG.md for version history.
License
The MIT License (MIT). See LICENSE for details.
Credits
Developed by: Alex Hackney
Built with:
- Laravel 10 & 11
- PHP 8.1+
- Nimble Streamer API
Artisan Commands
The package provides helpful Artisan commands for common operations:
Check Server Status
php artisan nimble:status
Displays server status, version, uptime, connections, and bandwidth statistics.
List Streams
php artisan nimble:streams
# Filter by status
php artisan nimble:streams --filter=active
php artisan nimble:streams --filter=inactive
Lists all streams with their status, protocol, viewers, and bitrate.
Clear Cache
php artisan nimble:cache:clear
# Clear specific cache type
php artisan nimble:cache:clear --type=hls
php artisan nimble:cache:clear --type=dash
Clears Nimble server cache.
Health Check
php artisan nimble:health
Performs a comprehensive health check of your Nimble server configuration.
Validation Rules
The package includes custom validation rules for Laravel forms:
use AlexHackney\LaraNimble\Rules\NimbleHostRule; use AlexHackney\LaraNimble\Rules\StreamProtocolRule; use AlexHackney\LaraNimble\Rules\StreamExistsRule; // Validate Nimble host connectivity $request->validate([ 'host' => ['required', new NimbleHostRule], ]); // Validate streaming protocol $request->validate([ 'protocol' => ['required', new StreamProtocolRule], ]); // Validate stream exists $request->validate([ 'stream_id' => ['required', new StreamExistsRule], ]);
Laravel Events
The package dispatches events for key actions, allowing you to hook into important moments:
Available Events
AlexHackney\LaraNimble\Events\StreamPublished- Fired when a stream is publishedAlexHackney\LaraNimble\Events\StreamUnpublished- Fired when a stream is unpublishedAlexHackney\LaraNimble\Events\SessionTerminated- Fired when a session is terminatedAlexHackney\LaraNimble\Events\CacheCleared- Fired when cache is cleared
Listening to Events
Create an event listener:
<?php namespace App\Listeners; use AlexHackney\LaraNimble\Events\StreamPublished; use Illuminate\Support\Facades\Log; class LogStreamPublished { public function handle(StreamPublished $event): void { Log::info('Stream published', [ 'app' => $event->app, 'stream' => $event->stream, ]); // Send notification, update database, etc. } }
Register in EventServiceProvider:
protected $listen = [ \AlexHackney\LaraNimble\Events\StreamPublished::class => [ \App\Listeners\LogStreamPublished::class, ], ];
Performance Optimizations
The package includes several performance optimizations:
- Service Caching: Service instances are cached within the Nimble manager to reduce memory usage
- Connection Pooling: HTTP connections are reused when possible
- Retry Logic: Automatic retry with exponential backoff for failed requests
- Lazy Loading: Services are only instantiated when needed
Contributing
We welcome contributions from the community! Here's how you can help:
Reporting Issues
If you find a bug or have a feature request, please:
- Check if the issue already exists in GitHub Issues
- If not, create a new issue with:
- Clear description of the problem or feature
- Steps to reproduce (for bugs)
- Laravel and PHP versions
- Nimble Streamer version
- Any relevant code samples or error messages
Pull Requests
We love pull requests! To contribute code:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Follow PSR-12 coding standards
- Write tests for new features (we use TDD!)
- Ensure all tests pass:
composer test - Run code formatting:
composer format - Run static analysis:
composer analyse - Commit your changes (
git commit -m 'Add amazing feature') - Push to your branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Guidelines
- Test-Driven Development: Write tests first, then implement features
- Type Safety: Use strict types and full type hints
- Documentation: Update README and inline docs for new features
- Backward Compatibility: Don't break existing APIs without major version bump
- Code Style: Follow PSR-12, use Laravel conventions
Running Tests
# Run all tests composer test # Run with coverage composer test-coverage # Run static analysis composer analyse # Format code composer format
Support
For issues and questions:
- GitHub Issues: Report an issue
- Source Code: View on GitHub
- Documentation: README
- Email: alex@alexhackney.com
Changelog
See CHANGELOG.md for version history and release notes.
Security
If you discover a security vulnerability, please email security@alexhackney.com instead of using the issue tracker. All security vulnerabilities will be promptly addressed.
Made with ❤️ using Test-Driven Development
Repository: https://github.com/alexhackney/lara-nimble