Update
This commit is contained in:
parent
806f50bc2d
commit
8164279427
@ -187,6 +187,9 @@ class Ogg
|
||||
for ($x = 0; $x < $count; $x++) {
|
||||
$sizes[]= $this->readLen($content, $offset);
|
||||
}
|
||||
if (!$selfDelimited) {
|
||||
$sizes []= ($len - ($offset + $padding));
|
||||
}
|
||||
} else { // CBR
|
||||
$size = $selfDelimited
|
||||
? $this->readLen($content, $offset)
|
||||
@ -241,6 +244,7 @@ class Ogg
|
||||
while (true) {
|
||||
$init = yield $this->stream->bufferRead(4+23);
|
||||
if (empty($init)) {
|
||||
$this->emitter->complete();
|
||||
return false; // EOF
|
||||
}
|
||||
if (\substr($init, 0, 4) !== self::CAPTURE_PATTERN) {
|
||||
|
@ -19,6 +19,7 @@ use danog\MadelineProto\Stream\ConnectionContext;
|
||||
use danog\MadelineProto\Stream\Ogg\Ogg;
|
||||
use danog\MadelineProto\VoIP\Endpoint;
|
||||
|
||||
use function Amp\delay;
|
||||
use function Amp\File\open;
|
||||
|
||||
if (\extension_loaded('php-libtgvoip')) {
|
||||
@ -30,7 +31,7 @@ class VoIP
|
||||
use \danog\MadelineProto\VoIP\MessageHandler;
|
||||
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_WAIT_INIT = 1;
|
||||
const STATE_WAIT_INIT_ACK = 2;
|
||||
@ -99,13 +100,13 @@ class VoIP
|
||||
|
||||
const PROTO_ID = 'GrVP';
|
||||
|
||||
const PROTOCOL_VERSION = 3;
|
||||
const MIN_PROTOCOL_VERSION = 3;
|
||||
const PROTOCOL_VERSION = 9;
|
||||
const MIN_PROTOCOL_VERSION = 9;
|
||||
|
||||
const STREAM_TYPE_AUDIO = 1;
|
||||
const STREAM_TYPE_VIDEO = 2;
|
||||
|
||||
const CODEC_OPUS = 1;
|
||||
const CODEC_OPUS = 'SUPO';
|
||||
|
||||
|
||||
private $TLID_DECRYPTED_AUDIO_BLOCK;
|
||||
@ -137,7 +138,7 @@ class VoIP
|
||||
private bool $creator;
|
||||
|
||||
private PermAuthKey $authKey;
|
||||
private int $peerVersion;
|
||||
private int $peerVersion = 0;
|
||||
|
||||
/**
|
||||
* @var Endpoint[]
|
||||
@ -149,24 +150,39 @@ class VoIP
|
||||
|
||||
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->otherID = $otherID;
|
||||
$this->callID = $callID;
|
||||
$this->MadelineProto = $MadelineProto;
|
||||
//$this->callID = $callID;
|
||||
$this->madeline = $this->MadelineProto = $MadelineProto;
|
||||
$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_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_SIMPLE_AUDIO_BLOCK = \strrev(\hex2bin(self::TLID_SIMPLE_AUDIO_BLOCK_HEX));
|
||||
}
|
||||
|
||||
public static function getConnectionMaxLayer(): int
|
||||
{
|
||||
return 92;
|
||||
}
|
||||
|
||||
public function deInitVoIPController()
|
||||
{
|
||||
}
|
||||
|
||||
public function getDebugString(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function setCall($callID)
|
||||
{
|
||||
$this->callID = $callID;
|
||||
}
|
||||
|
||||
public function setVisualization($visualization)
|
||||
{
|
||||
$this->visualization = $visualization;
|
||||
@ -210,24 +226,34 @@ class VoIP
|
||||
|
||||
public function startTheMagic()
|
||||
{
|
||||
foreach ($this->sockets as $socket) {
|
||||
Tools::callFork(function () use ($socket) {
|
||||
while ($payload = $this->recv_message($socket)) {
|
||||
Tools::callFork((function () {
|
||||
$this->authKey = new PermAuthKey();
|
||||
$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));
|
||||
}
|
||||
});
|
||||
}
|
||||
})());
|
||||
})());
|
||||
return $this;
|
||||
}
|
||||
public function handlePacket($datacenter, $packet)
|
||||
{
|
||||
\var_dump($packet);
|
||||
//\var_dump($packet);
|
||||
switch ($packet['_']) {
|
||||
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);
|
||||
break;
|
||||
case self::PKT_INIT_ACK:
|
||||
|
||||
if ($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);
|
||||
$it = $ogg->getEmitter()->iterate();
|
||||
Tools::callFork($ogg->read());
|
||||
Tools::callFork(function () use ($it) {
|
||||
Tools::callFork((function () use ($it, $datacenter) {
|
||||
$timestamp = 0;
|
||||
$t = microtime(true);
|
||||
$frames = [];
|
||||
while (yield $it->advance()) {
|
||||
$elapsed = microtime(true) - $t;
|
||||
$t = microtime(true);
|
||||
$frames []= $it->getCurrent();
|
||||
}
|
||||
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;
|
||||
}
|
||||
});
|
||||
})());
|
||||
}
|
||||
break;
|
||||
case self::PKT_INIT_ACK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
public $timestamp = 0;
|
||||
@ -321,23 +351,11 @@ class VoIP
|
||||
|
||||
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()
|
||||
{
|
||||
$test = $this->connection_settings['all']['test_mode'] ? 'test' : 'main';
|
||||
foreach ($this->datacenter->sockets as $dc_id => $socket) {
|
||||
foreach ($this->sockets as $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;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ trait AuthKeyHandler
|
||||
$g_b = $dh_config['g']->powMod($b, $dh_config['p']);
|
||||
Crypt::checkG($g_b, $dh_config['p']);
|
||||
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) {
|
||||
if ($e->rpc === 'CALL_ALREADY_ACCEPTED') {
|
||||
$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) {
|
||||
if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
|
||||
$this->logger("Discarding ended call...");
|
||||
$controller->discard();
|
||||
}
|
||||
});
|
||||
|
@ -28,12 +28,12 @@ trait MessageHandler
|
||||
if ($l <= 253) {
|
||||
$concat .= \chr($l);
|
||||
$concat .= $object;
|
||||
$concat .= \pack('@'.$this->posmod(-$l - 1, 4));
|
||||
$concat .= \pack('@'.Tools::posmod(-$l - 1, 4));
|
||||
} else {
|
||||
$concat .= \chr(254);
|
||||
$concat .= \substr(Tools::packSignedInt($l), 0, 3);
|
||||
$concat .= $object;
|
||||
$concat .= \pack('@'.$this->posmod(-$l, 4));
|
||||
$concat .= \pack('@'.Tools::posmod(-$l, 4));
|
||||
}
|
||||
|
||||
return $concat;
|
||||
@ -47,13 +47,13 @@ trait MessageHandler
|
||||
if ($l === 254) {
|
||||
$long_len = \unpack('V', \stream_get_contents($stream, 3).\chr(0))[1];
|
||||
$x = \stream_get_contents($stream, $long_len);
|
||||
$resto = $this->posmod(-$long_len, 4);
|
||||
$resto = Tools::posmod(-$long_len, 4);
|
||||
if ($resto > 0) {
|
||||
\stream_get_contents($stream, $resto);
|
||||
}
|
||||
} else {
|
||||
$x = \stream_get_contents($stream, $l);
|
||||
$resto = $this->posmod(-($l + 1), 4);
|
||||
$resto = Tools::posmod(-($l + 1), 4);
|
||||
if ($resto > 0) {
|
||||
\stream_get_contents($stream, $resto);
|
||||
}
|
||||
@ -78,8 +78,9 @@ trait MessageHandler
|
||||
$message .= Tools::packUnsignedInt($flags);
|
||||
$message .= \chr(\count($args['audio_streams']));
|
||||
foreach ($args['audio_streams'] as $codec) {
|
||||
$message .= \chr($codec);
|
||||
$message .= $codec;
|
||||
}
|
||||
$message .= chr(0);
|
||||
$message .= \chr(\count($args['video_streams']));
|
||||
foreach ($args['video_streams'] as $codec) {
|
||||
$message .= \chr($codec);
|
||||
@ -95,7 +96,7 @@ trait MessageHandler
|
||||
foreach ($args['all_streams'] as $stream) {
|
||||
$message .= \chr($stream['id']);
|
||||
$message .= \chr($stream['type']);
|
||||
$message .= \chr($stream['codec']);
|
||||
$message .= $stream['codec'];
|
||||
$message .= \pack('v', $stream['frame_duration']);
|
||||
$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->random(8);
|
||||
$payload .= Tools::random(8);
|
||||
$payload .= \chr(7);
|
||||
$payload .= $this->random(7);
|
||||
$payload .= Tools::random(7);
|
||||
$flags = 0;
|
||||
$flags = $flags | 4; // call_id
|
||||
$flags = $flags | 16; // seqno
|
||||
@ -211,9 +219,9 @@ trait MessageHandler
|
||||
}
|
||||
} else {
|
||||
$payload = $this->TLID_SIMPLE_AUDIO_BLOCK;
|
||||
$payload .= $this->random(8);
|
||||
$payload .= Tools::random(8);
|
||||
$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;
|
||||
|
||||
$payload .= $this->pack_string($message);
|
||||
@ -295,8 +303,29 @@ trait MessageHandler
|
||||
$result['peer_port'] = Tools::unpackSignedInt(\stream_get_contents($payload, 4));
|
||||
return $result;
|
||||
default:
|
||||
\danog\MadelineProto\Logger::log('Unknown packet received: '.\bin2hex($crc), \danog\MadelineProto\Logger::ERROR);
|
||||
return false;
|
||||
if ($this->peerVersion >= 8 || (!$this->peerVersion && true)) {
|
||||
\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)) {
|
||||
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;
|
||||
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));
|
||||
$flags = \unpack('V', \stream_get_contents($message, 4))[1];
|
||||
$result['data_saving_enabled'] = (bool) ($flags & 1);
|
||||
$result['audio_streams'] = [];
|
||||
$length = \ord(\stream_get_contents($message, 1));
|
||||
for ($x = 0; $x < $length; $x++) {
|
||||
$result['audio_streams'][$x] = \ord(\stream_get_contents($message, 1));
|
||||
}
|
||||
$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));
|
||||
$result['audio_streams'][$x] = \stream_get_contents($message, 4);
|
||||
}
|
||||
break;
|
||||
// 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));
|
||||
for ($x = 0; $x < $length; $x++) {
|
||||
$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]['frame_duration'] = \unpack('v', \stream_get_contents($message, 2))[1];
|
||||
$result['all_streams'][$x]['enabled'] = \ord(\stream_get_contents($message, 1));
|
||||
|
@ -19,11 +19,13 @@
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
||||
if (\class_exists(VoIPServerConfig::class)) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Manages storage of VoIP server config.
|
||||
*/
|
||||
class VoIPServerConfig extends VoIPServerConfigInternal
|
||||
class VoIPServerConfig
|
||||
{
|
||||
/**
|
||||
* The configuration.
|
||||
@ -47,7 +49,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
||||
public static function update(array $config)
|
||||
{
|
||||
self::$_config = $config;
|
||||
self::updateInternal(self::getFinal());
|
||||
}
|
||||
/**
|
||||
* Get shared call settings.
|
||||
@ -68,7 +69,6 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
||||
public static function updateDefault(array $configDefault)
|
||||
{
|
||||
self::$_configDefault = $configDefault;
|
||||
self::updateInternal(self::getFinal());
|
||||
}
|
||||
/**
|
||||
* Get default shared call settings.
|
||||
@ -89,4 +89,3 @@ if (\class_exists('\\danog\\MadelineProto\\VoIPServerConfigInternal')) {
|
||||
return \array_merge(self::$_configDefault, self::$_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user