diff --git a/docs b/docs index 2ba734c6c..165aa82a2 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 2ba734c6c105ed5c830a97889b943452b18dc196 +Subproject commit 165aa82a200e8fdee2c23550178b003601d639a6 diff --git a/src/Loop/VoIP/DjLoop.php b/src/Loop/VoIP/DjLoop.php index 62936b7c6..1644913af 100644 --- a/src/Loop/VoIP/DjLoop.php +++ b/src/Loop/VoIP/DjLoop.php @@ -26,9 +26,11 @@ use Amp\Cancellation; use Amp\CancelledException; use Amp\DeferredCancellation; use Amp\DeferredFuture; +use AssertionError; use danog\Loop\Loop; use danog\MadelineProto\LocalFile; use danog\MadelineProto\Loop\VoIPLoop; +use danog\MadelineProto\Magic; use danog\MadelineProto\Ogg; use danog\MadelineProto\RemoteUrl; use danog\MadelineProto\VoIP; @@ -199,6 +201,9 @@ final class DjLoop extends VoIPLoop } } if (!$it) { + if (!Magic::canConvertOgg()) { + throw new AssertionError("The passed file was not generated by MadelineProto or @libtgvoipbot, please pre-convert it using @libtgvoip bot or install FFI and ffmpeg to perform realtime conversion!"); + } $this->instance->log("Starting conversion fiber..."); $pipe = new Pipe(4096); EventLoop::queue(function () use ($f, $pipe, $cancellation): void { diff --git a/src/Magic.php b/src/Magic.php index e07b60e8b..30c61c586 100644 --- a/src/Magic.php +++ b/src/Magic.php @@ -20,6 +20,8 @@ declare(strict_types=1); namespace danog\MadelineProto; +use Amp\ByteStream\ReadableBuffer; +use Amp\ByteStream\WritableBuffer; use Amp\DeferredFuture; use Amp\SignalException; use danog\MadelineProto\TL\Conversion\Extension; @@ -389,4 +391,18 @@ final class Magic self::$initedIpv6 = true; } } + + private static ?bool $canConvert = null; + public static function canConvertOgg(): bool { + if (self::$canConvert !== null) { + return self::$canConvert; + } + try { + Ogg::convert(new ReadableBuffer("\0"), new WritableBuffer); + self::$canConvert = true; + } catch (\Throwable) { + self::$canConvert = false; + } + return self::$canConvert; + } } diff --git a/src/Ogg.php b/src/Ogg.php index 82c523c5b..426302c3b 100644 --- a/src/Ogg.php +++ b/src/Ogg.php @@ -541,7 +541,13 @@ final class Ogg */ public static function validateOgg(LocalFile|RemoteUrl|ReadableStream $f): void { - foreach ((new self($f))->opusPackets as $p) { + $ok = false; + try { + $ogg = new self($f); + $ok = \in_array('MADELINE_ENCODER_V=1', $ogg->comments, true); + } catch (\Throwable) {} + if (!$ok) { + throw new AssertionError("The passed file was not generated by MadelineProto or @libtgvoipbot, please pre-convert it using @libtgvoip bot or install FFI and ffmpeg to perform realtime conversion!"); } } diff --git a/src/VoIP/AuthKeyHandler.php b/src/VoIP/AuthKeyHandler.php index a04fb68a0..5e32f9a07 100644 --- a/src/VoIP/AuthKeyHandler.php +++ b/src/VoIP/AuthKeyHandler.php @@ -26,6 +26,7 @@ use danog\MadelineProto\LocalFile; use danog\MadelineProto\Logger; use danog\MadelineProto\Magic; use danog\MadelineProto\MTProtoTools\Crypt; +use danog\MadelineProto\Ogg; use danog\MadelineProto\PeerNotInDbException; use danog\MadelineProto\RemoteUrl; use danog\MadelineProto\VoIP; @@ -161,6 +162,11 @@ trait AuthKeyHandler */ public function callPlay(int $id, LocalFile|RemoteUrl|ReadableStream $file): void { + if (!Magic::canConvertOgg()) { + if ($file instanceof LocalFile) { + Ogg::validateOgg($file); + } + } ($this->calls[$id] ?? null)?->play($file); } @@ -174,7 +180,7 @@ trait AuthKeyHandler if (!isset($this->calls[$id])) { return; } - $this->calls[$id]->play($file); + $this->callPlay($id, $file); if ($file instanceof ReadableStream) { $deferred = new DeferredFuture; $file->onClose($deferred->complete(...)); @@ -227,6 +233,13 @@ trait AuthKeyHandler */ public function callPlayOnHold(int $id, LocalFile|RemoteUrl|ReadableStream ...$files): void { + if (!Magic::canConvertOgg()) { + foreach ($files as $file) { + if ($file instanceof LocalFile) { + Ogg::validateOgg($file); + } + } + } ($this->calls[$id] ?? null)?->playOnHold(...$files); } @@ -240,7 +253,7 @@ trait AuthKeyHandler if (!isset($this->calls[$id])) { return; } - $this->calls[$id]->playOnHold(...$files); + $this->callPlayOnHold($id, ...$files); foreach ($files as $file) { if ($file instanceof ReadableStream) { $deferred = new DeferredFuture;