Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

73 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

rtmp_streaming

πŸ“– Overview

rtmp_streaming is a Flutter plugin that provides unified streaming and video recording for Android and iOS.

Protocol support

Protocol Android iOS Example URL
RTMP βœ… βœ… rtmp://host/live/stream
RTSP βœ… ❌ rtsp://host:8554/live
SRT βœ… βœ… srt://host:10080?streamid=#!::r=live/livestream,m=publish
UDP βœ… ❌ udp://host:5004
WHIP βœ… βœ… (alpha) https://host/whip
WHEP ❌ βœ… (alpha) https://host/whep

Pass an explicit StreamingProtocol (default rtmp). iOS WHIP/WHEP use RTCHaishinKit (H264/OPUS) and require Flutter SPM.


βš™οΈ Technical Foundation

By leveraging these mature libraries, rtmp_streaming provides a consistent cross-platform API interface, reducing development complexity.


❓ Why This Plugin

  • No suitable Flutter RTMP plugin exists on pub.dev.
  • Existing plugins suffer from:
    • Long-term lack of maintenance.
    • Outdated dependencies, incompatible with the latest Flutter and platform SDKs.

Therefore, the goal of rtmp_streaming is to deliver a modern, stable, and maintainable RTMP streaming solution.


πŸ› οΈ Supported Methods

🌍 Common Methods (Android & iOS)

  • πŸ“· Get available cameras: availableCameras
  • βš™οΈ Initialize plugin: initialize
  • 🎬 Prepare for streaming (optional, recommended on iOS): prepareForVideoStreaming
  • πŸŽ₯ Start local video recording: startVideoRecording
  • ⏹️ Stop local video recording: stopRecording
  • πŸ“‘ Start recording and streaming: startVideoRecordingAndStreaming
  • ⏹️ Stop recording or streaming: stopRecordingOrStreaming
  • πŸ“‘ Start video streaming: startVideoStreaming (url, protocol, bitrate; WHIP optional whipToken)
  • ⏹️ Stop video streaming: stopStreaming
  • πŸ”„ Switch camera: switchCamera
  • πŸ”Š Toggle mic capture on/off: switchAudio
  • πŸ”‡ Temporary mute while streaming: getHasAudio / setHasAudio
  • πŸŽ₯ Temporary video mute while streaming: getHasVideo / setHasVideo
  • 🎚️ Audio bitrate: setAudioSettings
  • 🎞️ Video encoder settings: setVideoSettings
  • 🎬 Frame rate: setFrameRate
  • πŸ’‘ Toggle flashlight: switchFlashLight
  • πŸ“Š Stream statistics: getStreamStatistics
  • πŸ—‘οΈ Dispose plugin: dispose
  • πŸ“Έ Snapshot while streaming: takePicture
  • πŸ–ΌοΈ Overlay text/image: setOverlayText / setOverlayImage / clearOverlay

🍎 iOS Exclusive Methods

Since HaishinKit supports RTMP playback as well as publishing:

  • ⏸️ Pause stream playback: pauseVideoStreamPlay (pauseStream)

    Note: pauses playback, not publishing.

  • ▢️ Resume stream playback: resumeVideoStreamPlay (resumeStream)
  • πŸ“± Multitasking camera: setMultitaskingCameraAccessEnabled (HaishinKit 2.2.5+, iOS 17+ when supported)
  • βš™οΈ Session preset: setSessionPreset
  • πŸ–ΌοΈ Screen dimensions: setScreenSettings
  • 🎞️ setVideoSettings extras: expectedFrameRate, bitRateMode (2.2.1+ / 2.2.2+), profileLevel
  • πŸ“‘ Multi-streaming: startMultiStreaming / stopStreamingDestination / stopMultiStreaming (no WHIP/WHEP)

πŸ€– Android Exclusive Methods

  • ⏸️ Pause recording: pauseVideoRecording
  • ▢️ Resume recording: resumeVideoRecording
  • 🎨 Apply filter: setFilter β€” see CameraNativeView.kt for type values
  • ❌ Remove filter: removeFilter
  • πŸŽ™οΈ Pitch shift: setPitchShift (RootEncoder PitchShiftEffect; 1.0 disables)
  • πŸ”’ Exposure lock: lockExposure / unlockExposure / isExposureLocked (after preview or streaming starts)
  • 🎨 BT.709 encoding: setForceBt709Color (RootEncoder 2.7.0+)
  • πŸ“Ά RTMP ping / RTT: setRtmpShouldSendPings (RootEncoder 2.7.0+, RTMP only)

πŸ“˜ API Usage

Recommended streaming flow (cross-platform)

final cameras = await availableCameras();
final controller = CameraController(
  ResolutionPreset.high,
  enableAudio: true,
);

await controller.initialize(cameras.first);

// iOS: pre-attach audio to reduce start latency
await controller.prepareForVideoStreaming();

await controller.setAudioSettings(128 * 1024); // bps
await controller.setVideoSettings(bitrate: 1500 * 1024);
await controller.setFrameRate(30);

if (Platform.isAndroid) {
  await controller.setForceBt709Color(true);
  await controller.setRtmpShouldSendPings(true);
}

if (Platform.isIOS) {
  await controller.setMultitaskingCameraAccessEnabled(true);
  await controller.setVideoSettings(
    expectedFrameRate: 30,
    bitRateMode: 'average',
  );
}

await controller.startVideoStreaming(
  'rtmp://your-server/live/stream-key',
  protocol: StreamingProtocol.rtmp,
);

// SRT (both platforms)
// await controller.startVideoStreaming(
//   'srt://your-server:10080?streamid=#!::r=live/livestream,m=publish',
//   protocol: StreamingProtocol.srt,
// );

// WHIP (Android + iOS alpha) / WHEP (iOS alpha)
// await controller.startVideoStreaming(
//   'https://your-server/whip',
//   protocol: StreamingProtocol.whip,
//   whipToken: 'optional-bearer-token',
// );
// await controller.startVideoStreaming(
//   'https://your-server/whep',
//   protocol: StreamingProtocol.whep,
// );

prepareForVideoStreaming()

  • Purpose: Pre-warm the capture session for streaming. On iOS, attaches audio early; on Android, no-op (safe to call for shared code).
  • When: After initialize, before startVideoStreaming.

switchAudio vs setHasAudio

Method Behavior Use case
switchAudio(false) Detach / re-attach mic capture Fully stop mic input
setHasAudio(false) Temporary mute while still capturing Quick mute without teardown
await controller.setHasAudio(false);
final sending = await controller.getHasAudio(); // false

await controller.switchAudio(false);

getHasVideo / setHasVideo

  • Purpose: Temporarily stop or resume sending video while streaming.
  • Platform: Android sends black frames via OpenGL; iOS uses mixer video mute.
  • When: While streaming.
await controller.setHasVideo(false);
final hasVideo = await controller.getHasVideo();
await controller.setHasVideo(true);

setAudioSettings(int bitrate)

  • Purpose: AAC encoder bitrate in bps.
  • When: After initialize, before starting stream/record.
await controller.setAudioSettings(128 * 1024);
await controller.startVideoStreaming(url);

setVideoSettings({ ... })

Parameter Cross-platform Notes
bitrate βœ… Android can hot-update while live via setVideoBitrateOnFly.
width / height Partial Prefer before go-live.
frameInterval Mostly iOS Keyframe interval (seconds).
profileLevel iOS only H.264 profile/level string.
expectedFrameRate iOS only RTMP onMetaData framerate (2.2.2+).
bitRateMode iOS only average / constant (iOS 16+) / variable (iOS 26+).
await controller.setVideoSettings(bitrate: 1200 * 1024);
await controller.setVideoSettings(bitrate: 800 * 1024); // hot update on Android

await controller.setVideoSettings(
  expectedFrameRate: 30,
  bitRateMode: 'average',
);

setFrameRate(int frameRate)

  • Purpose: Target capture/encode frame rate.
  • When: After initialize, before streaming.
await controller.setFrameRate(30);
await controller.startVideoStreaming(url);

getStreamStatistics()

Returns StreamStatistics while streaming. Key fields:

Field Description
bitrate, fps, width, height Stream metrics
cacheSize Send buffer size
sentAudioFrames / sentVideoFrames Android
droppedAudioFrames / droppedVideoFrames Android
isAudioMuted / isVideoMuted Both platforms (1.0.8+)
rttMicros Android RTT (requires setRtmpShouldSendPings)
bytesSend Bytes sent
final stats = await controller.getStreamStatistics();

Android: setForceBt709Color(bool enabled)

await controller.setForceBt709Color(true);
await controller.startVideoStreaming(url);

Android: setPitchShift(double pitch)

// Raise pitch (chipmunk). Pass 1.0 to disable.
await controller.setPitchShift(1.8);

Overlay: setOverlayText / setOverlayImage / clearOverlay

Works on Android and iOS. fontSize drives glyph size; scale is a % of natural size (100 = 1:1).

await controller.setOverlayText(
  text: 'LIVE',
  fontSize: 28,
  colorArgb: 0xFFFF0000,
  position: OverlayPosition.topLeft,
);
await controller.setOverlayImage(
  filePath: '/path/to/logo.png',
  position: OverlayPosition.bottomRight,
);
await controller.clearOverlay();

Multi-streaming: startMultiStreaming

iOS only. WHIP/WHEP are not allowed. Example app defaults to one RTMP + one SRT (dest1 / dest2); use Stop dest1 only to drop one path.

await controller.startMultiStreaming([
  StreamDestination(
    url: 'rtmp://a/live/live',
    protocol: StreamingProtocol.rtmp,
    id: 'a',
  ),
  StreamDestination(
    url: 'srt://a:10080?streamid=#!::r=live/livestream,m=publish',
    protocol: StreamingProtocol.srt,
    id: 'b',
  ),
]);
await controller.stopStreamingDestination('a');
await controller.stopMultiStreaming();

Android: lockExposure / unlockExposure / isExposureLocked

Call after preview or streaming has started.

final locked = await controller.lockExposure();
final isLocked = await controller.isExposureLocked();
await controller.unlockExposure();

Android: setRtmpShouldSendPings(bool enabled)

await controller.setRtmpShouldSendPings(true);
await controller.startVideoStreaming(url);
final stats = await controller.getStreamStatistics();
print(stats.rttMicros);

iOS: setMultitaskingCameraAccessEnabled(bool enabled)

await controller.setMultitaskingCameraAccessEnabled(true);
await controller.startVideoStreaming(url);

πŸš€ Conclusion

rtmp_streaming provides cross-platform RTMP streaming and recording for Flutter.
Since 1.0.8, temporary audio/video mute, encoder settings, and frame rate APIs are aligned on both platforms; iOS retains playback and multitasking extras, Android retains filters, BT.709, and RTT.

About

flutter_ rtmp_streaming is a Flutter plugin designed to provide unified RTMP streaming and video recording capabilities for Android and iOS.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages