MadelineProto 8.20: video calls, group calls, livestreams and E2E conferences in pure PHP, 250x faster crypto, rich messages and much more

· MadelineProto · 10 min read

MadelineProto 8.20.1 is out, and it’s the biggest update since MadelineProto 8.0!

Since 8.7.0, MadelineProto has gained video calls, group calls, livestreams, live stories and end-to-end encrypted conference calls, all in pure PHP: calls run on a pure PHP WebRTC stack, with pure PHP OPUS and AAC codecs. No FFI, no extensions, no shell commands and no ffmpeg, so everything works on webhosts, too! Over 43 releases (8.8.8 → 8.20.1), we also added rich messages, resumable uploads and downloads, a native crypto extension, a new web UI, Windows IPC support, layers 231 to 233, and hundreds of fixes.

Also, MadelineProto just passed 1 million installs on Packagist. Thank you so much ❤️

Packagist statistics for danog/madelineproto: 1,020,797 installs

Calls, calls, calls

Everything runs in pure PHP, on any webhost. Calls use php-rtc, a pure PHP WebRTC stack (ICE, STUN, TURN, DTLS, SRTP, SCTP), and audio goes through a pure PHP OPUS encoder and AAC decoder: no FFI, no extensions, no shell commands, no ffmpeg.

<?php

if (!file_exists('madeline.php')) {
    copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';

use danog\MadelineProto\API;
use danog\MadelineProto\RemoteUrl;

$MadelineProto = new API('session.madeline');
$MadelineProto->start();

// Video call a user
$MadelineProto->requestCall('@username', video: true)
    ->play(new RemoteUrl('https://paste.daniil.it/oncall.webm'));

// Stream into the video chat of a group or the livestream of a channel
$MadelineProto->joinGroupCall('@mygroup')
    ->play(new RemoteUrl('https://paste.daniil.it/oncall.webm'));

See examples/bot.php for a full example, and the call documentation » for everything else.

  • Video calls: play WebM/MKV files with VP8, VP9, H.264, H.265 (or AV1, in one-to-one calls) video and OPUS audio into any call. Frames are demuxed in pure PHP and sent as they are, with no transcoding.
  • Screen sharing: play a video as a screen share next to the camera stream with MediaDestination::Presentation.
  • Group calls (video chats and livestreams): create them (scheduled and RTMP livestreams too), join them (as a channel or via an invite link too), stream audio and video, share the screen, record, and manage them: title, invites and invite links, muting, volume, raised hands, server-side recording, kicking participants, in-call messages and reactions.
  • Livestreams: record stream mode livestreams (RTMP ones included) with the new pure PHP MP4 demuxer, and publish to RTMP livestreams with play(): MP4 or Matroska files with H.264 video and AAC audio are published by MadelineProto itself, in pure PHP and without transcoding.
  • Stream to any Telegram livestream or user profile with the new startRtmpStream(), using the RTMP URL and key that the Telegram apps show when starting a stream “with another app”. No admin rights or joining needed, and the stream is resumed after restarts. Bots that accept URLs from users can restrict where streams connect with RtmpServers::Telegram or RtmpServers::Internet:
$stream = $MadelineProto->startRtmpStream('rtmps://dc4-1.rtmp.t.me/s/123456:AbCdEf', servers: RtmpServers::Telegram);
$stream->play(new RemoteUrl('https://example.com/video.mp4'));
  • Live stories: start one with startLive(), stream into it, comment, and handle Telegram Stars donations.
  • End-to-end encrypted conference calls: create them, join them via a link or an invitation, invite users, verify the key emojis, send end-to-end encrypted in-call messages and remove participants (rekeying the call), or upgrade a one-to-one call with migrateCallToConference().
  • Call recording: setOutput() records a participant’s microphone, camera and screen share into a Matroska (or OGG OPUS) file, and setOutputFolder() records every participant into a directory, starting a new file whenever their streams change. Recordings are written in pure PHP, without decoding anything.
  • AAC audio in calls, on webhosts too: the AAC audio of MP4 files is now played into one-to-one calls, video chats and conferences, thanks to a new pure PHP AAC decoder and OPUS encoder (ffmpeg and libopus are only used to speed it up when available, never required).
  • Any OGG OPUS file (mono or stereo, any frame size) can now be played as it is: no more pre-converting with @libtgvoip_bot or Ogg::convert.
  • One API for all calls: PrivateCall, GroupCall, LiveStory and ConferenceCall all implement the Call interface, with the same playlist, mute, screen sharing and recording controls.
  • Calls survive restarts: playlists (continuing the current file where it left off), hold files (which now loop) and recordings are saved in the session.
  • New updates: CallStreams, GroupCall, GroupCallParticipants, GroupCallMessage, GroupCallMessagesDeleted, LiveStory, LiveStoryMessage and ConferenceCallMessage. Message filters (commands, text, regexes, sender, incoming/outgoing, peer) work on in-call messages too.
  • Messages have new getCall(), canRequestCall(), requestCall() and getCallDenialReason() methods, so $message->requestCall()->join() works in every chat.

Want to try it out? Talk to magnaluna, our open-source pure PHP webradio: @magicalcrazypony. Call it, send it /call, send it the link of a group call or a conference call, or use /join in a group. It can play any YouTube video or livestream, without ffmpeg or yt-dlp. Its source code runs on any PHP webhost, so you can host your own!

magnaluna, the pure PHP webradio, playing in Telegram calls, video chats and livestreams

Much, much faster

  • MadelineCrypto, a new optional native extension contributed by xtrime, with further improvements by danog: about 250x faster file downloads and uploads, native per-packet crypto for calls (AES-GCM/CTR/CBC/IGE, HMAC, hashes), and 40x faster factorization of pq when creating auth keys. It’s preinstalled in the official Docker image, and you can install it anywhere with PIE, the successor of PECL (prebuilt binaries are available for Linux, macOS and Windows):

 

pie install danog/madelinecrypto
  • Webhosts got faster too: 10x faster file downloads thanks to a new pure PHP AES-IGE implementation (with one OpenSSL call per encryption, and no eval without OpenSSL), and up to 90% faster SHA-256 hashes (the fastest backend is picked for each input size).
  • Bulk downloads and uploads no longer time out: MadelineProto learns how many file requests each media DC accepts at once (like a TCP congestion window) and spreads them over several sockets, instead of piling them all on one.
  • Short download ranges (like a browser probing a video’s metadata) now fetch small parts instead of a whole megabyte.
  • Cryptography now uses OpenSSL and libsodium when available, with phpseclib only as the fallback.

Rich messages

Full support for rich messages and all message entities:

$message->replyRich("# Hello!\n\nThis is a **rich** message.", RichParseMode::MARKDOWN);
  • New sendRichMessage(), sendRichMessageDraft() (stream drafts while they are generated, perfect for AI bots) and sendRichMessageToAdmins() methods, and replyRich(), sendRich(), editRich() and replyOrEditRich() in the event handler.
  • Write them in Markdown, HTML, typed blocks (new Block\Paragraph(new Text\Bold('Hello'))), Bot API blocks or raw MTProto page blocks, and embed media from files, URLs, streams or file IDs.
  • Received rich messages are in Message::$richMessage, with the same API as messages ($message, $entities, getHTML(), $media) and typed $blocks. Filter them with FilterRichMessage.

Nothing gets lost

  • Resumable uploads: interrupted uploads of files, URLs, Telegram files and streams (encrypted ones too) resume after a restart, without uploading the parts already sent again.
  • Resumable method calls: interrupted method calls and send* calls uploading such files are resumed after a restart (disable it with the new resumeInterruptedCalls file setting).
  • Resumable download streams: downloadToReturnedStream() and Media::getStream() return a ResumableDownloadStream, which can be serialized and resumes from where it left off.
  • Network outages are survived: requests are queued and sent once the connection is back, with reconnections retried in the background (previously, a script whose network went down for a minute could die).
  • Dead connections are detected: connections that silently stop working (half-open TCP connections, dropped by a NAT for example) are replaced as soon as a state request goes unanswered.
  • Session files are synced to disk before replacing the old one: a crash or power loss could leave a session file full of zeroes.
  • Requests whose result can’t be deserialized now fail with an error, instead of being resent forever.
  • A new file reference database, driven by Telegram’s file reference map, refreshes expired file references automatically.

New in the event handler and API

  • Thumbnails are media: Media::$thumbs and Media::$videoThumbs hold Thumbnail and VideoThumbnail objects, which can be downloaded, streamed, linked with getDownloadLink() and reused as upload sources or as thumb:. Inline (stripped or cached) thumbnails are served from memory.
  • Locations: Message::$location holds StaticLocation, LiveLocation and Venue objects, with the new HasLocation, HasLiveLocation and HasVenue filters.
  • Cross-chat replies: $replyToChatId tells which chat a reply points to, getReply() fetches it there, and the reply*() methods take a $peer to reply to a message of another chat. getReply() also works when the replying message was deleted.
  • getUpdates() can be cancelled with a Cancellation, through IPC too.
  • Communities, ephemeral messages, wallets, bot widgets, audio file transcription and everything else from layers 231, 232 and 233.

Web UI and login

  • Web UI v3: a new login interface in the style of Telegram Web K, made of liquid glass.
  • With startAndLoopMulti(), the web login now lets you choose which session to log in.
  • The CLI login hides the bot token, API hash, 2FA password and login code as they’re typed, and so does the web login.
  • MadelineProto is now available in 21 languages: Spanish, Arabic, Turkish, Ukrainian, Indonesian, Hindi, Vietnamese, Japanese and Korean are new, and the German, Polish, French, Central Kurdish, Portuguese and Russian translations are complete. Translations now live in langs/ on GitHub.
The new web UI v3, ported from Telegram Web

Security

  • Files served to browsers are sandboxed: the download script (getDownloadLink()) and downloadToResponse() used the MIME type and the name chosen by whoever sent the file, so a link could serve HTML with scripts from your website. Every file is now served with Content-Security-Policy: sandbox, X-Content-Type-Options: nosniff and a normalized MIME type; only media and plain text are shown inline. Websites serving trusted files can turn this off with Files::setSandboxDownloads(false).
  • Secrets passed as parameters are marked #[\SensitiveParameter], so they don’t show up in stack traces.

Proxies, Windows, Docker and the phar

  • Fake TLS MTProxy secrets (ee) are now supported, implemented like TDLib, as are base64 secrets (URL-safe and dd-prefixed ones included). Failing proxies are no longer bypassed with direct connections.
  • The IPC server now starts automatically on Windows (Windows 10 1803+, with ext-sockets), like on the other platforms.
  • Docker image: based on Debian trixie, extensions installed with PIE, MadelineCrypto preinstalled, a non-root user, and PHP updated automatically (it already had the fixes for the latest PHP vulnerabilities). The latest tag now only moves on releases.
  • Phar: now named madeline.phar; phar updates work on php-fpm with opcache.validate_timestamps=0; startup no longer waits up to 18 seconds when the phar server can’t be reached. The latest phars are also on @madelineprotophar.

Notable fixes

  • Clicking the buttons of received keyboards works again, and Bot API keyboards are converted correctly.
  • The forum topic methods (createTopic(), editTopic(), openTopic(), closeTopic(), deleteTopic()) work again.
  • Sessions saved by older versions (before 8.4.7, or with phpseclib 3) load again, and Telegram Desktop sessions can be converted again.
  • Changing the database settings no longer loses data.
  • Fixed an endless loop that used all the memory when the event handler failed to start.
  • Fixed the update loop dying on RPC timeouts in getDifference/getChannelDifference.
  • Fixed a hang while starting the IPC worker on Windows, IPC request floods, and many more IPC issues.
  • Fixed the speed and time passed to upload and download progress callbacks, and downloadToBrowser() continuing after the browser closed the connection.
  • Fixed stale user statuses in getInfo(), and the replyToMsgId of sent messages.
  • Sending a message no longer fails with RANDOM_ID_DUPLICATE when it was resent while the server was still processing the first copy (the message was sent anyway).
  • Calls failing with server-side errors (RPC_CALL_FAIL, -503) are now retried with a growing delay, and fail with the server’s error instead of a timeout.
  • Round videos are video notes again, encrypted downloads starting from a non-zero offset work, and sending media with a TTL works.

See the full changelogs on GitHub for everything else.

Upgrade notes

  • Media::$thumb, $thumbWidth and $thumbHeight were replaced by the InlineThumbnail in Media::$thumbs.
  • Starting with layer 231, keyboard buttons carry their action in their type (the keyboardButtonUrl, keyboardButtonCallback… constructors were removed).
  • Files served by the download script are now sandboxed (see above).

Thanks

Thanks to everyone who contributed to these releases: @danog, @xtrime-ru, @xcgu, @bertmsk, @mtalaeii and @junwei-qu!

Get it

composer require danog/madelineproto:^8.20

Or just include madeline.php, which updates itself automatically.

Release announcements now go to @madelineprotophar, while @MadelineProto is kept for the big ones like this. Happy hacking!

#announcement #async #calls #madelineproto #performance #php #telegram