← Todas las extensiones

Extensión nativa · Insignia

KlugMedia

com.klug.media

NO NECESITAS APM. Descarga y disfruta. No puede ser más sencillo.

Cámara, voz bidireccional y cancelación de eco por hardware en una sola sesión nativa, con publicación y recepción de H.264 y Opus sobre RTMP estándar.

iOSAndroidmacOS En producción Desde €99 / año · Comprar

Resumen

Actualmente AIR no ofrece una implementación actualizada para streaming de medios en tiempo real. KlugMedia la añade como extensión nativa. Cámara, micrófono, codificador y cancelación de eco se ejecutan juntos en una sola sesión nativa, y ActionScript solo envía comandos y recibe estados.

El vídeo se publica y se recibe como H.264 y la voz como Opus, ambos sobre RTMP estándar. El vídeo recibido se dibuja de forma nativa sobre el escenario de AIR, por lo que se mantiene nítido y fluido incluso en dispositivos antiguos.

KlugMedia se usa a diario en nuestras apps, nuestra prueba de concepto, en la App Store, Google Play y el Mac.

Funciones

  • Autónoma: una ANE, sin biblioteca central ni ANE de dependencias que añadir
  • Captura de cámara y publicación en H.264 en una sola sesión nativa
  • Recepción y visualización nativas de H.264, con proporción correcta, recorte para rellenar y rotación
  • Voz Opus bidireccional con cancelación de eco por hardware, con ambos lados hablando a la vez
  • Vista previa nativa de la cámara, cambio de cámara, linterna y zoom
  • Capturas tomadas directamente de la imagen de la cámara
  • Grabación en MP4 de streams en directo en el servidor de streaming de Klug, con imagen y sonido
  • Adaptación automática del bitrate en redes débiles
  • Búfer de voz adaptativo que absorbe los cortes del Wi-Fi y vuelve solo a una latencia baja
  • En el Mac: cambia entre la cámara integrada y las cámaras USB en aproximadamente un segundo
  • RTMP estándar, por lo que funciona con servidores de medios convencionales

Servidor de streaming

KlugMedia incluye software de servidor a juego, desarrollado junto con la extensión y ajustado para apps AIR: gestión de streams, reconexiones fiables, retransmisión de voz bidireccional, grabación en MP4 y visualización en directo en un navegador web.

El servidor se describe en la página de resumen: Servidor de streaming.

Plataformas compatibles

iOS arm64
Android arm64 · armv7
macOS Apple silicon · Intel
Apps de iPad en el Mac Apple silicon · macOS 26 y 27

Apps de iPad en el Mac

En Macs con Apple silicon, la compilación de iOS de una app AIR puede ejecutarse como app de iPad. KlugMedia admite este modo con cámara, vídeo en directo y voz bidireccional, incluida la cámara FaceTime integrada y las cámaras USB externas. Una sola compilación sirve para iPhone, iPad y Mac.

Listo para iOS 27 y macOS 27

KlugMedia está probada en iOS 27, iPadOS 27 y macOS 27, en iPhone, iPad, MacBook y Mac mini, y también en iOS 17. Novedades de esta versión:

  • Ruta de recepción reforzada: detener y reiniciar un stream en directo es seguro en cualquier momento, también con los tiempos de iOS 27
  • Vista previa de cámara estable en macOS 27 para apps de iPad en el Mac, mientras la cámara arranca, se detiene o cambia
  • Orientación correcta en cada Mac: las cámaras integradas y USB se ven derechas en la vista previa y en el receptor, en macOS 26 y 27
  • Cambio rápido de cámara en el Mac entre la cámara FaceTime y las cámaras USB, en aproximadamente un segundo
  • Voz clara con el Wi-Fi del portátil: un búfer adaptativo absorbe las ráfagas breves de Wi-Fi típicas de los MacBook y se reduce de nuevo cuando la red está tranquila

Primeros pasos

Añade la extensión al descriptor de tu aplicación:

app.xml
<extensions>
    <extensionID>com.klug.media</extensionID>
</extensions>

Solicita el permiso de cámara y micrófono antes del primer inicio. A partir de entonces la extensión controla la captura: no abras a la vez una Camera o un Microphone de AIR.

Ejemplos de código

Cinco flujos completos, tomados de la API que funciona a diario en nuestras apps. Cada llamada devuelve de inmediato; los resultados llegan como StatusEvents. Documentación completa →

1 · Publicar un stream de cámara
Station.as
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();
}
2 · Recibir y seguir el diseño
Viewer.as
// 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 );
});
3 · Voz bidireccional con cancelación de eco
Voice.as
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 );
}
Los paquetes de voz viajan como mensajes de datos en su propio par de streams. El servidor de streaming de Klug los retransmite sin configuración adicional; otros servidores RTMP deben reenviar NetStream.send a los suscriptores.
4 · Vista previa, cambio de cámara, linterna, zoom, captura
Controls.as
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
5 · Parada y reinicio limpios
Session.as
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" );

Resumen de la API

isSupportedVerdadero donde la sesión nativa de medios está disponible.
startPublish(…)Inicia la cámara y publica H.264 sobre RTMP: tamaño, fps, bitrate, intervalo de fotogramas clave, cámara, inicio de sesión RTMP opcional.
stopPublish()Detiene la publicación; la cámara se libera salvo que la vista previa siga visible.
startReceive(…)Reproduce un stream remoto de forma nativa dentro de un rectángulo del escenario: ajuste a proporción o recorte para rellenar con rotación (estirado en Android).
setReceiveFrame(x, y, w, h)Mueve y redimensiona el vídeo nativo, para rotación, teléfonos plegables y pantalla completa.
stopReceive()Detiene la reproducción y elimina la vista nativa.
showPreview(…) / hidePreview()Vista previa nativa de la cámara sobre el escenario, sola o junto a una publicación en directo.
switchCamera()Cambia a la siguiente cámara durante el streaming: frontal y trasera en iPhone y iPad, integrada y USB en el Mac.
setTorch(on) / hasTorchLuz de la cámara durante el streaming y si el dispositivo dispone de ella.
setCameraZoom(step)Zoom real de la cámara en iOS y Android, 0..8 para 1.0x a 2.0x; el stream también se amplía.
setVideoBitrate(kbps)Cambia el bitrate del codificador en directo.
captureSnapshot(w, h)Guarda un JPEG de la imagen de la cámara en directo.
isiOSAppOnMacVerdadero cuando la compilación de iOS se ejecuta como app de iPad en un Mac con Apple silicon.
OpusVoiceBridgeVoz bidireccional: inicio, parada, cancelación de eco, altavoz, ganancia, búfer de reproducción.
Red5OpusTransportTransporta los paquetes Opus por tu conexión RTMP en dos streams dedicados.

Eventos de estado

cameraStatusconnecting · connected · disconnected · failed:<reason> · authError:<reason> · newBitrate:<rate> · authSuccess (Android)
receiveStatusplaying · firstFrame · disconnected · streamEnded y failed:<reason> (iOS, macOS)
snapshotStatussaved:<path> · failed:<reason>

Compra KlugMedia

Una licencia anual para una aplicación AIR, con todas las actualizaciones durante 12 meses. Tras el pago recibes la extensión, la biblioteca ActionScript y la documentación por e-mail, normalmente en un día hábil. Licencia y términos

Simple
€99 / año
  • Licencia para una aplicación AIR
  • Todas las actualizaciones durante 12 meses
  • Sin soporte
Comprar Simple
Standard
€349 / año
  • Licencia para una aplicación AIR
  • Todas las actualizaciones durante 12 meses
  • Respuesta por e-mail en un plazo de 7 días
Comprar Standard
Priority
€699 / año
  • Licencia para una aplicación AIR
  • Todas las actualizaciones durante 12 meses
  • Respuesta por e-mail en un plazo de 48 horas
Comprar Priority
Link (Stripe) calcula los impuestos al pagar. Durante el pago indicas el ID de aplicación de tu app AIR.

Requisitos

AIR SDK51.x (HARMAN)
iOSiOS 17 o posterior
AndroidAndroid 6.0 (API 23) o posterior
macOSmacOS 11 o posterior
Apps de iPad en el MacApple silicon, macOS 26 o posterior
PermisosCámara y micrófono
ServidorCualquier servidor RTMP; se recomienda el servidor de streaming de Klug a juego