gotgcall

package module
v0.5.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 31, 2026 License: GPL-3.0 Imports: 9 Imported by: 0

README

gotgcall

Pure-Go library for streaming audio and video into Telegram group calls. A drop-in alternative to ntgcalls — no libwebrtc, no cgo, no native build chain. Just go build.

WebRTC runs on pion v4. ffmpeg is invoked as a runtime binary for transcoding; nothing is linked in.

Status

Work in progress. Built for my own bots; the API is intentionally close to ntgcalls so existing code translates with minimal change.

Install

go get gotgcall

ffmpeg must be on PATH at runtime (or set gotgcall.WithFFmpegPath("/path/to/ffmpeg")).

Sources

Three constructors, all targeting Opus-in-OGG (audio) or VP8-in-IVF (video):

gotgcall.FromFile("song.mp3")                        // local file
gotgcall.FromURL("https://stream.example.com/...")   // HTTP / HLS / RTMP
gotgcall.FromShell("ffmpeg -i thing.mp3 ...", gotgcall.TrackAudio)

Defaults to audio only. Pass EncodeOptions{Tracks: gotgcall.TrackAudio | gotgcall.TrackVideo} to also extract video.

FromShell accepts a partial command — missing essentials (-analyzeduration 0, -probesize 64k before -i; -c:a libopus, -f ogg, opus pacing, pipe:1 after) are filled in automatically. Raw-PCM output codecs are rejected up front; the frame readers can't parse them.

Quick start

client, _ := gotgcall.New()
defer client.Close()

client.OnStreamEnd(func(chat int64, t gotgcall.StreamType, d gotgcall.Device, err error) {
    log.Printf("stream end: %v", err)
})

// 1. Local-side JSON.
localParams, _ := client.CreateCall(chatID)

// 2. Drive Telegram via your MTProto layer (gogram, etc.).
//    Pass localParams to phone.JoinGroupCall; read the response.
remoteParams := joinViaYourMTProto(localParams)

// 3. Finish the WebRTC handshake.
client.Connect(chatID, remoteParams)

// 4. Stream.
client.SetStreamSources(chatID, gotgcall.FromFile("song.mp3"))

// 5. Pause / resume / mute / change source any time.
client.Pause(chatID)
client.Resume(chatID)
client.SetStreamSources(chatID, gotgcall.FromURL("https://stream.example.com/radio.m3u8"))

// 6. Stop tears down the call.
client.Stop(chatID)

The library is blob-only — it never imports gogram or any MTProto stack. You drive phone.JoinGroupCall / phone.LeaveGroupCall yourself; the library just produces and consumes JSON. See examples/bot/ for the full wiring against gogram.

RTMP mode

For "go live" (host) broadcasts, swap WebRTC for RTMP push. Obtain the URL via phone.GetGroupCallStreamRtmpUrl, then:

client.StartRTMP(chatID, rtmpURL)
client.SetStreamSources(chatID, gotgcall.FromFile("movie.mp4"))
// Pause/Resume/Stop work identically.

Pause is kill-and-restart-with--ss (Telegram's RTMP ingest times out silent streams; SIGSTOP can't be used).

Concurrency

One *Client per process multiplexes any number of group calls. Methods are safe for concurrent use; per-chat operations are serialised internally. Two concurrent CreateCalls for the same chat won't allocate twice — the per-chat creation mutex gates them.

Options

gotgcall.New(
    gotgcall.WithFFmpegPath("/opt/ffmpeg/bin/ffmpeg"),
    gotgcall.WithLogger(slog.Default()),
    gotgcall.WithSharedUDPMux(),    // single UDP socket for all calls (high-concurrency)
    gotgcall.WithDTLSCertPool(16),  // pre-generate N certs to absorb burst joins
    gotgcall.WithDispatchBuffer(512),
)

Callbacks

client.OnStreamEnd(func(chat int64, t StreamType, d Device, err error) { ... })
client.OnConnectionChange(func(chat int64, info NetworkInfo) { ... })

All callbacks fire from a single dispatcher goroutine so they can safely re-enter the API (e.g. call client.Stop from inside OnStreamEnd).

Server-side media-state changes (admin mute, video disabled) come in through your own gogram UpdateGroupCallParticipants handler — react there by calling client.Pause / client.Resume directly. The library deliberately stays out of MTProto.

Why pure Go

ntgcalls works fine but pulls in libwebrtc + glibc + a C++ build chain. Cross-compiling music bots becomes a maintenance burden. gotgcall builds with CGO_ENABLED=0 to a single static binary on every supported platform. The trade-off is ffmpeg as a runtime dependency, which most bot deployments already have.

License

MIT — see LICENSE.

Documentation

Overview

Package gotgcall is a pure-Go library for streaming audio and video into Telegram group calls. The public API mirrors ntgcalls method names so bot code translates one-to-one.

The library is blob-only: signaling JSON is exchanged through your own MTProto client (typically gogram). Two calls are required:

params, _ := client.CreateCall(chatID)
resp, _   := tg.PhoneJoinGroupCall(... Params: &DataJson{Data: params})
client.Connect(chatID, resp.Updates[...].Call.Params.Data)
client.SetStreamSources(chatID, gotgcall.FromFile("song.mp3"))

See README.md for the full pattern.

Index

Constants

View Source
const (
	TrackAudio = media.TrackAudio
	TrackVideo = media.TrackVideo

	Audio      = models.Audio
	Video      = models.Video
	Microphone = models.Microphone
	Camera     = models.Camera

	Connecting = models.Connecting
	Connected  = models.Connected
	Failed     = models.Failed
	Closed     = models.Closed
	Timeout    = models.Timeout
)

Variables

View Source
var (
	FromFile  = media.FromFile
	FromURL   = media.FromURL
	FromShell = media.FromShell
)
View Source
var (
	ErrConnectionExists   = models.ErrConnectionExists
	ErrConnectionNotFound = models.ErrConnectionNotFound
	ErrConnectionTimeout  = models.ErrConnectionTimeout
	ErrConnectionFailed   = models.ErrConnectionFailed
	ErrInvalidParams      = models.ErrInvalidParams
	ErrFFmpegSpawn        = models.ErrFFmpegSpawn
	ErrFFmpegCrashed      = models.ErrFFmpegCrashed
	ErrFile               = models.ErrFile
	ErrClosed             = models.ErrClosed
	ErrInternal           = models.ErrInternal
	ErrNotConnected       = models.ErrNotConnected
	ErrWrongMode          = models.ErrWrongMode
)

Functions

This section is empty.

Types

type CallInfo

type CallInfo = models.CallInfo

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client multiplexes many concurrent group calls behind a single process-wide handle. Safe for concurrent use.

func New

func New(opts ...Option) (*Client, error)

New constructs a Client with the given options.

func (*Client) AudioSSRC

func (c *Client) AudioSSRC(chatID int64) (uint32, error)

AudioSSRC returns the audio SSRC of a WebRTC call. Pass as Source to phone.LeaveGroupCall. Returns ErrWrongMode for RTMP calls.

func (*Client) Calls

func (c *Client) Calls() map[int64]CallInfo

Calls returns a snapshot of all active calls.

func (*Client) Close

func (c *Client) Close() error

Close stops every call and releases resources. Idempotent.

func (*Client) Connect

func (c *Client) Connect(chatID int64, telegramParams string) error

Connect finishes the WebRTC handshake using Telegram's response JSON.

func (*Client) CreateCall

func (c *Client) CreateCall(chatID int64) (string, error)

CreateCall starts a new WebRTC group-call instance for chatID and returns the JSON params the caller must pass to phone.JoinGroupCall.

Concurrent CreateCall / StartRTMP calls for the same chat are serialized; the first one wins, others get ErrConnectionExists without allocating a pion PeerConnection.

func (*Client) GetState

func (c *Client) GetState(chatID int64) (MediaState, error)

GetState returns the current media-state (mute/pause flags).

func (*Client) Mute

func (c *Client) Mute(chatID int64) (bool, error)

func (*Client) OnConnectionChange

func (c *Client) OnConnectionChange(fn func(chatID int64, info NetworkInfo))

OnConnectionChange registers a callback for ICE/DTLS state transitions.

func (*Client) OnStreamEnd

func (c *Client) OnStreamEnd(fn func(chatID int64, t StreamType, d Device, err error))

OnStreamEnd registers a callback fired when a track ends (EOF, crash, stop). Called on the dispatcher goroutine so it is safe to re-enter the Client API from within.

func (*Client) Pause

func (c *Client) Pause(chatID int64) (bool, error)

func (*Client) Resume

func (c *Client) Resume(chatID int64) (bool, error)

func (*Client) SetStreamSources

func (c *Client) SetStreamSources(chatID int64, src Source, opt ...EncodeOptions) error

SetStreamSources installs or replaces the streaming source for chatID.

func (*Client) StartRTMP

func (c *Client) StartRTMP(chatID int64, rtmpURL string) error

StartRTMP creates an RTMP-push call for chatID. The caller obtains rtmpURL via phone.GetGroupCallStreamRtmpUrl gogram-side. Serialised with CreateCall via the same per-chat creation mutex.

func (*Client) Stop

func (c *Client) Stop(chatID int64) error

Stop tears down the call and clears every per-chat scrap of state the library kept (call instance, create-mutex). After Stop the chatID can be re-used cleanly.

func (*Client) Time

func (c *Client) Time(chatID int64) (uint64, error)

Time returns elapsed ms of media pushed.

func (*Client) Unmute

func (c *Client) Unmute(chatID int64) (bool, error)

type ConnState

type ConnState = models.ConnState

type Device

type Device = models.Device

type EncodeOptions

type EncodeOptions = media.EncodeOptions

type MediaState

type MediaState = models.MediaState

type NetworkInfo

type NetworkInfo = models.NetworkInfo

type Option

type Option func(*config)

func WithDTLSCertPool

func WithDTLSCertPool(n int) Option

WithDTLSCertPool sets the size of the pre-generated DTLS certificate pool. Larger pools absorb bigger call-creation bursts without keygen latency. 0 disables pre-generation.

func WithDispatchBuffer

func WithDispatchBuffer(n int) Option

WithDispatchBuffer sizes the event dispatcher's channel. Default 256.

func WithFFmpegPath

func WithFFmpegPath(p string) Option

WithFFmpegPath overrides the ffmpeg binary path (default "ffmpeg").

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets a structured logger for internal events.

func WithSharedUDPMux

func WithSharedUDPMux() Option

WithSharedUDPMux makes all calls share one UDP socket for ICE traffic. Useful for high-concurrency setups (100+ simultaneous calls).

type SeekableSource

type SeekableSource = media.SeekableSource

type Source

type Source = media.Source

type StreamType

type StreamType = models.StreamType

type Track

type Track = media.Track

Directories

Path Synopsis
Package instances holds the per-chat call state.
Package instances holds the per-chat call state.
jsonparams
Package jsonparams encodes and decodes the SDP-like JSON envelope that Telegram's group-call signaling uses in place of standard SDP O/A.
Package jsonparams encodes and decodes the SDP-like JSON envelope that Telegram's group-call signaling uses in place of standard SDP O/A.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL