This commit is contained in:
Daniil Gentili 2020-10-27 20:53:13 +01:00
parent 806f50bc2d
commit 8164279427
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 112 additions and 66 deletions

View File

@ -187,6 +187,9 @@ class Ogg
for ($x = 0; $x < $count; $x++) { for ($x = 0; $x < $count; $x++) {
$sizes[]= $this->readLen($content, $offset); $sizes[]= $this->readLen($content, $offset);
} }
if (!$selfDelimited) {
$sizes []= ($len - ($offset + $padding));
}
} else { // CBR } else { // CBR
$size = $selfDelimited $size = $selfDelimited
? $this->readLen($content, $offset) ? $this->readLen($content, $offset)
@ -241,6 +244,7 @@ class Ogg
while (true) { while (true) {
$init = yield $this->stream->bufferRead(4+23); $init = yield $this->stream->bufferRead(4+23);
if (empty($init)) { if (empty($init)) {
$this->emitter->complete();
return false; // EOF return false; // EOF
} }
if (\substr($init, 0, 4) !== self::CAPTURE_PATTERN) { if (\substr($init, 0, 4) !== self::CAPTURE_PATTERN) {

View File

@ -19,6 +19,7 @@ use danog\MadelineProto\Stream\ConnectionContext;
use danog\MadelineProto\Stream\Ogg\Ogg; use danog\MadelineProto\Stream\Ogg\Ogg;
use danog\MadelineProto\VoIP\Endpoint; use danog\MadelineProto\VoIP\Endpoint;
use function Amp\delay;
use function Amp\File\open; use function Amp\File\open;
if (\extension_loaded('php-libtgvoip')) { if (\extension_loaded('php-libtgvoip')) {
@ -30,7 +31,7 @@ class VoIP
use \danog\MadelineProto\VoIP\MessageHandler; use \danog\MadelineProto\VoIP\MessageHandler;
use \danog\MadelineProto\VoIP\AckHandler; use \danog\MadelineProto\VoIP\AckHandler;
const PHP_LIBTGVOIP_VERSION = '1.1.2'; const PHP_LIBTGVOIP_VERSION = '1.5.0';
const STATE_CREATED = 0; const STATE_CREATED = 0;
const STATE_WAIT_INIT = 1; const STATE_WAIT_INIT = 1;
const STATE_WAIT_INIT_ACK = 2; const STATE_WAIT_INIT_ACK = 2;
@ -99,13 +100,13 @@ class VoIP
const PROTO_ID = 'GrVP'; const PROTO_ID = 'GrVP';
const PROTOCOL_VERSION = 3; const PROTOCOL_VERSION = 9;
const MIN_PROTOCOL_VERSION = 3; const MIN_PROTOCOL_VERSION = 9;
const STREAM_TYPE_AUDIO = 1; const STREAM_TYPE_AUDIO = 1;
const STREAM_TYPE_VIDEO = 2; const STREAM_TYPE_VIDEO = 2;
const CODEC_OPUS = 1; const CODEC_OPUS = 'SUPO';
private $TLID_DECRYPTED_AUDIO_BLOCK; private $TLID_DECRYPTED_AUDIO_BLOCK;
@ -137,7 +138,7 @@ class VoIP
private bool $creator; private bool $creator;
private PermAuthKey $authKey; private PermAuthKey $authKey;
private int $peerVersion; private int $peerVersion = 0;
/** /**
* @var Endpoint[] * @var Endpoint[]
@ -149,24 +150,39 @@ class VoIP
private $datacenter; private $datacenter;
public function __construct(bool $creator, int $otherID, $callID, MTProto $MadelineProto, $callState, $protocol) public function __construct(bool $creator, int $otherID, MTProto $MadelineProto, $callState)
{ {
$this->creator = $creator; $this->creator = $creator;
$this->otherID = $otherID; $this->otherID = $otherID;
$this->callID = $callID; //$this->callID = $callID;
$this->MadelineProto = $MadelineProto; $this->madeline = $this->MadelineProto = $MadelineProto;
$this->callState = $callState; $this->callState = $callState;
$this->protocol = $protocol; //$this->protocol = $protocol;
$this->TLID_REFLECTOR_SELF_INFO = \strrev(\hex2bin(self::TLID_REFLECTOR_SELF_INFO_HEX)); $this->TLID_REFLECTOR_SELF_INFO = \strrev(\hex2bin(self::TLID_REFLECTOR_SELF_INFO_HEX));
$this->TLID_REFLECTOR_PEER_INFO = \strrev(\hex2bin(self::TLID_REFLECTOR_PEER_INFO_HEX)); $this->TLID_REFLECTOR_PEER_INFO = \strrev(\hex2bin(self::TLID_REFLECTOR_PEER_INFO_HEX));
$this->TLID_DECRYPTED_AUDIO_BLOCK = \strrev(\hex2bin(self::TLID_DECRYPTED_AUDIO_BLOCK_HEX)); $this->TLID_DECRYPTED_AUDIO_BLOCK = \strrev(\hex2bin(self::TLID_DECRYPTED_AUDIO_BLOCK_HEX));
$this->TLID_SIMPLE_AUDIO_BLOCK = \strrev(\hex2bin(self::TLID_SIMPLE_AUDIO_BLOCK_HEX)); $this->TLID_SIMPLE_AUDIO_BLOCK = \strrev(\hex2bin(self::TLID_SIMPLE_AUDIO_BLOCK_HEX));
} }
public static function getConnectionMaxLayer(): int
{
return 92;
}
public function deInitVoIPController() public function deInitVoIPController()
{ {
} }
public function getDebugString(): string
{
return '';
}
public function setCall($callID)
{
$this->callID = $callID;
}
public function setVisualization($visualization) public function setVisualization($visualization)
{ {
$this->visualization = $visualization; $this->visualization = $visualization;
@ -210,24 +226,34 @@ class VoIP
public function startTheMagic() public function startTheMagic()
{ {
foreach ($this->sockets as $socket) { Tools::callFork((function () {
Tools::callFork(function () use ($socket) { $this->authKey = new PermAuthKey();
while ($payload = $this->recv_message($socket)) { $this->authKey->setAuthKey($this->configuration['auth_key']);
foreach ($this->configuration['endpoints'] as $endpoint) {
$this->sockets['v6 '.$endpoint['id']] = new Endpoint('['.$endpoint['ipv6'].']', $endpoint['port'], $endpoint['peer_tag'], true, $this);
$this->sockets['v4 '.$endpoint['id']] = new Endpoint($endpoint['ip'], $endpoint['port'], $endpoint['peer_tag'], true, $this);
}
foreach ($this->sockets as $socket) {
yield from $socket->connect();
}
$this->init_all();
Tools::callFork((function () use ($socket) {
while ($payload = yield from $this->recv_message($socket)) {
Tools::callFork($this->handlePacket($socket, $payload)); Tools::callFork($this->handlePacket($socket, $payload));
} }
}); })());
} })());
return $this; return $this;
} }
public function handlePacket($datacenter, $packet) public function handlePacket($datacenter, $packet)
{ {
\var_dump($packet); //\var_dump($packet);
switch ($packet['_']) { switch ($packet['_']) {
case self::PKT_INIT: case self::PKT_INIT:
$this->voip_state = self::STATE_WAIT_INIT_ACK; //$this->voip_state = self::STATE_WAIT_INIT_ACK;
$this->send_message(['_' => self::PKT_INIT_ACK, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'all_streams' => [['id' => 0, 'type' => self::STREAM_TYPE_AUDIO, 'codec' => self::CODEC_OPUS, 'frame_duration' => 60, 'enabled' => 1]]], $datacenter); $this->send_message(['_' => self::PKT_INIT_ACK, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'all_streams' => [['id' => 0, 'type' => self::STREAM_TYPE_AUDIO, 'codec' => self::CODEC_OPUS, 'frame_duration' => 60, 'enabled' => 1]]], $datacenter);
break;
case self::PKT_INIT_ACK:
if ($this->voip_state !== self::STATE_ESTABLISHED) { if ($this->voip_state !== self::STATE_ESTABLISHED) {
$this->voip_state = self::STATE_ESTABLISHED; $this->voip_state = self::STATE_ESTABLISHED;
@ -237,21 +263,25 @@ class VoIP
$ogg = yield from Ogg::init($stream, 60000); $ogg = yield from Ogg::init($stream, 60000);
$it = $ogg->getEmitter()->iterate(); $it = $ogg->getEmitter()->iterate();
Tools::callFork($ogg->read()); Tools::callFork($ogg->read());
Tools::callFork(function () use ($it) { Tools::callFork((function () use ($it, $datacenter) {
$timestamp = 0; $timestamp = 0;
$t = microtime(true); $frames = [];
while (yield $it->advance()) { while (yield $it->advance()) {
$elapsed = microtime(true) - $t; $frames []= $it->getCurrent();
$t = microtime(true); }
foreach ($frames as $frame) {
$t = (microtime(true) / 1000) + 60;
yield $this->send_message(['_' => self::PKT_STREAM_DATA, 'stream_id' => 0, 'data' => $frame, 'timestamp' => $timestamp], $datacenter);
yield new Delayed((int) ($t - (microtime(true) / 1000)));
yield new Delayed((int) (60000 - $elapsed / 1000));
yield $this->send_message(['_' => self::PKT_STREAM_DATA, 'stream_id' => 0, 'data' => $it->getCurrent(), 'timestamp' => $this->timestamp], $datacenter);
$timestamp += 60; $timestamp += 60;
} }
}); })());
} }
break; break;
case self::PKT_INIT_ACK:
break;
} }
} }
public $timestamp = 0; public $timestamp = 0;
@ -321,23 +351,11 @@ class VoIP
public function parseConfig() public function parseConfig()
{ {
$this->authKey = new PermAuthKey();
$this->authKey->setAuthKey($this->configuration['auth_key']);
if (\count($this->configuration['endpoints'])) {
foreach ($this->configuration['endpoints'] as $endpoint) {
$this->sockets['v6 '.$endpoint['id']] = new Endpoint($endpoint['ipv6'], $endpoint['port'], $endpoint['peer_tag'], true, $this);
$this->sockets['v4 '.$endpoint['id']] = new Endpoint($endpoint['ip'], $endpoint['port'], $endpoint['peer_tag'], true, $this);
}
foreach ($this->sockets as $socket) {
yield from $socket->connect();
}
}
} }
private function init_all() private function init_all()
{ {
$test = $this->connection_settings['all']['test_mode'] ? 'test' : 'main'; foreach ($this->sockets as $socket) {
foreach ($this->datacenter->sockets as $dc_id => $socket) {
$this->send_message(['_' => self::PKT_INIT, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'audio_streams' => [self::CODEC_OPUS], 'video_streams' => []], $socket); $this->send_message(['_' => self::PKT_INIT, 'protocol' => self::PROTOCOL_VERSION, 'min_protocol' => self::MIN_PROTOCOL_VERSION, 'audio_streams' => [self::CODEC_OPUS], 'video_streams' => []], $socket);
$this->voip_state = self::STATE_WAIT_INIT; $this->voip_state = self::STATE_WAIT_INIT;
} }

View File

@ -137,7 +137,7 @@ trait AuthKeyHandler
$g_b = $dh_config['g']->powMod($b, $dh_config['p']); $g_b = $dh_config['g']->powMod($b, $dh_config['p']);
Crypt::checkG($g_b, $dh_config['p']); Crypt::checkG($g_b, $dh_config['p']);
try { try {
$res = yield from $this->methodCallAsyncRead('phone.acceptCall', ['peer' => $call, 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]]); $res = yield from $this->methodCallAsyncRead('phone.acceptCall', ['peer' => ['id' => $call['id'], 'access_hash' => $call['access_hash'], '_' => 'inputPhoneCall'], 'g_b' => $g_b->toBytes(), 'protocol' => ['_' => 'phoneCallProtocol', 'udp_reflector' => true, 'udp_p2p' => true, 'min_layer' => 65, 'max_layer' => \danog\MadelineProto\VoIP::getConnectionMaxLayer()]]);
} catch (\danog\MadelineProto\RPCErrorException $e) { } catch (\danog\MadelineProto\RPCErrorException $e) {
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') { if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id'])); $this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['call_already_accepted'], $call['id']));
@ -322,6 +322,7 @@ trait AuthKeyHandler
{ {
\array_walk($this->calls, function ($controller, $id) { \array_walk($this->calls, function ($controller, $id) {
if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) { if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
$this->logger("Discarding ended call...");
$controller->discard(); $controller->discard();
} }
}); });

View File

@ -28,12 +28,12 @@ trait MessageHandler
if ($l <= 253) { if ($l <= 253) {
$concat .= \chr($l); $concat .= \chr($l);
$concat .= $object; $concat .= $object;
$concat .= \pack('@'.$this->posmod(-$l - 1, 4)); $concat .= \pack('@'.Tools::posmod(-$l - 1, 4));
} else { } else {
$concat .= \chr(254); $concat .= \chr(254);
$concat .= \substr(Tools::packSignedInt($l), 0, 3); $concat .= \substr(Tools::packSignedInt($l), 0, 3);
$concat .= $object; $concat .= $object;
$concat .= \pack('@'.$this->posmod(-$l, 4)); $concat .= \pack('@'.Tools::posmod(-$l, 4));
} }
return $concat; return $concat;
@ -47,13 +47,13 @@ trait MessageHandler
if ($l === 254) { if ($l === 254) {
$long_len = \unpack('V', \stream_get_contents($stream, 3).\chr(0))[1]; $long_len = \unpack('V', \stream_get_contents($stream, 3).\chr(0))[1];
$x = \stream_get_contents($stream, $long_len); $x = \stream_get_contents($stream, $long_len);
$resto = $this->posmod(-$long_len, 4); $resto = Tools::posmod(-$long_len, 4);
if ($resto > 0) { if ($resto > 0) {
\stream_get_contents($stream, $resto); \stream_get_contents($stream, $resto);
} }
} else { } else {
$x = \stream_get_contents($stream, $l); $x = \stream_get_contents($stream, $l);
$resto = $this->posmod(-($l + 1), 4); $resto = Tools::posmod(-($l + 1), 4);
if ($resto > 0) { if ($resto > 0) {
\stream_get_contents($stream, $resto); \stream_get_contents($stream, $resto);
} }
@ -78,8 +78,9 @@ trait MessageHandler
$message .= Tools::packUnsignedInt($flags); $message .= Tools::packUnsignedInt($flags);
$message .= \chr(\count($args['audio_streams'])); $message .= \chr(\count($args['audio_streams']));
foreach ($args['audio_streams'] as $codec) { foreach ($args['audio_streams'] as $codec) {
$message .= \chr($codec); $message .= $codec;
} }
$message .= chr(0);
$message .= \chr(\count($args['video_streams'])); $message .= \chr(\count($args['video_streams']));
foreach ($args['video_streams'] as $codec) { foreach ($args['video_streams'] as $codec) {
$message .= \chr($codec); $message .= \chr($codec);
@ -95,7 +96,7 @@ trait MessageHandler
foreach ($args['all_streams'] as $stream) { foreach ($args['all_streams'] as $stream) {
$message .= \chr($stream['id']); $message .= \chr($stream['id']);
$message .= \chr($stream['type']); $message .= \chr($stream['type']);
$message .= \chr($stream['codec']); $message .= $stream['codec'];
$message .= \pack('v', $stream['frame_duration']); $message .= \pack('v', $stream['frame_duration']);
$message .= \chr($stream['enabled']); $message .= \chr($stream['enabled']);
} }
@ -184,11 +185,18 @@ trait MessageHandler
} }
} }
if (\in_array($this->voip_state, [\danog\MadelineProto\VoIP::STATE_WAIT_INIT, \danog\MadelineProto\VoIP::STATE_WAIT_INIT_ACK])) { if ($this->peerVersion >= 8 || (!$this->peerVersion && true)) {
$payload = \chr($args['_']);
$payload .= Tools::packUnsignedInt($this->session_in_seq_no);
$payload .= Tools::packUnsignedInt($this->session_out_seq_no);
$payload .= Tools::packUnsignedInt($ack_mask);
$payload .= \chr(0);
$payload .= $message;
} elseif (\in_array($this->voip_state, [\danog\MadelineProto\VoIP::STATE_WAIT_INIT, \danog\MadelineProto\VoIP::STATE_WAIT_INIT_ACK])) {
$payload = $this->TLID_DECRYPTED_AUDIO_BLOCK; $payload = $this->TLID_DECRYPTED_AUDIO_BLOCK;
$payload .= $this->random(8); $payload .= Tools::random(8);
$payload .= \chr(7); $payload .= \chr(7);
$payload .= $this->random(7); $payload .= Tools::random(7);
$flags = 0; $flags = 0;
$flags = $flags | 4; // call_id $flags = $flags | 4; // call_id
$flags = $flags | 16; // seqno $flags = $flags | 16; // seqno
@ -211,9 +219,9 @@ trait MessageHandler
} }
} else { } else {
$payload = $this->TLID_SIMPLE_AUDIO_BLOCK; $payload = $this->TLID_SIMPLE_AUDIO_BLOCK;
$payload .= $this->random(8); $payload .= Tools::random(8);
$payload .= \chr(7); $payload .= \chr(7);
$payload .= $this->random(7); $payload .= Tools::random(7);
$message = \chr($args['_']).Tools::packUnsignedInt($this->session_in_seq_no).Tools::packUnsignedInt($this->session_out_seq_no).Tools::packUnsignedInt($ack_mask).$message; $message = \chr($args['_']).Tools::packUnsignedInt($this->session_in_seq_no).Tools::packUnsignedInt($this->session_out_seq_no).Tools::packUnsignedInt($ack_mask).$message;
$payload .= $this->pack_string($message); $payload .= $this->pack_string($message);
@ -295,8 +303,29 @@ trait MessageHandler
$result['peer_port'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4)); $result['peer_port'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
return $result; return $result;
default: default:
\danog\MadelineProto\Logger::log('Unknown packet received: '.\bin2hex($crc), \danog\MadelineProto\Logger::ERROR); if ($this->peerVersion >= 8 || (!$this->peerVersion && true)) {
return false; \fseek($payload, 0);
$result['_'] = \ord(\stream_get_contents($payload, 1));
$in_seq_no = \unpack('V', \stream_get_contents($payload, 4))[1];
$out_seq_no = \unpack('V', \stream_get_contents($payload, 4))[1];
$ack_mask = \unpack('V', \stream_get_contents($payload, 4))[1];
$flags = \ord(\stream_get_contents($payload, 1));
if ($flags & 1) {
$result['extra'] = [];
$count = \ord(\stream_get_contents($payload, 1));
for ($x = 0; $x < $count; $x++) {
$len = \ord(\stream_get_contents($payload, 1));
$result['extra'][]= \stream_get_contents($payload, $len);
}
}
$message = \fopen('php://memory', 'rw+b');
\fwrite($message, \stream_get_contents($payload));
\fseek($message, 0);
} else {
\danog\MadelineProto\Logger::log('Unknown packet received: '.\bin2hex($crc), \danog\MadelineProto\Logger::ERROR);
return false;
}
} }
if (!$this->received_packet($in_seq_no, $out_seq_no, $ack_mask)) { if (!$this->received_packet($in_seq_no, $out_seq_no, $ack_mask)) {
return false; return false;
@ -306,19 +335,14 @@ trait MessageHandler
// //
// packetInit#1 protocol:int min_protocol:int flags:# data_saving_enabled:flags.0?true audio_streams:byteVector<streamTypeSimple> video_streams:byteVector<streamTypeSimple> = Packet; // packetInit#1 protocol:int min_protocol:int flags:# data_saving_enabled:flags.0?true audio_streams:byteVector<streamTypeSimple> video_streams:byteVector<streamTypeSimple> = Packet;
case \danog\MadelineProto\VoIP::PKT_INIT: case \danog\MadelineProto\VoIP::PKT_INIT:
$result['protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4)); $result['protocol'] = $this->peerVersion = Tools::unpackSignedInt(\stream_get_contents($message, 4));
$result['min_protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4)); $result['min_protocol'] = Tools::unpackSignedInt(\stream_get_contents($message, 4));
$flags = \unpack('V', \stream_get_contents($message, 4))[1]; $flags = \unpack('V', \stream_get_contents($message, 4))[1];
$result['data_saving_enabled'] = (bool) ($flags & 1); $result['data_saving_enabled'] = (bool) ($flags & 1);
$result['audio_streams'] = []; $result['audio_streams'] = [];
$length = \ord(\stream_get_contents($message, 1)); $length = \ord(\stream_get_contents($message, 1));
for ($x = 0; $x < $length; $x++) { for ($x = 0; $x < $length; $x++) {
$result['audio_streams'][$x] = \ord(\stream_get_contents($message, 1)); $result['audio_streams'][$x] = \stream_get_contents($message, 4);
}
$result['video_streams'] = [];
$length = \ord(\stream_get_contents($message, 1));
for ($x = 0; $x < $length; $x++) {
$result['video_streams'][$x] = \ord(\stream_get_contents($message, 1));
} }
break; break;
// streamType id:int8 type:int8 codec:int8 frame_duration:int16 enabled:int8 = StreamType; // streamType id:int8 type:int8 codec:int8 frame_duration:int16 enabled:int8 = StreamType;
@ -331,7 +355,7 @@ trait MessageHandler
$length = \ord(\stream_get_contents($message, 1)); $length = \ord(\stream_get_contents($message, 1));
for ($x = 0; $x < $length; $x++) { for ($x = 0; $x < $length; $x++) {
$result['all_streams'][$x]['id'] = \ord(\stream_get_contents($message, 1)); $result['all_streams'][$x]['id'] = \ord(\stream_get_contents($message, 1));
$result['all_streams'][$x]['type'] = \ord(\stream_get_contents($message, 1)); $result['all_streams'][$x]['type'] = \stream_get_contents($message, 4);
$result['all_streams'][$x]['codec'] = \ord(\stream_get_contents($message, 1)); $result['all_streams'][$x]['codec'] = \ord(\stream_get_contents($message, 1));
$result['all_streams'][$x]['frame_duration'] = \unpack('v', \stream_get_contents($message, 2))[1]; $result['all_streams'][$x]['frame_duration'] = \unpack('v', \stream_get_contents($message, 2))[1];
$result['all_streams'][$x]['enabled'] = \ord(\stream_get_contents($message, 1)); $result['all_streams'][$x]['enabled'] = \ord(\stream_get_contents($message, 1));

View File

@ -19,11 +19,13 @@
namespace danog\MadelineProto; namespace danog\MadelineProto;
if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) { if (\class_exists(VoIPServerConfig::class)) {
return;
}
/** /**
* Manages storage of VoIP server config. * Manages storage of VoIP server config.
*/ */
class VoIPServerConfig extends VoIPServerConfigInternal class VoIPServerConfig
{ {
/** /**
* The configuration. * The configuration.
@ -47,7 +49,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
public static function update(array $config) public static function update(array $config)
{ {
self::$_config = $config; self::$_config = $config;
self::updateInternal(self::getFinal());
} }
/** /**
* Get shared call settings. * Get shared call settings.
@ -68,7 +69,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
public static function updateDefault(array $configDefault) public static function updateDefault(array $configDefault)
{ {
self::$_configDefault = $configDefault; self::$_configDefault = $configDefault;
self::updateInternal(self::getFinal());
} }
/** /**
* Get default shared call settings. * Get default shared call settings.
@ -89,4 +89,3 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
return \array_merge(self::$_configDefault, self::$_config); return \array_merge(self::$_configDefault, self::$_config);
} }
} }
}