Überblick
AIR bietet derzeit keine aktuelle Implementierung für Echtzeit-Medien-Streaming. KlugMedia ergänzt sie als native Erweiterung. Kamera, Mikrofon, Encoder und Echounterdrückung laufen gemeinsam in einer nativen Sitzung, und ActionScript sendet nur Befehle und empfängt Status.
Video wird als H.264 gesendet und empfangen, Sprache als Opus, beides über Standard-RTMP. Empfangenes Video wird nativ über der AIR-Stage gezeichnet und bleibt dadurch auch auf älteren Geräten scharf und flüssig.
KlugMedia ist in unseren Apps täglich im Einsatz, unserem Praxisbeweis, im App Store, bei Google Play und auf dem Mac.
Funktionen
- Eigenständig: eine ANE, keine Kernbibliothek und keine abhängigen ANEs, die Sie ergänzen müssten
- Kameraaufnahme und H.264-Publishing in einer nativen Sitzung
- Nativer H.264-Empfang und native Anzeige, seitenverhältnistreu, mit Zuschneiden zum Füllen und Rotation
- Bidirektionale Opus-Sprache mit Hardware-Echounterdrückung, beide Seiten sprechen gleichzeitig
- Native Kameravorschau, Kamerawechsel, Taschenlampe und Zoom
- Schnappschüsse direkt aus dem Kamerabild
- MP4-Aufzeichnung von Live-Streams auf dem Klug Streaming Server, mit Bild und Ton
- Automatische Bitratenanpassung in schwachen Netzen
- Adaptiver Sprachpuffer, der WLAN-Aussetzer überbrückt und von selbst zu niedriger Verzögerung zurückkehrt
- Auf dem Mac: Wechsel zwischen eingebauter Kamera und USB-Kameras in etwa einer Sekunde
- Standard-RTMP, daher kompatibel mit gewöhnlichen Medienservern
Streaming-Server
KlugMedia wird mit der passenden Server-Software geliefert, gemeinsam mit der Erweiterung entwickelt und auf AIR-Apps abgestimmt: Stream-Verwaltung, zuverlässige Wiederverbindung, das Relay für bidirektionale Sprache, MP4-Aufzeichnung und Live-Wiedergabe im Webbrowser.
Unterstützte Plattformen
iPad-Apps auf dem Mac
Auf Macs mit Apple Silicon kann der iOS-Build einer AIR-App als iPad-App laufen. KlugMedia unterstützt diesen Modus mit Kamera, Live-Video und bidirektionaler Sprache, einschließlich der eingebauten FaceTime-Kamera und externer USB-Kameras. Ein Build bedient iPhone, iPad und Mac.
Bereit für iOS 27 und macOS 27
KlugMedia ist getestet auf iOS 27, iPadOS 27 und macOS 27, auf iPhone, iPad, MacBook und Mac mini, und weiterhin auf iOS 17. Highlights dieser Version:
- Gehärteter Empfangspfad: Das Stoppen und Neustarten eines Live-Streams ist jederzeit sicher, auch bei dem Timing von iOS 27
- Stabile Kameravorschau unter macOS 27 für iPad-Apps auf dem Mac, während die Kamera startet, stoppt oder wechselt
- Korrekte Ausrichtung auf jedem Mac: Eingebaute und USB-Kameras stehen in der Vorschau und beim Empfänger aufrecht, unter macOS 26 und 27
- Schneller Kamerawechsel auf dem Mac zwischen der FaceTime-Kamera und USB-Kameras, in etwa einer Sekunde
- Klare Sprache im Laptop-WLAN: Ein adaptiver Puffer fängt die kurzen WLAN-Bursts ab, die bei MacBooks typisch sind, und schrumpft wieder, wenn das Netz ruhig ist
Erste Schritte
Fügen Sie die Erweiterung Ihrem Application Descriptor hinzu:
<extensions>
<extensionID>com.klug.media</extensionID>
</extensions>
Fordern Sie vor dem ersten Start die Kamera- und Mikrofonberechtigung an. Danach besitzt die Erweiterung die Aufnahme: Öffnen Sie nicht gleichzeitig eine AIR-Camera oder ein AIR-Microphone.
Codebeispiele
Fünf vollständige Abläufe, entnommen der API, die täglich in unseren Apps läuft. Jeder Aufruf kehrt sofort zurück; Ergebnisse kommen als StatusEvents an. Vollständige Dokumentation →
import com.klug.petcam.camera.CameraStreamANE; import flash.events.StatusEvent; var media:CameraStreamANE = CameraStreamANE.instance; media.addEventListener( StatusEvent.STATUS, onMedia ); if ( media.isSupported ) { // camera, H.264 encoder and RTMP in one native session media.startPublish( "rtmp://your.server:1935/live", "station-1", 640, 480, // size 12, 800, // fps, kbps 2, // keyframe every 2 s: fast start at the viewer CameraStreamANE.CAMERA_BACK ); } function onMedia( e:StatusEvent ):void { if ( e.code != CameraStreamANE.STATUS_EVENT ) return; if ( e.level == "connected" ) showLive(); else if ( e.level.indexOf( "failed:" ) == 0 ) retryLater( e.level.substr( 7 ) ); else if ( e.level.indexOf( "authError:" ) == 0 ) askForLogin(); }
// the video is decoded natively and drawn in a view above the stage (pixels) media.startReceive( "rtmp://your.server:1935/live", "station-1", 0, 80, stage.stageWidth, stage.stageHeight - 160, 0, CameraStreamANE.RECEIVE_FIT ); // or RECEIVE_CROPFILL media.addEventListener( StatusEvent.STATUS, function( e:StatusEvent ):void { if ( e.code == "receiveStatus" && e.level == "firstFrame" ) hideSpinner(); }); // rotation, a folding phone, fullscreen: move the native view with the stage stage.addEventListener( Event.RESIZE, function( e:Event ):void { media.setReceiveFrame( 0, 80, stage.stageWidth, stage.stageHeight - 160 ); });
import com.klug.petcam.audioecho.*; var voice:OpusVoiceBridge = new OpusVoiceBridge( new NativeOpusCodec(), 48000, 1, 960 ); var link:Red5OpusTransport; var nc:NetConnection = new NetConnection(); nc.addEventListener( NetStatusEvent.NET_STATUS, function( e:NetStatusEvent ):void { if ( e.info.code == "NetConnection.Connect.Success" ) startVoice(); }); nc.connect( "rtmp://your.server:1935/live" ); function startVoice():void { link = new Red5OpusTransport( nc ); link.addEventListener( OpusPacketEvent.PACKET, function( e:OpusPacketEvent ):void { voice.playRemoteOpus( e.packet ); // decode and play the other side }); link.start( "voice_me", "voice_other" ); // my stream, the other side's stream voice.setVoiceProcessing( true ); // hardware echo cancellation EchoCancellationANE.instance.setDuck( false ); // both sides may talk at once voice.start(); addEventListener( Event.ENTER_FRAME, sendVoice ); } function sendVoice( e:Event ):void { var packet:ByteArray; while ( ( packet = voice.readLocalOpus() ) != null ) // every finished 20 ms frame link.sendPacket( packet ); }
media.showPreview( 20, 100, 320, 240, CameraStreamANE.CAMERA_FRONT ); // aiming preview media.switchCamera(); // front / back, or built-in / USB camera on the Mac if ( media.hasTorch ) media.setTorch( true ); media.setCameraZoom( 4 ); // 0..8 = 1.0x..2.0x, the stream is zoomed too media.setVideoBitrate( 500 ); // change the bitrate while live media.addEventListener( StatusEvent.STATUS, function( e:StatusEvent ):void { if ( e.code == "snapshotStatus" && e.level.indexOf( "saved:" ) == 0 ) showPhoto( e.level.substr( 6 ) ); // absolute path of the JPEG }); media.captureSnapshot( 640, 480 ); media.hidePreview(); // native views sit above the stage: hide them before dialogs
function stopAll():void { removeEventListener( Event.ENTER_FRAME, sendVoice ); voice.stop(); link.stop(); media.stopReceive(); media.stopPublish(); // always stop before publishing the same name again } // safe at any moment, also while a stream is still connecting stopAll(); media.startPublish( "rtmp://your.server:1935/live", "station-1" );
API-Übersicht
| isSupported | True, wenn die native Mediensitzung verfügbar ist. |
| startPublish(…) | Startet die Kamera und sendet H.264 über RTMP: Größe, fps, Bitrate, Keyframe-Intervall, Kamera, optionale RTMP-Anmeldung. |
| stopPublish() | Beendet das Senden; die Kamera wird freigegeben, sofern die Vorschau nicht noch angezeigt wird. |
| startReceive(…) | Spielt einen entfernten Stream nativ in einem Rechteck der Stage ab: Seitenverhältnis einpassen oder Zuschneiden zum Füllen mit Rotation (Strecken unter Android). |
| setReceiveFrame(x, y, w, h) | Verschiebt und skaliert das native Video, für Rotation, faltbare Smartphones und Vollbild. |
| stopReceive() | Beendet die Wiedergabe und entfernt die native Ansicht. |
| showPreview(…) / hidePreview() | Native Kameravorschau über der Stage, allein oder neben einem laufenden Stream. |
| switchCamera() | Wechselt während des Streamings zur nächsten Kamera: vorne und hinten auf iPhone und iPad, eingebaute und USB-Kameras auf dem Mac. |
| setTorch(on) / hasTorch | Kameralicht während des Streamings und ob das Gerät eines hat. |
| setCameraZoom(step) | Echter Kamerazoom unter iOS und Android, 0..8 für 1,0x bis 2,0x; der Stream wird mitgezoomt. |
| setVideoBitrate(kbps) | Ändert die Encoder-Bitrate im laufenden Betrieb. |
| captureSnapshot(w, h) | Speichert ein JPEG aus dem Live-Kamerabild. |
| isiOSAppOnMac | True, wenn der iOS-Build als iPad-App auf einem Mac mit Apple Silicon läuft. |
| OpusVoiceBridge | Bidirektionale Sprache: Start, Stopp, Echounterdrückung, Lautsprecher, Verstärkung, Wiedergabepuffer. |
| Red5OpusTransport | Überträgt die Opus-Pakete über Ihre RTMP-Verbindung auf zwei dedizierten Streams. |
Status-Ereignisse
| cameraStatus | connecting · connected · disconnected · failed:<reason> · authError:<reason> · newBitrate:<rate> · authSuccess (Android) |
| receiveStatus | playing · firstFrame · disconnected · streamEnded und failed:<reason> (iOS, macOS) |
| snapshotStatus | saved:<path> · failed:<reason> |
KlugMedia kaufen
Eine Jahreslizenz für eine AIR-Anwendung, mit allen Updates für 12 Monate. Nach der Zahlung erhalten Sie die Erweiterung, die ActionScript-Bibliothek und die Dokumentation per E-Mail, in der Regel innerhalb eines Werktags. Lizenz und Bedingungen
- Lizenz für eine AIR-Anwendung
- Alle Updates für 12 Monate
- Kein Support
- Lizenz für eine AIR-Anwendung
- Alle Updates für 12 Monate
- Antwort per E-Mail innerhalb von 7 Tagen
- Lizenz für eine AIR-Anwendung
- Alle Updates für 12 Monate
- Antwort per E-Mail innerhalb von 48 Stunden
Voraussetzungen
| AIR SDK | 51.x (HARMAN) |
| iOS | iOS 17 oder neuer |
| Android | Android 6.0 (API 23) oder neuer |
| macOS | macOS 11 oder neuer |
| iPad-Apps auf dem Mac | Apple Silicon, macOS 26 oder neuer |
| Berechtigungen | Kamera und Mikrofon |
| Server | Jeder RTMP-Server; empfohlen wird der passende Klug Streaming Server |