npm.io
1.2.1 • Published 1 month ago

@astronautlabs/rtmp

Licence
MIT
Version
1.2.1
Deps
4
Size
610 kB
Vulns
0
Weekly
0
Stars
5

@/rtmp

Adobe RTMP (December 21, 2012)
Adobe’s Real Time Messaging Protocol (RTMP)

Stable
This library is a mostly-complete and working implementation of RTMP. (stable, semver 1.x.x).

Part of the Astronaut Labs Broadcast Suite

See also:

  • @/amf - Adobe's Action Message Format (AMF)
  • @/flv - Adobe's Flash Video format (FLV)

Comprehensive Typescript implementation of Adobe's Real Time Messaging Protocol (RTMP) using Bitstream

Motivation

This library is intended to provide an approachable and comprehensive RTMP implementation for Node.js using Typescript. It uses similar concepts to those of Adobe Flash / Flash Media Server / Flex in exposing RTMP to users. Supports AMF v0 and v3 via @astronautlabs/amf

Installation

npm i @astronautlabs/rtmp

Examples

Client (Publishing)

import 'reflect-metadata';
import 'source-map-support/register';

import * as RTMP from '@astronautlabs/rtmp';
import * as FLV from '@astronautlabs/flv';

async function publish() {
    let client = new RTMP.Client();

    // Connect to the server and issue the RTMP `connect` command.
    await client.connect({ host: 'localhost', app: 'live' });

    // Allocate a message stream and begin publishing under a stream key.
    let stream = await client.createStream();
    await stream.publish('my-stream-key', 'live');

    // Send stream metadata (onMetaData).
    stream.sendMetadata({ 
        width: 1280, 
        height: 720, 
        framerate: 30,
        videocodecid: FLV.VideoCodec.AVC,
        audiocodecid: FLV.AudioCodec.AAC,
    });

    // Send audio/video. Payloads are FLV tag bodies (a raw Buffer or a
    // VideoMessageData/AudioMessageData). Send codec sequence headers first.
    // You can use `@astronautlabs/flv` to construct these.
    stream.sendVideo(0, avcSequenceHeaderBody);
    stream.sendAudio(0, aacSequenceHeaderBody);
    stream.sendVideo(0, videoFrameBody);
    stream.sendAudio(23, audioFrameBody);

    // When finished:
    await stream.unpublish();
    client.disconnect();
}

Custom server RPC calls can be invoked with client.call('commandName', [args]) (awaits the _result/_error response). Subclass RTMP.Client and decorate methods with @RPC() (or override receiveCall) to handle server-initiated commands. A runnable loopback example is available via npm run sample:client (src/client.example.ts).

Server

import 'reflect-metadata';
import 'source-map-support/register';

import { Socket } from 'net';
import * as RTMP from '@astronautlabs/rtmp';

class MyServer extends RTMP.Server {
    protected createSession(socket: Socket): RTMP.Session {
        return new MySession(this, socket);
    }
}

class MySession extends RTMP.Session {
    protected createStream(id: number): RTMP.ServerMediaStream {
        return new MyStream(this, id);
    }
}

class MyStream extends RTMP.ServerMediaStream {
    play(streamName: string, start: number, duration: number, reset: boolean): void {
        // Client wants to receive this stream.

        this.notifyBegin();

        this.sendVideo(Buffer.from([ ... ]));
        this.sendAudio(Buffer.from([ ... ]));
    }

    publish(streamName : string) {
        // Client is publishing this stream
    }

    receiveVideo(data : Uint8Array) {
        // Do something with the video packets
    }

    receiveAudio(data : Uint8Array) {
        // Do something with the audio packets
    }
}

let server = new MyServer();
server.listen();

Custom RPC

import 'reflect-metadata';
import 'source-map-support/register';

import { Socket } from 'net';
import * as RTMP from '.';

class MyServer extends RTMP.Server {
    protected createSession(socket: Socket): RTMP.Session {
        return new MySession(this, socket);
    }
}

class MySession extends RTMP.Session {
    protected createStream(id: number): RTMP.ServerMediaStream {
        return new MyStream(this, id);
    }
}

class MyStream extends RTMP.ServerMediaStream {

    /**
     * Mark any method with `@RPC()` to expose it as an RTMP command.
     * Here the command 'customMethod' gets mapped to this method, with
     * its parameters automatically converted from AMF0/3 to the appropriate
     * Javascript types, and the return value being sent back in a "_result" 
     * response. If an exception is thrown, an "_error" response is sent back with 
     * a summary of the error.
     */
    @RPC() customMethod(foo : string, bar : number[]) {
        return { message: 'All done!' };
    }

    play(streamName: string, start: number, duration: number, reset: boolean): void {
        console.log(`play('${streamName}', ${start}, ${duration}, ${reset})`);
        super.play(streamName, start, duration, reset);
    }
}

let server = new MyServer();
server.listen();

Keywords