npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@epicnephrin/react-native-rtmp-publisher

v0.1.1

Published

iOS-only React Native New Architecture RTMP publisher optimized for Mux Live ingest.

Readme

@epicnephrin/react-native-rtmp-publisher

@epicnephrin/react-native-rtmp-publisher is an iOS-only React Native RTMP/RTMPS publisher for Mux Live ingest. It uses native camera and microphone capture, VideoToolbox H.264 encoding, AAC-LC audio, FLV packaging, and RTMP/RTMPS transport.

Requirements

  • iOS only
  • React Native New Architecture only
  • Expo prebuild/custom dev client or bare React Native iOS app
  • Expo Go is not supported

Features

  • Native local camera preview via RtmpPublisherView
  • Singleton TurboModule session API
  • H.264 hardware video encoding with VideoToolbox
  • AAC-LC audio encoding
  • FLV muxing and RTMP/RTMPS publishing
  • Camera switching, torch, zoom, focus, mute, bitrate control
  • Reconnect logic and runtime stats
  • Orientation-aware publishing: portrait, landscapeLeft, landscapeRight
  • Expo config plugin for camera/microphone permissions and iOS pod integration

Installation

npm install @epicnephrin/react-native-rtmp-publisher

If you use Expo, add the config plugin and enable the New Architecture:

{
  "expo": {
    "newArchEnabled": true,
    "plugins": ["@epicnephrin/react-native-rtmp-publisher"]
  }
}

The config plugin is expected to handle iOS permission setup and the native registration glue needed for Expo prebuild apps. Consumer apps should not need manual Podfile edits or patch-package.

Current status for Expo SDK 55 / React Native 0.83:

  • consumer apps should use only the package plus the Expo config plugin
  • the package still applies a package-owned iOS registration workaround during prebuild
  • the package plugin also injects the iOS pod for this library on this stack because Expo autolinking is not reliably discovering it
  • this is temporary and exists because current Expo/RN iOS codegen does not reliably generate the required provider registration for this library
  • the package also ships vendored iOS codegen artifacts on this stack, and the podspec exposes the vendored codegen include root required by those generated sources
  • this is not a consumer-owned patch and should not require manual native edits in the app

Then generate and build iOS native code:

npx expo prebuild --platform ios
npx expo run:ios

Use a custom dev client or production build. Expo Go is unsupported.

Important:

  • native code changes require a fresh native rebuild
  • a JS reload alone is only enough for JS-only changes

Mux Integration

Your backend should create the Mux live stream and return a publish URL or stream key to the broadcaster. The app should publish to:

rtmps://global-live.mux.com:443/app/<stream_key>

Do not call the Mux API directly from the device and do not embed long-lived Mux secrets in the app.

Quick Start

import React, { useEffect, useState } from 'react';
import { Button, View } from 'react-native';
import {
  MUX_PORTRAIT_720P,
  NativeRtmpPublisher,
  RtmpPublisherView,
  type CameraPosition,
  type PublisherConfig,
} from '@epicnephrin/react-native-rtmp-publisher';

const PUBLISH_URL = 'rtmps://global-live.mux.com:443/app/<stream_key>';

export default function LiveScreen() {
  const [cameraPosition, setCameraPosition] = useState<CameraPosition>('front');

  useEffect(() => {
    const config: PublisherConfig = {
      ...MUX_PORTRAIT_720P,
      video: {
        ...MUX_PORTRAIT_720P.video,
        orientation: 'portrait',
      },
      camera: {
        ...MUX_PORTRAIT_720P.camera,
        position: cameraPosition,
        mirrorPreview: cameraPosition === 'front',
      },
    };

    void NativeRtmpPublisher.prepare(config);

    return () => {
      void NativeRtmpPublisher.destroy();
    };
  }, [cameraPosition]);

  async function startLive() {
    await NativeRtmpPublisher.startPublish(PUBLISH_URL);
  }

  async function stopLive() {
    await NativeRtmpPublisher.stopPublish();
  }

  async function switchCamera() {
    await NativeRtmpPublisher.switchCamera();
    setCameraPosition((current) => (current === 'front' ? 'back' : 'front'));
  }

  return (
    <View style={{ flex: 1 }}>
      <RtmpPublisherView
        style={{ flex: 1 }}
        cameraPosition={cameraPosition}
        mirrorPreview={cameraPosition === 'front'}
        resizeMode="cover"
      />
      <Button title="Go live" onPress={startLive} />
      <Button title="Switch camera" onPress={switchCamera} />
      <Button title="Stop" onPress={stopLive} />
    </View>
  );
}

Orientation

Set orientation in config.video.orientation:

  • portrait
  • landscapeLeft
  • landscapeRight

Notes:

  • the selected orientation is fixed for the prepared session
  • change orientation by stopping or destroying, then calling prepare() again with a new config
  • the local preview is intended to follow the selected session orientation

Preset

The package currently ships:

  • MUX_PORTRAIT_720P

It is a portrait-oriented Mux preset with:

  • 720x1280
  • 30fps
  • 1.8 Mbps video bitrate
  • 128 kbps mono AAC audio

TurboModule API

  • prepare(config: PublisherConfig): Promise<void>
  • startPublish(url: string): Promise<void>
  • stopPublish(): Promise<void>
  • destroy(): Promise<void>
  • switchCamera(): Promise<void>
  • setMuted(muted: boolean): Promise<void>
  • setTorch(enabled: boolean): Promise<void>
  • setZoom(zoom: number): Promise<void>
  • focus(point: { x: number; y: number }): Promise<void>
  • setVideoBitrate(bitrate: number): Promise<void>
  • requestKeyFrame(): Promise<void>
  • getStats(): Promise<PublisherStats>
  • getDebugSnapshot(): Promise<PublisherDebugSnapshot>

Events

  • onStateChange
  • onError
  • onStats
  • onDiagnostic
  • onPublishStarted
  • onPublishStopped
  • onCameraChanged
  • onNetworkHealth

Example:

const statsSub = NativeRtmpPublisher.addEventListener('onStats', (stats) => {
  console.log('publisher stats', stats);
});

const errorSub = NativeRtmpPublisher.addEventListener('onError', (error) => {
  console.error('publisher error', error);
});

const diagnosticSub = NativeRtmpPublisher.addEventListener(
  'onDiagnostic',
  (event) => {
    console.log('publisher diagnostic', event);
  },
);

// cleanup
statsSub.remove();
errorSub.remove();
diagnosticSub.remove();

Types

Important public types:

  • PublisherConfig
  • PublisherStats
  • PublisherDebugSnapshot
  • PublisherError
  • PublisherOrientation
  • CameraPosition
  • ResizeMode

PublisherStats and PublisherDebugSnapshot expose detailed runtime fields such as:

  • current publisher state
  • startup stage
  • transport (rtmp / rtmps)
  • orientation
  • bytes sent
  • video packet counters
  • encoded frame counters
  • RTMP status details

getDebugSnapshot() is useful when runtime event delivery is unavailable or incomplete in a host app.

Expo Notes

  • Use a real iPhone for end-to-end camera and microphone validation
  • If you change native Swift/ObjC code, plugins, podspecs, or codegen surfaces, rebuild the native app
  • If you only change JS/TS code, a Metro reload is usually enough
  • On Expo SDK 55 / React Native 0.83, the package plugin currently injects the iOS pod and patches generated iOS registration files during prebuild so the TurboModule and Fabric view are registered correctly
  • On this same stack, the package still relies on vendored/generated iOS codegen artifacts that are compiled from the pod target
  • The intended consumer contract is still zero manual native setup: no app-side Podfile edits and no patch-package
  • Pure autolinking/codegen without that package-owned workaround is not yet claimed for this Expo/RN line

Publishing To npm

The package is configured for a public scoped npm release:

  • package name: @epicnephrin/react-native-rtmp-publisher
  • first publish uses public access automatically via publishConfig.access

Recommended release flow:

npm version patch
npm publish

Notes:

  • prepublishOnly runs npm run build, so the published tarball includes fresh compiled output
  • if this is the first publish for the @epicnephrin scope, the npm account you use must own that scope or have publish rights to it
  • if 0.1.0 is already published, bump to the next version before publishing

Constraints

  • single publisher session only
  • iOS only
  • New Architecture only
  • Expo Go unsupported

Development

npm install
npm run typecheck
npm test