diff --git a/.gitignore b/.gitignore index 9e82d75..14a9856 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -composer.lock vendor /tests/nodeserver/node_modules/websocket/build/Release/.deps/ /tests/nodeserver/node_modules diff --git a/README.mdown b/README.md similarity index 100% rename from README.mdown rename to README.md diff --git a/composer.json b/composer.json index b614831..f103153 100644 --- a/composer.json +++ b/composer.json @@ -1,28 +1,29 @@ { - "name": "rukavinamilan/kurento-client-php", + "name": "glavweb/kurento-client-php", "type": "library", + "version": "0.1.0", "description": "A PHP Kurento Client", "keywords": ["Kurento", "Client", "PHP"], - "homepage": "https://github.com/rukavinamilan/kurento-client-php", + "homepage": "https://github.com/glavweb/kurento-client-php", "license": "MIT", "authors": [ - { - "name": "Milan Rukavina", - "email": "rukavinamilan@gmail.com" - } - ], + { + "name": "Milan Rukavina", + "email": "rukavinamilan@gmail.com" + }, + { + "name": "Sergey Zvyagintsev", + "email": "nitron.ru@gmail.com" + } + ], "autoload": { "psr-4": { "MgKurentoClient\\": "src/MgKurentoClient" } }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/Devristo/phpws" - } - ], "require": { - "devristo/phpws": "dev-master" + "ratchet/pawl": "^0.3.4", + "psr/log": "^1.1", + "ext-json": "*" } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..cce7b4f --- /dev/null +++ b/composer.lock @@ -0,0 +1,687 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "7fe972d559719dade79c86a222054e4b", + "packages": [ + { + "name": "evenement/evenement", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7", + "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "time": "2017-07-23T21:35:13+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2019-07-01T23:21:34+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ratchet/pawl", + "version": "v0.3.4", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/Pawl.git", + "reference": "3a7d5b78e0deaec82f42513a4a3193a8eb12feb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/Pawl/zipball/3a7d5b78e0deaec82f42513a4a3193a8eb12feb1", + "reference": "3a7d5b78e0deaec82f42513a4a3193a8eb12feb1", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0", + "php": ">=5.4", + "ratchet/rfc6455": "^0.2.3", + "react/socket": "^1.0 || ^0.8 || ^0.7" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "reactivex/rxphp": "~2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ratchet\\Client\\": "src" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Asynchronous WebSocket client", + "keywords": [ + "Ratchet", + "async", + "client", + "websocket", + "websocket client" + ], + "time": "2019-01-14T14:09:36+00:00" + }, + { + "name": "ratchet/rfc6455", + "version": "v0.2.6", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/RFC6455.git", + "reference": "879e48c840f8dbc296d68d6a5030673df79bd916" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/879e48c840f8dbc296d68d6a5030673df79bd916", + "reference": "879e48c840f8dbc296d68d6a5030673df79bd916", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^1.0", + "php": ">=5.4.2" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "react/socket": "^1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ratchet\\RFC6455\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "role": "Developer" + } + ], + "description": "RFC6455 WebSocket protocol handler", + "homepage": "http://socketo.me", + "keywords": [ + "WebSockets", + "rfc6455", + "websocket" + ], + "time": "2019-12-15T10:18:18+00:00" + }, + { + "name": "react/cache", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "aa10d63a1b40a36a486bdf527f28bac607ee6466" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/aa10d63a1b40a36a486bdf527f28bac607ee6466", + "reference": "aa10d63a1b40a36a486bdf527f28bac607ee6466", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "~2.0|~1.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "time": "2019-07-11T13:45:28+00:00" + }, + { + "name": "react/dns", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "a214d90c2884dac18d0cac6176202f247b66d762" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/a214d90c2884dac18d0cac6176202f247b66d762", + "reference": "a214d90c2884dac18d0cac6176202f247b66d762", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.0 || ^0.5", + "react/promise": "^2.7 || ^1.2.1", + "react/promise-timer": "^1.2" + }, + "require-dev": { + "clue/block-react": "^1.2", + "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "time": "2019-08-15T09:06:31+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "6d24de090cd59cfc830263cfba965be77b563c13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/6d24de090cd59cfc830263cfba965be77b563c13", + "reference": "6d24de090cd59cfc830263cfba965be77b563c13", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35" + }, + "suggest": { + "ext-event": "~1.0 for ExtEventLoop", + "ext-pcntl": "For signal handling support when using the StreamSelectLoop", + "ext-uv": "* for ExtUvLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "time": "2020-01-01T18:39:52+00:00" + }, + { + "name": "react/promise", + "version": "v2.8.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/f3cff96a19736714524ca0dd1d4130de73dbbbc4", + "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0 || ^6.5 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "time": "2020-05-12T15:16:56+00:00" + }, + { + "name": "react/promise-timer", + "version": "v1.5.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise-timer.git", + "reference": "35fb910604fd86b00023fc5cda477c8074ad0abc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/35fb910604fd86b00023fc5cda477c8074ad0abc", + "reference": "35fb910604fd86b00023fc5cda477c8074ad0abc", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", + "react/promise": "^2.7.0 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\Timer\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@lueck.tv" + } + ], + "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.", + "homepage": "https://github.com/reactphp/promise-timer", + "keywords": [ + "async", + "event-loop", + "promise", + "reactphp", + "timeout", + "timer" + ], + "time": "2019-03-27T18:10:32+00:00" + }, + { + "name": "react/socket", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "97522e24987365e1ed873f0f4884900747a668e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/97522e24987365e1ed873f0f4884900747a668e0", + "reference": "97522e24987365e1ed873f0f4884900747a668e0", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.1", + "react/event-loop": "^1.0 || ^0.5", + "react/promise": "^2.6.0 || ^1.2.1", + "react/promise-timer": "^1.4.0", + "react/stream": "^1.1" + }, + "require-dev": { + "clue/block-react": "^1.2", + "phpunit/phpunit": "^7.5 || ^6.4 || ^5.7 || ^4.8.35", + "react/promise-stream": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "time": "2020-03-12T12:15:14+00:00" + }, + { + "name": "react/stream", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "7c02b510ee3f582c810aeccd3a197b9c2f52ff1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/7c02b510ee3f582c810aeccd3a197b9c2f52ff1a", + "reference": "7c02b510ee3f582c810aeccd3a197b9c2f52ff1a", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "time": "2020-05-04T10:17:57+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-json": "*" + }, + "platform-dev": [] +} diff --git a/src/MgKurentoClient/FaceOverlayFilter.php b/src/MgKurentoClient/FaceOverlayFilter.php index 033e325..a5c5202 100644 --- a/src/MgKurentoClient/FaceOverlayFilter.php +++ b/src/MgKurentoClient/FaceOverlayFilter.php @@ -10,14 +10,18 @@ namespace MgKurentoClient; -class FaceOverlayFilter extends MediaElement implements Interfaces\FaceOverlayFilter { - public function setOverlayedImage($uri, $offsetXPercent, $offsetYPercent, $widthPercent, $heightPercent, callable $callback){ - $this->remoteInvoke('setOverlayedImage', array( - "uri" => $uri, - "offsetXPercent" => $offsetXPercent, - "offsetYPercent" => $offsetYPercent, - "widthPercent" => $widthPercent, +use React\Promise\PromiseInterface; + +class FaceOverlayFilter extends MediaElement implements Interfaces\FaceOverlayFilter +{ + public function setOverlayedImage($uri, $offsetXPercent, $offsetYPercent, $widthPercent, $heightPercent): PromiseInterface + { + return $this->remoteInvoke('setOverlayedImage', [ + "uri" => $uri, + "offsetXPercent" => $offsetXPercent, + "offsetYPercent" => $offsetYPercent, + "widthPercent" => $widthPercent, "heightPercent" => $heightPercent - ), $callback); - } + ]); + } } diff --git a/src/MgKurentoClient/Interfaces/Endpoint.php b/src/MgKurentoClient/Interfaces/Endpoint.php index 769505d..3ce1b61 100644 --- a/src/MgKurentoClient/Interfaces/Endpoint.php +++ b/src/MgKurentoClient/Interfaces/Endpoint.php @@ -10,5 +10,6 @@ namespace MgKurentoClient\Interfaces; -interface Endpoint extends MediaElement { +interface Endpoint extends MediaElement +{ } diff --git a/src/MgKurentoClient/Interfaces/FaceOverlayFilter.php b/src/MgKurentoClient/Interfaces/FaceOverlayFilter.php index 6c4689e..1d4181d 100644 --- a/src/MgKurentoClient/Interfaces/FaceOverlayFilter.php +++ b/src/MgKurentoClient/Interfaces/FaceOverlayFilter.php @@ -10,6 +10,9 @@ namespace MgKurentoClient\Interfaces; -interface FaceOverlayFilter extends Filter { - public function setOverlayedImage($uri, $offsetXPercent, $offsetYPercent, $widthPercent, $heightPercent, callable $callback); +use React\Promise\PromiseInterface; + +interface FaceOverlayFilter extends Filter +{ + public function setOverlayedImage($uri, $offsetXPercent, $offsetYPercent, $widthPercent, $heightPercent): PromiseInterface; } diff --git a/src/MgKurentoClient/Interfaces/Filter.php b/src/MgKurentoClient/Interfaces/Filter.php index c2332d0..300de6c 100644 --- a/src/MgKurentoClient/Interfaces/Filter.php +++ b/src/MgKurentoClient/Interfaces/Filter.php @@ -10,5 +10,6 @@ namespace MgKurentoClient\Interfaces; -interface Filter extends MediaElement { +interface Filter extends MediaElement +{ } diff --git a/src/MgKurentoClient/Interfaces/MediaElement.php b/src/MgKurentoClient/Interfaces/MediaElement.php index 95281de..a3bf042 100644 --- a/src/MgKurentoClient/Interfaces/MediaElement.php +++ b/src/MgKurentoClient/Interfaces/MediaElement.php @@ -10,11 +10,15 @@ namespace MgKurentoClient\Interfaces; -interface MediaElement extends MediaObject { - public function connect(MediaElement $sink, $callback); +use React\Promise\PromiseInterface; + +interface MediaElement extends MediaObject +{ + public function connect(MediaElement $sink): PromiseInterface; + public function addSource(MediaElement $source); + public function getMediaSinks(); - public function getMediaSrcs(); - - + + public function getMediaSources(); } diff --git a/src/MgKurentoClient/Interfaces/MediaObject.php b/src/MgKurentoClient/Interfaces/MediaObject.php index d992015..db8deb2 100644 --- a/src/MgKurentoClient/Interfaces/MediaObject.php +++ b/src/MgKurentoClient/Interfaces/MediaObject.php @@ -10,11 +10,17 @@ namespace MgKurentoClient\Interfaces; -interface MediaObject { - public function build(callable $callback, array $params = array()); - public function getId(); +use React\Promise\PromiseInterface; + +interface MediaObject +{ + public function build(array $params = []): PromiseInterface; + + public function release(): PromiseInterface; + + public function getId(); + public function getMediaPipeline(); + public function getParent(); - public function release(callable $callback); - } diff --git a/src/MgKurentoClient/Interfaces/MediaPipeline.php b/src/MgKurentoClient/Interfaces/MediaPipeline.php index c508e50..a81945f 100644 --- a/src/MgKurentoClient/Interfaces/MediaPipeline.php +++ b/src/MgKurentoClient/Interfaces/MediaPipeline.php @@ -10,9 +10,12 @@ namespace MgKurentoClient\Interfaces; -interface MediaPipeline extends MediaObject { +use MgKurentoClient\JsonRpc\Client; + +interface MediaPipeline extends MediaObject +{ /** - * @return \MgKurentoClient\JsonRpc\Client + * @return Client */ public function getJsonRpc(); } diff --git a/src/MgKurentoClient/Interfaces/PlayerEndpoint.php b/src/MgKurentoClient/Interfaces/PlayerEndpoint.php index ffe1542..3503937 100644 --- a/src/MgKurentoClient/Interfaces/PlayerEndpoint.php +++ b/src/MgKurentoClient/Interfaces/PlayerEndpoint.php @@ -10,7 +10,11 @@ namespace MgKurentoClient\Interfaces; -interface PlayerEndpoint extends UriEndpoint { - public function play(callable $callback); - public function addEndOfStreamListener(callable $listener, callable $callback); +use React\Promise\PromiseInterface; + +interface PlayerEndpoint extends UriEndpoint +{ + public function play(): PromiseInterface; + + public function addEndOfStreamListener(callable $listener): PromiseInterface; } diff --git a/src/MgKurentoClient/Interfaces/RecorderEndpoint.php b/src/MgKurentoClient/Interfaces/RecorderEndpoint.php index ee7d067..5532aed 100644 --- a/src/MgKurentoClient/Interfaces/RecorderEndpoint.php +++ b/src/MgKurentoClient/Interfaces/RecorderEndpoint.php @@ -10,6 +10,9 @@ namespace MgKurentoClient\Interfaces; -interface RecorderEndpoint extends UriEndpoint { - public function record(callable $callback); +use React\Promise\PromiseInterface; + +interface RecorderEndpoint extends UriEndpoint +{ + public function record(): PromiseInterface; } diff --git a/src/MgKurentoClient/Interfaces/RtpEndpoint.php b/src/MgKurentoClient/Interfaces/RtpEndpoint.php index 47b0b27..c6b1f73 100644 --- a/src/MgKurentoClient/Interfaces/RtpEndpoint.php +++ b/src/MgKurentoClient/Interfaces/RtpEndpoint.php @@ -10,5 +10,6 @@ namespace MgKurentoClient\Interfaces; -interface RtpEndpoint extends SdpEndpoint { +interface RtpEndpoint extends SdpEndpoint +{ } diff --git a/src/MgKurentoClient/Interfaces/SdpEndpoint.php b/src/MgKurentoClient/Interfaces/SdpEndpoint.php index 6268ab3..f4024ea 100644 --- a/src/MgKurentoClient/Interfaces/SdpEndpoint.php +++ b/src/MgKurentoClient/Interfaces/SdpEndpoint.php @@ -10,12 +10,17 @@ namespace MgKurentoClient\Interfaces; -interface SdpEndpoint extends SessionEndpoint { +use React\Promise\PromiseInterface; + +interface SdpEndpoint extends SessionEndpoint +{ public function generateOffer(); - public function getLocalSessionDescriptor(); + + public function processAnswer($answer): PromiseInterface; + + public function processOffer($offer): PromiseInterface; + + public function getLocalSessionDescriptor(); + public function getRemoteSessionDescriptor(); - public function processAnswer($answer, $callback); - public function processOffer($offer, $callback); - - } diff --git a/src/MgKurentoClient/Interfaces/SessionEndpoint.php b/src/MgKurentoClient/Interfaces/SessionEndpoint.php index 658f392..c87bfa5 100644 --- a/src/MgKurentoClient/Interfaces/SessionEndpoint.php +++ b/src/MgKurentoClient/Interfaces/SessionEndpoint.php @@ -10,5 +10,6 @@ namespace MgKurentoClient\Interfaces; -interface SessionEndpoint extends Endpoint { +interface SessionEndpoint extends Endpoint +{ } diff --git a/src/MgKurentoClient/Interfaces/UriEndpoint.php b/src/MgKurentoClient/Interfaces/UriEndpoint.php index 6ba0d2a..2f61dba 100644 --- a/src/MgKurentoClient/Interfaces/UriEndpoint.php +++ b/src/MgKurentoClient/Interfaces/UriEndpoint.php @@ -10,5 +10,6 @@ namespace MgKurentoClient\Interfaces; -interface UriEndpoint extends Endpoint { +interface UriEndpoint extends Endpoint +{ } diff --git a/src/MgKurentoClient/Interfaces/WebRtcEndpoint.php b/src/MgKurentoClient/Interfaces/WebRtcEndpoint.php index 8921dfd..6e39485 100644 --- a/src/MgKurentoClient/Interfaces/WebRtcEndpoint.php +++ b/src/MgKurentoClient/Interfaces/WebRtcEndpoint.php @@ -10,5 +10,11 @@ namespace MgKurentoClient\Interfaces; -interface WebRtcEndpoint extends SdpEndpoint { +use React\Promise\PromiseInterface; + +interface WebRtcEndpoint extends SdpEndpoint +{ + public function gatherCandidates(): PromiseInterface; + + public function addIceCandidate($candidate): PromiseInterface; } diff --git a/src/MgKurentoClient/JsonRpc/Client.php b/src/MgKurentoClient/JsonRpc/Client.php index 5dc8e38..8cd69bd 100644 --- a/src/MgKurentoClient/JsonRpc/Client.php +++ b/src/MgKurentoClient/JsonRpc/Client.php @@ -10,179 +10,248 @@ namespace MgKurentoClient\JsonRpc; +use Psr\Log\LoggerInterface; +use React\EventLoop\LoopInterface; +use React\EventLoop\TimerInterface; +use React\Promise\Deferred; +use React\Promise\PromiseInterface; + /** * JSON RPC implementation - * + * * @author Milan Rukavina - * + * */ -class Client{ +class Client +{ + protected $id = 0; + /** * - * @var \MgKurentoClient\WebRtc\Client + * @var \MgKurentoClient\WebRtc\Client */ protected $wsClient; - protected $id = 0; + protected $sessionId = null; - protected $callbacks = array(); - protected $subscriptions = array(); + + protected $deferred = []; + + protected $subscriptions = []; + protected $logger = null; - - function __construct($websocketUrl, $loop, $logger, $callback) { - $this->logger = $logger; + + /** + * @var LoopInterface + */ + private $loop; + + /** + * @var TimerInterface + */ + private $pingTimer; + + /** + * Client constructor. + * + * @param string $websocketUrl + * @param LoopInterface $loop + * @param LoggerInterface $logger + */ + public function __construct($websocketUrl, $loop, $logger) + { + $this->loop = $loop; + $this->logger = $logger; $this->wsClient = new \MgKurentoClient\WebRtc\Client($websocketUrl, $loop, $this->logger); - $this->wsClient->open(); - $this->wsClient->onMessage(function($data){ + $this->wsClient->on('message', function ($data) { $this->receive(json_decode($data, true)); }); - $this->wsClient->onConnect($callback); + $this->wsClient->once('connect', function () { + $this->startPing(); + }); } /** - * Send method - * - * @param string $method - * @param array $params - * @param callable $callback + * @return PromiseInterface */ - protected function send($method, $params, callable $callback){ - $this->id++; - if(isset($this->sessionId)){ - $params['sessionId'] = $this->sessionId; - } - - $data = array( - "jsonrpc" => "2.0", - "id" => $this->id, - "method" => $method, - "params" => $params - ); - $this->wsClient->send(json_encode($data, JSON_UNESCAPED_SLASHES)); - $this->callbacks[$this->id] = $callback; + public function connect() + { + return $this->wsClient->connect(); } - + /** * Receive data - * + * * @param array $data * @return mixed - * @throws \MgKurentoClient\JsonRpc\Exception + * @throws Exception */ - public function receive($data){ - //set sesstion - if(isset($data['result']['sessionId'])){ + public function receive($data) + { + //set session + if (isset($data['result']['sessionId'])) { $this->sessionId = $data['result']['sessionId']; } //onEvent? - if(isset($data['method']) && $data['method'] == 'onEvent'){ - if(isset($this->subscriptions[$data['params']['value']['type']])){ - $onEvent = $this->subscriptions[$data['params']['value']['type']]; - $onEvent($data); + if (isset($data['method']) && $data['method'] == 'onEvent') { + $value = $data['params']['value']; + $key = $value['object'] . '__' . $value['type']; + if (isset($this->subscriptions[$key])) { + $onEvent = $this->subscriptions[$key]['callback']; + $onEvent($value['data']); } + return; } - if(array_key_exists('result',$data) && isset($data['id']) && isset($this->callbacks[$data['id']])){ - $callback = $this->callbacks[$data['id']]; - $callback(true, $data['result']); - unset($this->callbacks[$data['id']]); + /** @var Deferred $deferred */ + if (array_key_exists('result', $data) && isset($data['id']) && isset($this->deferred[$data['id']])) { + $deferred = $this->deferred[$data['id']]; + $deferred->resolve($data['result']); + unset($this->deferred[$data['id']]); + return; } - if(isset($data['error']) && isset($data['id']) && isset($this->callbacks[$data['id']])){ - $callback = $this->callbacks[$data['id']]; - $callback(false, $data['error']); - unset($this->callbacks[$data['id']]); + if (isset($data['error']) && isset($data['id']) && isset($this->deferred[$data['id']])) { + $deferred = $this->deferred[$data['id']]; + $deferred->reject($data['error']); + unset($this->deferred[$data['id']]); + return; } - - throw new \MgKurentoClient\JsonRpc\Exception('Json callback not found'); - } - + + throw new Exception('Json deferred not found'); + } + /** * Create method - * + * * @param string $type * @param array $creationParams - * @param callable $callback - * @return mixed + * @return PromiseInterface */ - public function sendCreate($type, $creationParams, callable $callback){ - $message = array( - 'type' => $type - ); - if(isset($creationParams) && count($creationParams)){ + public function sendCreate($type, $creationParams): PromiseInterface + { + $message = [ + 'type' => $type + ]; + if (isset($creationParams) && count($creationParams)) { $message['constructorParams'] = $creationParams; } - return $this->send('create', $message, $callback); + + return $this->send('create', $message); } - + /** * Invoke method - * + * * @param string $object * @param string $operation * @param array $operationParams - * @param callable $callback - * @return mixed + * @return PromiseInterface */ - public function sendInvoke($object, $operation, $operationParams, callable $callback){ - return $this->send('invoke', array( - 'object' => $object, - 'operation' => $operation, - 'operationParams' => $operationParams - ), $callback); + public function sendInvoke($object, $operation, $operationParams): PromiseInterface + { + return $this->send('invoke', [ + 'object' => $object, + 'operation' => $operation, + 'operationParams' => $operationParams + ]); } - + /** * Release method - * + * * @param string $object - * @param callable $callback - * @return type + * @return PromiseInterface */ - public function sendRelease($object, callable $callback){ - return $this->send('release', array( - 'object' => $object - ), $callback); + public function sendRelease($object): PromiseInterface + { + return $this->send('release', [ + 'object' => $object + ]); } - + /** * Subscribe method - * + * * @param string $object * @param string $type * @param string $onEvent - * @param callable $callback - * @return mixed + * @return PromiseInterface */ - public function sendSubscribe($object, $type, $onEvent, callable $callback){ - return $this->send('subscribe', array( - 'object' => $object, - 'type' => $type - ), function($success, $data) use($onEvent, $callback){ - if(!$success){ - return false; - } - $this->subscriptions[$data['value']] = $onEvent; - $callback($success, $data); - }); + public function sendSubscribe($object, $type, $onEvent): PromiseInterface + { + return $this->send('subscribe', [ + 'object' => $object, + 'type' => $type + ]) + ->then(function ($data) use ($object, $type, $onEvent) { + $key = $object . '__' . $type; + $this->subscriptions[$key] = [ + 'id' => $data['value'], + 'callback' => $onEvent + ]; + + return $data['value']; + }); } - + /** * Unsubscribe method - * - * @param string $subscription - * @param callable $callback - * @return mixed + * + * @param string $subscriptionId + * @return PromiseInterface + */ + public function sendUnsubscribe($subscriptionId): PromiseInterface + { + return $this->send('unsubscribe', [ + 'subscription' => $subscriptionId + ]) + ->then(function ($data) use ($subscriptionId) { + foreach ($this->subscriptions as $key => $subscription) { + if ($subscription['id'] === $subscriptionId) { + unset($this->subscriptions[$key]); + break; + } + } + + return $data; + }); + } + + /** + * Send method + * + * @param string $method + * @param array $params + * @return PromiseInterface */ - public function sendUnsubscribe($subscription, callable $callback){ - return $this->send('unsubscribe', array( - 'subscription' => $subscription - ), function($success, $data) use ($subscription){ - if(!$success){ - return false; - } - unset($this->subscriptions[$subscription]); - $callback($success, $data); + protected function send($method, $params): PromiseInterface + { + $this->id++; + if (isset($this->sessionId)) { + $params['sessionId'] = $this->sessionId; + } + + $data = [ + "jsonrpc" => "2.0", + "id" => $this->id, + "method" => $method, + "params" => $params + ]; + $this->wsClient->send(json_encode($data, JSON_UNESCAPED_SLASHES)); + + $deferred = new Deferred(); + $this->deferred[$this->id] = $deferred; + + return $deferred->promise(); + } + + private function startPing() + { + $this->pingTimer = $this->loop->addPeriodicTimer(60, function () { + if ($this->wsClient->isConnected()) { + $this->send('ping', []); + } }); - } + } } diff --git a/src/MgKurentoClient/KurentoClient.php b/src/MgKurentoClient/KurentoClient.php index 9898639..8bcc578 100644 --- a/src/MgKurentoClient/KurentoClient.php +++ b/src/MgKurentoClient/KurentoClient.php @@ -11,69 +11,60 @@ namespace MgKurentoClient; +use Psr\Log\LoggerInterface; +use React\EventLoop\LoopInterface; +use React\Promise\PromiseInterface; + /** - * Factory to create {MediaPipeline} in the media server. + * KurentoClient * * @author Milan Rukavina */ -class KurentoClient { - - /** - * - * @var KurentoClient - */ - protected static $instance; - +class KurentoClient +{ + /** * * @var JsonRpc\Client; */ private $jsonRpc = null; - + + + private $logger = null; + /** + * KurentoClient constructor. * - * @var \MgKurentoClient\MediaPipeline + * @param string $websocketUrl + * @param LoopInterface $loop + * @param LoggerInterface $logger */ - private $pipeline = null; - - private $logger = null; - - private function __construct($websocketUrl, $loop, $logger, callable $callback) { - $this->logger = $logger; - $this->jsonRpc = new JsonRpc\Client($websocketUrl, $loop, $this->logger, $callback); + public function __construct($websocketUrl, $loop, $logger) + { + $this->logger = $logger; + $this->jsonRpc = new JsonRpc\Client($websocketUrl, $loop, $this->logger); } - + /** * Creates Client object - * - * @param string $websocketUrl - * @param LibEventLoop|LibEvLoop|ExtEventLoop|StreamSelectLoop $loop - * @param \Zend\Log\Logger $logger - * - * @return KurentoClient + * + * @return PromiseInterface */ - public static function create($websocketUrl, $loop, $logger, callable $callback) { - if(!isset(self::$instance)){ - self::$instance = new self($websocketUrl, $loop, $logger, function() use ($callback){ - $callback(self::$instance); - }); - } - return self::$instance; + public function connect(): PromiseInterface + { + return $this->jsonRpc->connect()->then(function () { + return $this; + }); } /** * Creates a new {MediaPipeline} in the media server - * - * @param callable $callback * - * @return Interfaces\MediaPipeline + * @param array $params + * @return PromiseInterface */ - public function createMediaPipeline(callable $callback) { - $this->pipeline = new MediaPipeline($this->jsonRpc); - $this->pipeline->build(function($success, $data) use ($callback){ - $callback($this->pipeline, $success, $data); - }); - return $this->pipeline; + public function createMediaPipeline(array $params = []): PromiseInterface + { + return (new MediaPipeline($this->jsonRpc))->build($params); } - -} \ No newline at end of file +} diff --git a/src/MgKurentoClient/MediaElement.php b/src/MgKurentoClient/MediaElement.php index 6c22309..b39d41d 100644 --- a/src/MgKurentoClient/MediaElement.php +++ b/src/MgKurentoClient/MediaElement.php @@ -10,31 +10,37 @@ namespace MgKurentoClient; -class MediaElement extends MediaObject implements Interfaces\MediaElement { - - protected $sinks = array(); - protected $sources = array(); - - public function connect(Interfaces\MediaElement $sink, $callback){ - $this->remoteInvoke('connect', array('sink' => $sink->getId()), function($success, $data) use ($callback, $sink){ - if($success){ +use React\Promise\PromiseInterface; + +class MediaElement extends MediaObject implements Interfaces\MediaElement +{ + protected $sinks = []; + + protected $sources = []; + + public function connect(Interfaces\MediaElement $sink): PromiseInterface + { + return $this->remoteInvoke('connect', ['sink' => $sink->getId()]) + ->then(function ($data) use ($sink) { $this->sinks[] = $sink; - $sink->addSource($this); - } - $callback($success, $data); - }); + $sink->addSource($this); + + return $data; + }); } - - public function addSource(Interfaces\MediaElement $source){ + + public function addSource(Interfaces\MediaElement $source) + { $this->sources[] = $source; } - - public function getMediaSinks(){ + + public function getMediaSinks() + { return $this->sinks; } - - public function getMediaSrcs(){ + + public function getMediaSources() + { return $this->sources; } - } diff --git a/src/MgKurentoClient/MediaObject.php b/src/MgKurentoClient/MediaObject.php index 4ad08a5..234c403 100644 --- a/src/MgKurentoClient/MediaObject.php +++ b/src/MgKurentoClient/MediaObject.php @@ -10,71 +10,90 @@ namespace MgKurentoClient; -class MediaObject implements Interfaces\MediaObject { - - protected $pipeline = null; +use React\Promise\PromiseInterface; + +class MediaObject implements Interfaces\MediaObject +{ protected $id = null; - protected $subscriptions = array(); + protected $pipeline = null; - function __construct(Interfaces\MediaPipeline $pipeline) { + public function __construct(Interfaces\MediaPipeline $pipeline) + { $this->pipeline = $pipeline; } - - public function getId(){ - return $this->id; - } - - public function getMediaPipeline(){ - return $this->pipeline; - + public function release(): PromiseInterface + { + return $this->remoteRelease(); + } + + public function build(array $params = []): PromiseInterface + { + return $this->remoteCreate($this->getRemoteTypeName(), $params) + ->then(function () { + return $this; + }); } - - public function getParent(){ - + + public function remoteCreate($remoteType, array $params = []): PromiseInterface + { + $localParams = ($this->pipeline === $this) ? [] : ['mediaPipeline' => $this->pipeline->getId()]; + + return $this->pipeline->getJsonRpc() + ->sendCreate($remoteType, array_merge($localParams, $params)) + ->then(function ($data) { + if (isset($data['value'])) { + $this->id = $data['value']; + } + + return $data; + }); } - - public function release(callable $callback){ - $this->remoteRelease($callback); + + public function remoteInvoke($operation, $operationParams): PromiseInterface + { + return $this->pipeline->getJsonRpc() + ->sendInvoke($this->getId(), $operation, $operationParams); } - - protected function getRemoteTypeName(){ - $fullName = get_class($this); - $parts = explode("\\", $fullName); - return $parts[count($parts) - 1]; + + public function remoteRelease(): PromiseInterface + { + return $this->pipeline->getJsonRpc() + ->sendRelease($this->getId()); } - - public function build(callable $callback, array $params = array()){ - $this->remoteCreate($this->getRemoteTypeName(), function($success, $data) use($callback){ - $callback($this, $success, $data); - }, $params); - } - - public function remoteCreate($remoteType, callable $callback, array $params = array()){ - $localParams = ($this->pipeline == $this)? array(): array('mediaPipeline' => $this->pipeline->getId()); - $this->pipeline->getJsonRpc()->sendCreate($remoteType, array_merge($localParams, $params), function($success, $data) use($callback){ - if($success && isset($data['value'])){ - $this->id = $data['value']; - } - $callback($success, $data); - }); - } - - public function remoteInvoke($operation, $operationParams, callable $callback){ - $this->pipeline->getJsonRpc()->sendInvoke($this->getId(), $operation, $operationParams, $callback); + + public function remoteUnsubscribe($subscriptionId): PromiseInterface + { + return $this->pipeline->getJsonRpc() + ->sendUnsubscribe($subscriptionId); + } + + public function remoteSubscribe($type, $onEvent): PromiseInterface + { + return $this->pipeline->getJsonRpc() + ->sendSubscribe($this->getId(), $type, $onEvent); + } + + public function getId() + { + return $this->id; + } + + public function getMediaPipeline() + { + return $this->pipeline; } - - public function remoteRelease(callable $callback){ - $this->pipeline->getJsonRpc()->sendRelease($this->getId(), $callback); + + public function getParent() + { } - - protected function remoteSubscribe($type, $onEvent, callable $callback){ - $this->pipeline->getJsonRpc()->sendSubscribe($this->getId(), $type, $onEvent, $callback); + + protected function getRemoteTypeName() + { + $fullName = get_class($this); + $parts = explode("\\", $fullName); + + return $parts[count($parts) - 1]; } - - public function remoteUnsubscribe($subscription, callable $callback){ - $this->pipeline->getJsonRpc()->sendUnsubscribe($subscription, $callback); - } - } diff --git a/src/MgKurentoClient/MediaPipeline.php b/src/MgKurentoClient/MediaPipeline.php index 54cb0f1..99696b2 100644 --- a/src/MgKurentoClient/MediaPipeline.php +++ b/src/MgKurentoClient/MediaPipeline.php @@ -10,21 +10,25 @@ namespace MgKurentoClient; -class MediaPipeline extends MediaObject implements Interfaces\MediaPipeline { - +use MgKurentoClient\JsonRpc\Client; + +class MediaPipeline extends MediaObject implements Interfaces\MediaPipeline +{ + /** * - * @var \MgKurentoClient\JsonRpc\Client; + * @var Client; */ - private $jsonRpc = null; - - function __construct(JsonRpc\Client $jsonRpc) { + private $jsonRpc = null; + + public function __construct(JsonRpc\Client $jsonRpc) + { $this->jsonRpc = $jsonRpc; parent::__construct($this); - } - - public function getJsonRpc(){ + } + + public function getJsonRpc() + { return $this->jsonRpc; } - } diff --git a/src/MgKurentoClient/PlayerEndpoint.php b/src/MgKurentoClient/PlayerEndpoint.php index aeb2ee6..2ad2676 100644 --- a/src/MgKurentoClient/PlayerEndpoint.php +++ b/src/MgKurentoClient/PlayerEndpoint.php @@ -10,12 +10,17 @@ namespace MgKurentoClient; -class PlayerEndpoint extends MediaElement implements Interfaces\PlayerEndpoint { - public function play(callable $callback){ - $this->remoteInvoke('play', array(), $callback); +use React\Promise\PromiseInterface; + +class PlayerEndpoint extends MediaElement implements Interfaces\PlayerEndpoint +{ + public function play(): PromiseInterface + { + return $this->remoteInvoke('play', []); + } + + public function addEndOfStreamListener(callable $listener): PromiseInterface + { + return $this->remoteSubscribe('EndOfStream', $listener); } - - public function addEndOfStreamListener(callable $listener, callable $callback){ - $this->remoteSubscribe('EndOfStream', $listener, $callback); - } } diff --git a/src/MgKurentoClient/RecorderEndpoint.php b/src/MgKurentoClient/RecorderEndpoint.php index acd9c7f..519c0ee 100644 --- a/src/MgKurentoClient/RecorderEndpoint.php +++ b/src/MgKurentoClient/RecorderEndpoint.php @@ -10,8 +10,12 @@ namespace MgKurentoClient; -class RecorderEndpoint extends MediaElement implements Interfaces\RecorderEndpoint { - public function record(callable $callback){ - $this->remoteInvoke('record', array(), $callback); - } +use React\Promise\PromiseInterface; + +class RecorderEndpoint extends MediaElement implements Interfaces\RecorderEndpoint +{ + public function record(): PromiseInterface + { + return $this->remoteInvoke('record', []); + } } diff --git a/src/MgKurentoClient/RtpEndpoint.php b/src/MgKurentoClient/RtpEndpoint.php index b5d0d7d..cedeabd 100644 --- a/src/MgKurentoClient/RtpEndpoint.php +++ b/src/MgKurentoClient/RtpEndpoint.php @@ -10,5 +10,36 @@ namespace MgKurentoClient; -class RtpEndpoint extends MediaElement implements Interfaces\RtpEndpoint { +use React\Promise\PromiseInterface; +use function React\Promise\reject; + +class RtpEndpoint extends MediaElement implements Interfaces\RtpEndpoint +{ + public function generateOffer() + { + // TODO: Implement generateOffer() method. + } + + public function processAnswer($answer): PromiseInterface + { + // TODO: Implement processAnswer() method. + return reject(); + + } + + public function processOffer($offer): PromiseInterface + { + // TODO: Implement processOffer() method. + return reject(); + } + + public function getLocalSessionDescriptor() + { + // TODO: Implement getLocalSessionDescriptor() method. + } + + public function getRemoteSessionDescriptor() + { + // TODO: Implement getRemoteSessionDescriptor() method. + } } diff --git a/src/MgKurentoClient/WebRtc/Client.php b/src/MgKurentoClient/WebRtc/Client.php index 1cf339c..680a110 100644 --- a/src/MgKurentoClient/WebRtc/Client.php +++ b/src/MgKurentoClient/WebRtc/Client.php @@ -10,86 +10,144 @@ namespace MgKurentoClient\WebRtc; +use Evenement\EventEmitter; +use Exception; +use Psr\Log\LoggerInterface; +use Ratchet\Client\Connector; +use Ratchet\Client\WebSocket; +use Ratchet\RFC6455\Messaging\Frame; +use Ratchet\RFC6455\Messaging\MessageInterface; +use React\EventLoop\LoopInterface; +use React\Promise\PromiseInterface; + /** * Websocket transport layer implementation - * - * @author Milan Rukavina + * + * @author Milan Rukavina */ -class Client { - +class Client extends EventEmitter +{ + /** - * - * @var \Devristo\Phpws\Client\WebSocket + * @var LoopInterface */ - private $client = null; private $loop = null; + + /** + * @var LoggerInterface + */ private $logger = null; + /** + * @var string + */ + private $websocketUrl; /** - * - * Constructor + * @var WebSocket */ - public function __construct($websocketUrl, $loop, $logger) - { - $this->logger = $logger; - $this->loop = $loop; - $this->client = new \Devristo\Phpws\Client\WebSocket($websocketUrl . '?encoding=text', $this->loop, $this->logger); - - //debug - $this->client->on("request", function($headers){ - $this->logger->notice("\nRequest object created!\n"); - }); + private $connection = null; - $this->client->on("handshake", function() { - $this->logger->notice("\nHandshake received!\n"); - }); - $this->client->on("connect", function(){ - $this->logger->notice("\nConnected!\n"); - }); + /** + * @var bool + */ + private $connecting = false; + - $this->client->on("message", function($message){ - $this->logger->notice("\nGot message: " . $message->getData()); - }); - - } - /** - * Open WS connections + * + * Constructor + * + * @param string $websocketUrl + * @param LoopInterface $loop + * @param LoggerInterface $logger */ - public function open() { - $this->client->open(); + public function __construct($websocketUrl, $loop, $logger) + { + $this->websocketUrl = $websocketUrl; + $this->loop = $loop; + $this->logger = $logger; } - + /** - * Send message - * - * @param string $message + * @return PromiseInterface */ - public function send($message){ - $this->logger->notice("\nSending message: " . $message); - $this->client->send($message); + public function connect() + { + $this->connecting = true; + $connector = new Connector($this->loop); + + return $connector($this->websocketUrl . '?encoding=text') + ->then(function (WebSocket $connection) { + $this->logger->info("Connected"); + $this->connection = $connection; + $this->emit('connect', [$connection]); + $this->connecting = false; + + $connection->on('message', function (MessageInterface $msg) { + $this->logger->debug("Got message: {$msg}"); + $this->emit('message', [$msg]); + }); + + $connection->on('close', function ($code = null, $reason = null) { + $this->logger->info("Connection closed ({$code} - {$reason})"); + $this->emit('close', [$code, $reason]); + if ($code === Frame::CLOSE_ABNORMAL) { + $this->reconnect(); + } + }); + + $connection->on('error', function (MessageInterface $error) { + $this->logger->error("Error: {$error}"); + $this->emit('error', [$error]); + }); + }, function (Exception $e) { + $this->logger->error("Could not connect: {$e->getMessage()}"); + $this->connection = null; + $this->reconnect(); + }); } - + /** - * On message received callback - * - * @param callable $callback + * Send message + * + * @param string $message */ - public function onMessage(callable $callback){ - $this->client->on("message", function($message) use ($callback){ - $callback($message->getData()); - }); + public function send($message) + { + if (!$this->connection) { + if (!$this->connecting) { + $this->connect(); + } + $this->once('connect', function () use ($message) { + $this->_send($message); + }); + } else { + $this->_send($message); + } + } + + private function reconnect(): void + { + $this->logger->info("Reconnect after 5 seconds"); + $this->loop->addTimer(5, function () { + $this->logger->info("Reconnecting"); + $this->connect(); + }); } - + /** - * On connect callback - * - * @param callable $callback + * @param string $message */ - public function onConnect(callable $callback){ - $this->client->on("connect", $callback); - } + private function _send(string $message): void + { + $this->logger->debug("Sending message: {$message}"); + $this->connection->send($message); + } + public function isConnected(): bool + { + return $this->connection !== null; + } } diff --git a/src/MgKurentoClient/WebRtcEndpoint.php b/src/MgKurentoClient/WebRtcEndpoint.php index 681abaf..05b4fd8 100644 --- a/src/MgKurentoClient/WebRtcEndpoint.php +++ b/src/MgKurentoClient/WebRtcEndpoint.php @@ -2,23 +2,45 @@ namespace MgKurentoClient; -class WebRtcEndpoint extends MediaElement implements Interfaces\WebRtcEndpoint { - - public function generateOffer(){ - +use React\Promise\PromiseInterface; + +class WebRtcEndpoint extends MediaElement implements Interfaces\WebRtcEndpoint +{ + public function generateOffer(): PromiseInterface + { + return $this->remoteInvoke('generateOffer', []) + ->then(function($result) { + return $result['value']; + }); } - public function getLocalSessionDescriptor(){ - + + public function getLocalSessionDescriptor() + { + // TODO: Implement getLocalSessionDescriptor() method. } - public function getRemoteSessionDescriptor(){ - + + public function getRemoteSessionDescriptor() + { + // TODO: Implement getRemoteSessionDescriptor() method. } - public function processAnswer($answer, $callback){ - + + public function processAnswer($answer): PromiseInterface + { + return $this->remoteInvoke('processAnswer', ['answer' => $answer]); } - public function processOffer($offer, $callback){ - $this->remoteInvoke('processOffer', array('offer' => $offer), function($success, $data) use ($callback){ - $callback($success, $data); - }); + + public function processOffer($offer): PromiseInterface + { + return $this->remoteInvoke('processOffer', ['offer' => $offer]); + } + + public function gatherCandidates(): PromiseInterface + { + return $this->remoteInvoke('gatherCandidates', []); + } + + public function addIceCandidate($candidate): PromiseInterface + { + return $this->remoteInvoke('addIceCandidate', ['candidate' => $candidate]); } }