├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README_zh-CN-PHP.md ├── composer.json ├── example └── example.php ├── lib ├── Pili.php ├── Pili │ ├── Api.php │ ├── Config.php │ ├── Hub.php │ ├── Stream.php │ └── Transport.php └── Qiniu │ ├── Credentials.php │ ├── HttpRequest.php │ ├── HttpResponse.php │ └── Utils.php ├── phpunit.xml.dist └── tests ├── Pili └── Tests │ └── UtilTest.php └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | composer.lock 4 | vendor 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # using docker container 2 | sudo: false 3 | 4 | language: php 5 | php: 6 | - 7.0 7 | before_script: 8 | - travis_retry composer self-update 9 | - travis_retry composer install --no-interaction --prefer-source --dev 10 | script: 11 | # - ./vendor/bin/phpcs --standard=PSR2 src 12 | # - ./vendor/bin/phpcs --standard=PSR2 examples 13 | # - ./vendor/bin/phpcs --standard=PSR2 tests 14 | - ./vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover tests/Pili/Tests/ 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Pili Engineering, Qiniu Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pili Streaming Cloud server-side library for PHP 2 | 3 | ## Features 4 | 5 | - Stream Create,Get,List 6 | - [x] $hub->createStream() 7 | - [x] $hub->getStream() 8 | - [x] $hub->listStreams() 9 | - Stream operations else 10 | - [x] stream->toJSONString() 11 | - [x] stream->update() 12 | - [x] stream->disable() 13 | - [x] stream->enable() 14 | - [x] stream->status() 15 | - [x] stream->rtmpPublishUrl() 16 | - [x] stream->rtmpLiveUrls() 17 | - [x] stream->hlsLiveUrls() 18 | - [x] stream->httpFlvLiveUrls() 19 | - [x] stream->segments() 20 | - [x] stream->hlsPlaybackUrls() 21 | - [x] stream->snapshot() 22 | - [x] stream->saveAs() 23 | - [x] stream->delete() 24 | 25 | 26 | ## Contents 27 | 28 | - [Installation](#installation) 29 | - [Usage](#usage) 30 | - [Configuration](#configuration) 31 | - [Hub](#hub) 32 | - [Instantiate a Pili Hub object](#instantiate-a-pili-hub-object) 33 | - [Create a new Stream](#create-a-new-stream) 34 | - [Get a Stream](#get-a-stream) 35 | - [List Streams](#List-streams) 36 | - [Stream](#stream) 37 | - [To JSON string](#to-json-string) 38 | - [Update a Stream](#update-a-stream) 39 | - [Disable a Stream](#disable-a-stream) 40 | - [Enable a Stream](#enable-a-stream) 41 | - [Get Stream status](#get-stream-status) 42 | - [Generate RTMP publish URL](#generate-rtmp-publish-url) 43 | - [Generate RTMP live play URLs](#generate-rtmp-live-play-urls) 44 | - [Generate HLS live play URLs](generate-hls-live-play-urls) 45 | - [Generate Http-Flv live play URLs](generate-http-flv-live-play-urls) 46 | - [Get Stream segments](#get-stream-segments) 47 | - [Generate HLS playback URLs](generate-hls-playback-urls) 48 | - [Save Stream as a file](#save-stream-as-a-file) 49 | - [Snapshot Stream](#snapshot-stream) 50 | - [Delete a Stream](#delete-a-stream) 51 | - [History](#history) 52 | 53 | 54 | ## Installaion 55 | 56 | ### Requirements 57 | 58 | - PHP >= 5.3.0 59 | 60 | ### Install with Composer 61 | 62 | If you're using [Composer](http://getcomposer.org) to manage dependencies, you can add pili-sdk-php with it. 63 | 64 | ```bash 65 | # Install Composer 66 | curl -sS https://getcomposer.org/installer | php 67 | ``` 68 | 69 | You can add Pili as a dependency using the `composer.phar` CLI: 70 | 71 | ```bash 72 | php composer.phar require pili-engineering/pili-sdk-php:dev-master 73 | ``` 74 | 75 | Alternatively, you can specify pili-sdk-php as a dependency in your project's 76 | existing `composer.json` file: 77 | 78 | ```js 79 | { 80 | "require": { 81 | "pili-engineering/pili-sdk-php": "dev-master" 82 | } 83 | } 84 | ``` 85 | 86 | After installing, you need to require Composer's autoloader: 87 | 88 | ```php 89 | require 'vendor/autoload.php'; 90 | ``` 91 | 92 | You can find out more on how to install Composer, configure autoloading, and 93 | other best-practices for defining dependencies at . 94 | 95 | ### Install source from GitHub 96 | 97 | The `pili-sdk-php` requires PHP `v5.3+`. Download the PHP library from Github, and require in your script like so: 98 | 99 | To install the source code: 100 | 101 | ```bash 102 | $ git clone https://github.com/pili-engineering/pili-sdk-php.git 103 | ``` 104 | 105 | And include it in your scripts: 106 | 107 | ```php 108 | require_once '/path/to/pili-sdk-php/lib/Pili.php'; 109 | ``` 110 | 111 | ### Install source from zip/tarball 112 | 113 | Alternatively, you can fetch a [tarball](https://github.com/pili-engineering/pili-sdk-php/tarball/master) or [zipball](https://github.com/pili-engineering/pili-sdk-php/zipball/master): 114 | 115 | ```bash 116 | $ curl -L https://github.com/pili-engineering/pili-sdk-php/tarball/master | tar xzv 117 | 118 | (or) 119 | 120 | $ wget https://github.com/pili-engineering/pili-sdk-php/tarball/master -O - | tar xzv 121 | ``` 122 | 123 | And include it in your scripts: 124 | 125 | ```php 126 | require_once '/path/to/pili-sdk-php/lib/Pili.php'; 127 | ``` 128 | 129 | 130 | ## Usage 131 | 132 | ### Configuration 133 | 134 | ```php 135 | // Replace with your keys here 136 | define('ACCESS_KEY', 'Qiniu_AccessKey'); 137 | define('SECRET_KEY', 'Qiniu_SecretKey'); 138 | 139 | // Replace with your hub name 140 | define('HUB', 'Pili_Hub_Name'); // The Hub must be exists before use 141 | 142 | // Change API host as necessary 143 | // 144 | // pili.qiniuapi.com as default 145 | // pili-lte.qiniuapi.com is the latest RC version 146 | // 147 | // $cfg = \Pili\Config::getInstance(); 148 | // $cfg->API_HOST = 'pili.qiniuapi.com'; // default 149 | ``` 150 | 151 | 152 | ### Hub 153 | 154 | #### Instantiate a Pili Hub object 155 | 156 | ```php 157 | // Instantiate an Hub object 158 | $credentials = new \Qiniu\Credentials(ACCESS_KEY, SECRET_KEY); #=> Credentials Object 159 | $hub = new \Pili\Hub($credentials, HUB); # => Hub Object 160 | ``` 161 | 162 | 163 | #### Create a new Stream 164 | 165 | ```php 166 | try { 167 | 168 | $title = NULL; // optional, auto-generated as default 169 | $publishKey = NULL; // optional, auto-generated as default 170 | $publishSecurity = NULL; // optional, can be "dynamic" or "static", "dynamic" as default 171 | 172 | $stream = $hub->createStream($title, $publishKey, $publishSecurity); # => Stream Object 173 | 174 | echo "createStream() =>\n"; 175 | var_export($stream); 176 | echo "\n\n"; 177 | 178 | } catch (Exception $e) { 179 | echo 'createStream() failed. Caught exception: ', $e->getMessage(), "\n"; 180 | } 181 | /* 182 | Pili\Stream::__set_state(array( 183 | '_data' => 184 | array ( 185 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 186 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 187 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 188 | 'title' => '55d7a219e3ba5723280000b5', 189 | 'hub' => 'coding', 190 | 'disabled' => false, 191 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 192 | "publishSecurity":"dynamic", 193 | 'hosts' => 194 | array ( 195 | 'publish' => 196 | array ( 197 | 'rtmp' => 'pili-publish.example.com', 198 | ), 199 | 'live' => 200 | array ( 201 | 'rtmp' => 'pili-live-rtmp.example.com', 202 | 'hls' => 'pili-live-hls.example.com', 203 | 'hdl' => 'pili-live-hdl.example.com', 204 | ), 205 | 'playback' => 206 | array ( 207 | 'hls' => 'pili-playback.example.com', 208 | ), 209 | ), 210 | ), 211 | )) 212 | */ 213 | ``` 214 | 215 | 216 | #### Get a Stream 217 | 218 | ```php 219 | try { 220 | 221 | $streamId = $stream->id; 222 | 223 | $stream = $hub->getStream($streamId); # => Stream Object 224 | 225 | echo "getStream() =>\n"; 226 | var_export($stream); 227 | echo "\n\n"; 228 | 229 | } catch (Exception $e) { 230 | echo "getStream() failed. Caught exception: ", $e->getMessage(), "\n"; 231 | } 232 | /* 233 | Pili\Stream::__set_state(array( 234 | '_data' => 235 | array ( 236 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 237 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 238 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 239 | 'title' => '55d7a219e3ba5723280000b5', 240 | 'hub' => 'coding', 241 | 'disabled' => false, 242 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 243 | "publishSecurity":"dynamic", 244 | 'hosts' => 245 | array ( 246 | 'publish' => 247 | array ( 248 | 'rtmp' => 'pili-publish.example.com', 249 | ), 250 | 'live' => 251 | array ( 252 | 'rtmp' => 'pili-live-rtmp.example.com', 253 | 'hls' => 'pili-live-hls.example.com', 254 | 'hdl' => 'pili-live-hdl.example.com', 255 | ), 256 | 'playback' => 257 | array ( 258 | 'hls' => 'pili-playback.example.com', 259 | ), 260 | ), 261 | ), 262 | )) 263 | */ 264 | ``` 265 | 266 | 267 | #### List Streams 268 | 269 | ```php 270 | try { 271 | 272 | $marker = NULL; // optional 273 | $limit = NULL; // optional 274 | $title_prefix = NULL; // optional 275 | $status = NULL; // optional, "connected" only 276 | 277 | $result = $hub->listStreams($marker, $limit, $title_prefix, $status); # => Array 278 | 279 | echo "listStreams() =>\n"; 280 | var_export($result); 281 | echo "\n\n"; 282 | 283 | } catch (Exception $e) { 284 | echo "listStreams() failed. Caught exception: ", $e->getMessage(), "\n"; 285 | } 286 | /* 287 | array ( 288 | 'marker' => '2', 289 | 'end' => true, 290 | 'items' => 291 | array ( 292 | 0 => Stream Object, 293 | 1 => Stream Object, 294 | ) 295 | ) 296 | */ 297 | ``` 298 | 299 | 300 | ### Stream 301 | 302 | #### To JSON string 303 | 304 | ```php 305 | $result = $stream->toJSONString(); # => string 306 | echo "Stream toJSONString() =>\n"; 307 | var_export($result); 308 | echo "\n\n"; 309 | /* 310 | '{ 311 | "id":"z1.coding.55d7a219e3ba5723280000b5", 312 | "createdAt":"2015-08-21T18:11:37.057-04:00", 313 | "updatedAt":"2015-08-21T18:30:32.548-04:00", 314 | "title":"55d7a219e3ba5723280000b5", 315 | "hub":"coding", 316 | "disabled":false, 317 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 318 | "publishSecurity":"dynamic", 319 | "hosts":{ 320 | "publish":{"rtmp":"pili-publish.example.com"}, 321 | "live":{ 322 | "rtmp":"pili-live-rtmp.example.com", 323 | "hls":"pili-live-hls.example.com", 324 | "hdl":"pili-live-hdl.example.com" 325 | }, 326 | "playback":{ 327 | "hls":"pili-playback.example.com" 328 | } 329 | } 330 | }' 331 | */ 332 | ``` 333 | 334 | 335 | ### Update a Stream 336 | 337 | ```php 338 | try { 339 | 340 | $stream->publishKey = 'new_secret_words'; // optional 341 | $stream->publishSecurity = 'static'; // optional, can be "dynamic" or "static" 342 | $stream->disabled = NULL; // optional, can be "true" of "false" 343 | 344 | $stream = $stream->update(); # => Stream Object 345 | 346 | echo "Stream update() =>\n"; 347 | var_export($stream); 348 | echo "\n\n"; 349 | 350 | } catch (Exception $e) { 351 | echo "Stream update() failed. Caught exception: ", $e->getMessage(), "\n"; 352 | } 353 | /* 354 | Pili\Stream::__set_state(array( 355 | '_data' => 356 | array ( 357 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 358 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 359 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 360 | 'title' => '55d7a219e3ba5723280000b5', 361 | 'hub' => 'coding', 362 | 'disabled' => false, 363 | 'publishKey' => 'new_secret_words', 364 | 'publishSecurity' => 'static', 365 | 'hosts' => 366 | array ( 367 | 'publish' => 368 | array ( 369 | 'rtmp' => 'pili-publish.example.com', 370 | ), 371 | 'live' => 372 | array ( 373 | 'rtmp' => 'pili-live-rtmp.example.com', 374 | 'hls' => 'pili-live-hls.example.com', 375 | 'hdl' => 'pili-live-hdl.example.com', 376 | ), 377 | 'playback' => 378 | array ( 379 | 'hls' => 'pili-playback.example.com', 380 | ), 381 | ), 382 | ), 383 | )) 384 | */ 385 | ``` 386 | 387 | 388 | #### Disable a Stream 389 | 390 | ```php 391 | $disabledTill = time() + 10; # disabled in 10s from now 392 | $result = $stream->disable($disabledTill); # => NULL 393 | echo "Stream disable() =>\n"; 394 | var_export($result); 395 | echo "\n\n"; 396 | /* 397 | true 398 | */ 399 | ``` 400 | 401 | 402 | #### Enable a Stream 403 | 404 | ```php 405 | $result = $stream->enable(); # => NULL 406 | echo "Stream enable() =>\n"; 407 | var_export($result); 408 | echo "\n\n"; 409 | /* 410 | false 411 | */ 412 | ``` 413 | 414 | 415 | #### Get Stream status 416 | 417 | ```php 418 | try { 419 | 420 | $result = $stream->status(); # => Array 421 | 422 | echo "Stream status() =>\n"; 423 | var_export($result); 424 | echo "\n\n"; 425 | 426 | } catch (Exception $e) { 427 | echo "Stream status() failed. Caught exception: ", $e->getMessage(), "\n"; 428 | } 429 | /* 430 | array ( 431 | "reqId" => "YmMxOTcuAAASDc1n", 432 | "hub" => "coding", 433 | "stream" => "2b20838cdb214448b7c7eef46abf1a0a", 434 | "startFrom" => "2015-12-03T12:24:30.226Z", 435 | 'addr' => '222.73.202.226:2572', 436 | 'status' => 'connected', 437 | 'bytesPerSecond' => 16870.200000000001, 438 | 'framesPerSecond' => 439 | array ( 440 | 'audio' => 42.200000000000003, 441 | 'video' => 14.733333333333333, 442 | 'data' => 0.066666666666666666, 443 | ), 444 | ) 445 | */ 446 | ``` 447 | 448 | 449 | #### Generate RTMP publish URL 450 | 451 | ```php 452 | $publishUrl = $stream->rtmpPublishUrl(); 453 | echo "Stream rtmpPublishUrl() =>\n"; 454 | echo $publishUrl; 455 | echo "\n\n"; 456 | /* 457 | rtmp://pili-publish.example.com/coding/55d7a219e3ba5723280000b5?key=new_secret_words 458 | */ 459 | ``` 460 | 461 | 462 | #### Generate RTMP live play URLs 463 | 464 | ```php 465 | $urls = $stream->rtmpLiveUrls(); 466 | echo "Stream rtmpLiveUrls() =>\n"; 467 | var_export($urls); 468 | echo "\n\n"; 469 | /* 470 | array ( 471 | 'ORIGIN' => 'rtmp://pili-live-rtmp.example.com/coding/55d7a219e3ba5723280000b5', 472 | ) 473 | */ 474 | ``` 475 | 476 | 477 | #### Generate HLS play live URLs 478 | 479 | ```php 480 | $urls = $stream->hlsLiveUrls(); 481 | echo "Stream hlsLiveUrls() =>\n"; 482 | var_export($urls); 483 | echo "\n\n"; 484 | /* 485 | array ( 486 | 'ORIGIN' => 'http://pili-live-hls.example.com/coding/55d7a219e3ba5723280000b5.m3u8', 487 | ) 488 | */ 489 | ``` 490 | 491 | 492 | #### Generate Http-Flv live play URLs 493 | 494 | ```php 495 | $urls = $stream->httpFlvLiveUrls(); 496 | echo "Stream httpFlvLiveUrls() =>\n"; 497 | var_export($urls); 498 | echo "\n\n"; 499 | /* 500 | array ( 501 | 'ORIGIN' => 'http://pili-live-hdl.example.com/coding/55d7a219e3ba5723280000b5.flv', 502 | ) 503 | */ 504 | ``` 505 | 506 | 507 | #### Get Stream segments 508 | 509 | ```php 510 | try { 511 | 512 | $start = NULL; // optional, in second, unix timestamp 513 | $end = NULL; // optional, in second, unix timestamp 514 | $limit = NULL; // optional, uint 515 | 516 | $result = $stream->segments($start, $end, $limit); # => Array 517 | 518 | echo "Stream segments() =>\n"; 519 | var_export($result); 520 | echo "\n\n"; 521 | 522 | } catch (Exception $e) { 523 | echo "Stream segments() failed. Caught exception: ", $e->getMessage(), "\n"; 524 | } 525 | /* 526 | array ( 527 | 'start' => 1440196065, 528 | 'end' => 1440198092, 529 | 'segments' => 530 | array ( 531 | 0 => 532 | array ( 533 | 'start' => 1440196065, 534 | 'end' => 1440196124, 535 | ), 536 | 1 => 537 | array ( 538 | 'start' => 1440198072, 539 | 'end' => 1440198092, 540 | ), 541 | ), 542 | ) 543 | */ 544 | ``` 545 | 546 | 547 | #### Generate HLS playback URLs 548 | 549 | ```php 550 | $start = 1440196065; // optional, in second, unix timestamp 551 | $end = 1440196105; // optional, in second, unix timestamp 552 | 553 | $urls = $stream->hlsPlaybackUrls($start, $end); 554 | echo "Stream hlsPlaybackUrls() =>\n"; 555 | var_export($urls); 556 | echo "\n\n"; 557 | /* 558 | array ( 559 | 'ORIGIN' => 'http://pili-playback.example.com/coding/55d7a219e3ba5723280000b5.m3u8?start=-1&end=-1', 560 | ) 561 | */ 562 | ``` 563 | 564 | 565 | #### Save Stream as a file 566 | 567 | ```php 568 | try { 569 | 570 | $name = 'videoName.mp4'; // required 571 | $format = NULL; // optional 572 | $start = -1; // optional, in second, unix timestamp 573 | $end = -1; // optional, in second, unix timestamp 574 | $notifyUrl = NULL; // optional 575 | $pipeline = NULL; // optional 576 | 577 | $result = $stream->saveAs($name, $format, $start, $end, $notifyUrl, $pipeline); # => Array 578 | 579 | echo "Stream saveAs() =>\n"; 580 | var_export($result); 581 | echo "\n\n"; 582 | 583 | } catch (Exception $e) { 584 | echo "Stream saveAs() failed. Caught exception: ", $e->getMessage(), "\n"; 585 | } 586 | /* 587 | array ( 588 | 'url' => 'http://pili-media.example.com/recordings/z1.coding.55d7a219e3ba5723280000b5/videoName.m3u8', 589 | 'targetUrl' => 'http://pili-vod.example.com/recordings/z1.coding.55d7a219e3ba5723280000b5/videoName.mp4', 590 | 'persistentId' => 'z1.55d7a6e77823de5a49a8899b', 591 | ) 592 | */ 593 | ``` 594 | 595 | 596 | While invoking `saveAs()` and `snapshot()`, you can get processing state via Qiniu FOP Service using `persistentId`. 597 | API: `curl -D GET http://api.qiniu.com/status/get/prefop?id={PersistentId}` 598 | Doc reference: 599 | 600 | 601 | #### Snapshot Stream 602 | 603 | ```php 604 | try { 605 | 606 | $name = 'imageName.jpg'; // required 607 | $format = 'jpg'; // required 608 | $time = NULL; // optional, in second, unix timestamp 609 | $notifyUrl = NULL; // optional 610 | $pipeline = NULL; // optional 611 | 612 | $result = $stream->snapshot($name, $format, $time, $notifyUrl, $pipeline); # => Array 613 | 614 | echo "Stream snapshot() =>\n"; 615 | var_export($result); 616 | echo "\n\n"; 617 | 618 | } catch (Exception $e) { 619 | echo "Stream snapshot() failed. Caught exception: ", $e->getMessage(), "\n"; 620 | } 621 | /* 622 | array ( 623 | 'targetUrl' => 'http://pili-static.example.com/snapshots/z1.coding.55d7a219e3ba5723280000b5/imageName.jpg', 624 | 'persistentId' => 'z1.55d7a6e77823de5a49a8899a', 625 | ) 626 | */ 627 | ``` 628 | 629 | 630 | #### Delete a Stream 631 | 632 | ```php 633 | try { 634 | $result = $stream->delete(); # => NULL 635 | echo "Stream delete() =>\n"; 636 | var_dump($result); 637 | echo "\n\n"; 638 | } catch (Exception $e) { 639 | echo "Stream delete() failed. Caught exception: ", $e->getMessage(), "\n"; 640 | } 641 | /* 642 | NULL 643 | */ 644 | ``` 645 | 646 | 647 | ## History 648 | 649 | - 1.5.4 650 | - Use $stream->saveAs in $stream->hlsPlaybackUrls 651 | 652 | - 1.5.3 653 | - Update $stream->disable($disabledTill) 654 | 655 | - 1.5.2 656 | - Update $stream->rtmpPublishUrl() 657 | 658 | - 1.5.1 659 | - Update API 660 | - $hub->listStreams($marker=NULL, $limit=NULL, $title_prefix=NULL, $status=NULL) 661 | - $stream->saveAs($name, $format=NULL, $start=NULL, $end=NULL, $notifyUrl=NULL, $pipeline=NULL) 662 | - $stream->snapshot($name, $format, $time=NULL, $notifyUrl=NULL, $pipeline=NULL) 663 | - $stream->hlsPlaybackUrls($start=-1, $end=-1) 664 | - 1.5.0 665 | - Add Credentials and Transport class 666 | - Renamed $client to $hub 667 | - 1.4.0 668 | - Add Stream Create,Get,List 669 | - $hub->createStream() 670 | - $hub->getStream() 671 | - $hub->listStreams() 672 | - Add Stream operations else 673 | - $stream->toJSONString() 674 | - $stream->update() 675 | - $stream->disable() 676 | - $stream->enable() 677 | - $stream->status() 678 | - $stream->segments() 679 | - $stream->rtmpPublishUrl() 680 | - $stream->rtmpLiveUrls() 681 | - $stream->hlsLiveUrls() 682 | - $stream->httpFlvLiveUrls() 683 | - $stream->hlsPlaybackUrls() 684 | - $stream->snapshot() 685 | - $stream->saveAs() 686 | - $stream->delete() 687 | -------------------------------------------------------------------------------- /README_zh-CN-PHP.md: -------------------------------------------------------------------------------- 1 | # PILI直播 PHP服务端SDK 使用指南 2 | 3 | ## 功能列表 4 | 5 | - 直播流的创建、获取和列举 6 | - [x] hub.createStream() // 创建流 7 | - [x] hub.getStream() // 获取流 8 | - [x] hub.listStreams() // 列举流 9 | - 直播流的其他功能 10 | - [x] stream.toJsonString() // 流信息转为json 11 | - [x] stream.update() // 更新流 12 | - [x] stream.disable() // 禁用流 13 | - [x] stream.enable() // 启用流 14 | - [x] stream.status() // 获取流状态 15 | - [x] stream.rtmpPublishUrl() // 生成推流地址 16 | - [x] stream.rtmpLiveUrls() // 生成rtmp播放地址 17 | - [x] stream.hlsLiveUrls() // 生成hls播放地址 18 | - [x] stream.httpFlvLiveUrls() // 生成flv播放地址 19 | - [x] stream.segments() // 获取流片段 20 | - [x] stream.hlsPlaybackUrls() // 生成hls回看地址 21 | - [x] stream.saveAs() // 流另存为文件 22 | - [x] stream.snapshot() // 获取快照 23 | - [x] stream.delete() // 删除流 24 | 25 | 26 | ## 目录 27 | 28 | - [安装](#installation) 29 | - [用法](#usage) 30 | - [配置](#configuration) 31 | - [Hub](#hub) 32 | - [实例化hub对象](#instantiate-a-pili-hub-object) 33 | - [创建流](#create-a-new-stream) 34 | - [获取流](#get-an-exist-stream) 35 | - [列举流](#list-streams) 36 | - [直播流](#stream) 37 | - [流信息转为json](#to-json-string) 38 | - [更新流](#update-a-stream) 39 | - [禁用流](#disable-a-stream) 40 | - [启用流](#enable-a-stream) 41 | - [获取流状态](#get-stream-status) 42 | - [生成推流地址](#generate-rtmp-publish-url) 43 | - [生成rtmp播放地址](#generate-rtmp-live-play-urls) 44 | - [生成hls播放地址](#generate-hls-play-urls) 45 | - [生成flv播放地址](#generate-http-flv-live-play-urls) 46 | - [获取流片段](#get-stream-segments) 47 | - [生成hls回看地址](#generate-hls-playback-urls) 48 | - [流另存为文件](#save-stream-as-a-file) 49 | - [获取快照](#snapshot-stream) 50 | - [删除流](#delete-a-stream) 51 | - [History](#history) 52 | 53 | 54 | 55 | ## 安装 56 | 57 | ### 使用要求 58 | 59 | - PHP >= 5.3.0 60 | 61 | ### 使用Composer安装 62 | 63 | 如果你需要使用[Composer](http://getcomposer.org) 来管理依赖, 你可以使用Composer来添加 pili-sdk-php. 64 | 65 | ```bash 66 | # 安装Composer 67 | curl -sS https://getcomposer.org/installer | php 68 | ``` 69 | 70 | 使用 Composer 获取最新版本的pili-sdk-php : 71 | 72 | ```bash 73 | php composer.phar require pili-engineering/pili-sdk-php:dev-master 74 | ``` 75 | 76 | 或者, 你可以在你项目中的`composer.json`里面指定pili-sdk-php为依赖包 : 77 | 78 | ```js 79 | { 80 | "require": { 81 | "pili-engineering/pili-sdk-php": "dev-msater" 82 | } 83 | } 84 | ``` 85 | 86 | 安装之后, 你代码中 require Composer生成的 autoloader: 87 | 88 | ```php 89 | require 'vendor/autoload.php'; 90 | ``` 91 | 92 | 如果需要更详细的关于 Composer 的使用说明,你可以访问 Composer 的官方网站http://getcomposer.org/,或对应的中文网站 http://www.phpcomposer.com/。 93 | 94 | ### 通过GitHub使用源码安装 95 | 96 | `pili-sdk-php` 需要 PHP `v5.3+`,下载php-sdk的源码,然后像下面介绍的这样导入: 97 | 98 | 安装源码: 99 | 100 | ```bash 101 | $ git clone https://github.com/pili-engineering/pili-sdk-php.git 102 | ``` 103 | 104 | 导入到你的脚本中: 105 | 106 | ```php 107 | require_once '/path/to/pili-sdk-php/lib/Pili.php'; 108 | ``` 109 | 110 | ### 通过zip/tarball安装源码 111 | 112 | 或者,直接这里获取: [tarball](https://github.com/pili-engineering/pili-sdk-php/tarball/master) or [zipball](https://github.com/pili-engineering/pili-sdk-php/zipball/master): 113 | 114 | ```bash 115 | $ curl -L https://github.com/pili-engineering/pili-sdk-php/tarball/master | tar xzv 116 | 117 | (or) 118 | 119 | $ wget https://github.com/pili-engineering/pili-sdk-php/tarball/master -O - | tar xzv 120 | ``` 121 | 122 | 导入到你的脚本中: 123 | 124 | ```php 125 | require_once '/path/to/pili-sdk-php/lib/Pili.php'; 126 | ``` 127 | 128 | 129 | 130 | ## 用法: 131 | 132 | 133 | ### 配置 134 | 135 | ```php 136 | // Replace with your keys here 137 | define('ACCESS_KEY', 'Qiniu_AccessKey'); 138 | define('SECRET_KEY', 'Qiniu_SecretKey'); 139 | 140 | // Replace with your hub name 141 | define('HUB', 'Pili_Hub_Name'); // 使用前必须需要先要获得HUB 142 | 143 | # 如有需要可以更改API host 144 | # 145 | # 默认为 pili.qiniuapi.com 146 | # pili-lte.qiniuapi.com 为最近更新版本 147 | # 148 | # conf.API_HOST = 'pili.qiniuapi.com' # 默认 149 | ``` 150 | 151 | 152 | ### Hub 153 | 154 | 155 | #### 实例化hub对象 156 | 157 | ```php 158 | // Instantiate an Hub object 159 | $credentials = new \Qiniu\Credentials(ACCESS_KEY, SECRET_KEY); #=> Credentials Object 160 | $hub = new \Pili\Hub($credentials, HUB); # => Hub Object 161 | ``` 162 | 163 | 164 | 165 | #### 创建流 166 | 167 | ```php 168 | try { 169 | 170 | $title = NULL; // 选填,默认自动生成 171 | $publishKey = NULL; // 选填,默认自动生成 172 | $publishSecurity = NULL; // 选填, 可以为 "dynamic" 或 "static", 默认为 "dynamic" 173 | 174 | $stream = $hub->createStream($title, $publishKey, $publishSecurity); # => Stream Object 175 | 176 | echo "createStream() =>\n"; 177 | var_export($stream); 178 | echo "\n\n"; 179 | 180 | /* 181 | echo $stream->id; 182 | echo $stream->createdAt; 183 | echo $stream->updatedAt; 184 | echo $stream->title; 185 | echo $stream->hub; 186 | echo $stream->disabled; 187 | echo $stream->publishKey; 188 | echo $stream->publishSecurity; 189 | echo $stream->hosts; 190 | echo $stream->hosts["publish"]["rtmp"]; 191 | echo $stream->hosts["live"]["rtmp"]; 192 | echo $stream->hosts["live"]["http"]; 193 | echo $stream->hosts["playback"]["http"]; 194 | */ 195 | 196 | } catch (Exception $e) { 197 | echo 'createStream() failed. Caught exception: ', $e->getMessage(), "\n"; 198 | } 199 | /* 200 | Pili\Stream::__set_state(array( 201 | '_auth' => 202 | Pili\Auth::__set_state(array( 203 | '_accessKey' => '74kG54cpbbkbhTMhnauZLsJObodYXecvlyUnL3AL', 204 | '_secretKey' => 'gRgMaR7aGmyVrrkkXDVM19zlVq2K2v1ezufRtCpI', 205 | )), 206 | '_data' => 207 | array ( 208 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 209 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 210 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 211 | 'title' => '55d7a219e3ba5723280000b5', 212 | 'hub' => 'coding', 213 | 'disabled' => false, 214 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 215 | "publishSecurity":"dynamic", 216 | 'hosts' => 217 | array ( 218 | 'publish' => 219 | array ( 220 | 'rtmp' => 'iuel7l.publish.z1.pili.qiniup.com', 221 | ), 222 | 'live' => 223 | array ( 224 | 'http' => 'iuel7l.live1-http.z1.pili.qiniucdn.com', 225 | 'rtmp' => 'iuel7l.live1-rtmp.z1.pili.qiniucdn.com', 226 | ), 227 | 'playback' => 228 | array ( 229 | 'http' => 'iuel7l.playback1.z1.pili.qiniucdn.com', 230 | ), 231 | ), 232 | ), 233 | )) 234 | */ 235 | ``` 236 | 237 | 238 | #### 获取流 239 | 240 | ```php 241 | try { 242 | 243 | $streamId = $stream->id; 244 | 245 | $stream = $hub->getStream($streamId); # => Stream Object 246 | 247 | echo "getStream() =>\n"; 248 | var_export($stream); 249 | echo "\n\n"; 250 | 251 | } catch (Exception $e) { 252 | echo "getStream() failed. Caught exception: ", $e->getMessage(), "\n"; 253 | } 254 | /* 255 | Pili\Stream::__set_state(array( 256 | '_auth' => 257 | Pili\Auth::__set_state(array( 258 | '_accessKey' => '74kG54cpbbkbhTMhnauZLsJObodYXecvlyUnL3AL', 259 | '_secretKey' => 'gRgMaR7aGmyVrrkkXDVM19zlVq2K2v1ezufRtCpI', 260 | )), 261 | '_data' => 262 | array ( 263 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 264 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 265 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 266 | 'title' => '55d7a219e3ba5723280000b5', 267 | 'hub' => 'coding', 268 | 'disabled' => false, 269 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 270 | "publishSecurity":"dynamic", 271 | 'hosts' => 272 | array ( 273 | 'publish' => 274 | array ( 275 | 'rtmp' => 'iuel7l.publish.z1.pili.qiniup.com', 276 | ), 277 | 'live' => 278 | array ( 279 | 'http' => 'iuel7l.live1-http.z1.pili.qiniucdn.com', 280 | 'rtmp' => 'iuel7l.live1-rtmp.z1.pili.qiniucdn.com', 281 | ), 282 | 'playback' => 283 | array ( 284 | 'http' => 'iuel7l.playback1.z1.pili.qiniucdn.com', 285 | ), 286 | ), 287 | ), 288 | )) 289 | */ 290 | ``` 291 | 292 | 293 | 294 | #### 列举流 295 | 296 | ```php 297 | try { 298 | 299 | $marker = NULL; // 可选 300 | $limit = NULL; // 可选 301 | $title_prefix = NULL; // 可选 302 | 303 | $result = $hub->listStreams($marker, $limit, $title_prefix); # => Array 304 | 305 | echo "listStreams() =>\n"; 306 | var_export($result); 307 | echo "\n\n"; 308 | 309 | } catch (Exception $e) { 310 | echo "listStreams() failed. Caught exception: ", $e->getMessage(), "\n"; 311 | } 312 | /* 313 | array ( 314 | 'marker' => '2', 315 | 'items' => 316 | array ( 317 | 0 => Stream Object, 318 | 1 => Stream Object, 319 | ) 320 | */ 321 | ``` 322 | 323 | 324 | 325 | ### 直播流 326 | 327 | 328 | #### 流信息转为json 329 | 330 | ```php 331 | $result = $stream->toJSONString(); # => string 332 | echo "Stream toJSONString() =>\n"; 333 | var_export($result); 334 | echo "\n\n"; 335 | /* 336 | '{ 337 | "id":"z1.coding.55d7a219e3ba5723280000b5", 338 | "createdAt":"2015-08-21T18:11:37.057-04:00", 339 | "updatedAt":"2015-08-21T18:30:32.548-04:00", 340 | "title":"55d7a219e3ba5723280000b5", 341 | "hub":"coding", 342 | "disabled":false, 343 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 344 | "publishSecurity":"dynamic", 345 | "hosts":{ 346 | "publish":{"rtmp":"iuel7l.publish.z1.pili.qiniup.com"}, 347 | "live":{ 348 | "http":"iuel7l.live1-http.z1.pili.qiniucdn.com", 349 | "rtmp":"iuel7l.live1-rtmp.z1.pili.qiniucdn.com" 350 | }, 351 | "playback":{ 352 | "http":"iuel7l.playback1.z1.pili.qiniucdn.com" 353 | } 354 | } 355 | }' 356 | */ 357 | ``` 358 | 359 | 360 | 361 | #### 更新流 362 | 363 | ```php 364 | try { 365 | 366 | $stream->publishKey = 'new_secret_words'; // 选填 367 | $stream->publishSecurity = 'static'; // 选填, 可以为 "dynamic" 或 "static", 默认为 "dynamic" 368 | $stream->disabled = NULL; // 选填, 可以为 "true" 或 "false" 369 | 370 | $stream = $stream->update(); # => Stream Object 371 | 372 | echo "Stream update() =>\n"; 373 | var_export($stream); 374 | echo "\n\n"; 375 | 376 | } catch (Exception $e) { 377 | echo "Stream update() failed. Caught exception: ", $e->getMessage(), "\n"; 378 | } 379 | /* 380 | Pili\Stream::__set_state(array( 381 | '_auth' => 382 | Pili\Auth::__set_state(array( 383 | '_accessKey' => '74kG54cpbbkbhTMhnauZLsJObodYXecvlyUnL3AL', 384 | '_secretKey' => 'gRgMaR7aGmyVrrkkXDVM19zlVq2K2v1ezufRtCpI', 385 | )), 386 | '_data' => 387 | array ( 388 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 389 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 390 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 391 | 'title' => '55d7a219e3ba5723280000b5', 392 | 'hub' => 'coding', 393 | 'disabled' => false, 394 | 'publishKey' => 'new_secret_words', 395 | 'publishSecurity' => 'static', 396 | 'hosts' => 397 | array ( 398 | 'publish' => 399 | array ( 400 | 'rtmp' => 'iuel7l.publish.z1.pili.qiniup.com', 401 | ), 402 | 'live' => 403 | array ( 404 | 'http' => 'iuel7l.live1-http.z1.pili.qiniucdn.com', 405 | 'rtmp' => 'iuel7l.live1-rtmp.z1.pili.qiniucdn.com', 406 | ), 407 | 'playback' => 408 | array ( 409 | 'http' => 'iuel7l.playback1.z1.pili.qiniucdn.com', 410 | ), 411 | ), 412 | ), 413 | )) 414 | */ 415 | ``` 416 | 417 | 418 | 419 | #### 禁用流 420 | 421 | ```php 422 | $stream = $stream->disable(); # => Stream Object 423 | echo "Stream disable() =>\n"; 424 | var_export($stream->disabled); 425 | echo "\n\n"; 426 | /* 427 | true 428 | */ 429 | ``` 430 | 431 | 432 | 433 | #### 启用流 434 | 435 | ```php 436 | $stream = $stream->enable(); # => Stream Object 437 | echo "Stream enable() =>\n"; 438 | var_export($stream->disabled); 439 | echo "\n\n"; 440 | /* 441 | false 442 | */ 443 | ``` 444 | 445 | 446 | 447 | #### 获取流状态 448 | 449 | ```php 450 | try { 451 | 452 | $result = $stream->status(); # => Array 453 | 454 | echo "Stream status() =>\n"; 455 | var_export($result); 456 | echo "\n\n"; 457 | 458 | } catch (Exception $e) { 459 | echo "Stream status() failed. Caught exception: ", $e->getMessage(), "\n"; 460 | } 461 | /* 462 | array ( 463 | 'addr' => '222.73.202.226:2572', 464 | 'status' => 'connected', 465 | 'bytesPerSecond' => 16870.200000000001, 466 | 'framesPerSecond' => 467 | array ( 468 | 'audio' => 42.200000000000003, 469 | 'video' => 14.733333333333333, 470 | 'data' => 0.066666666666666666, 471 | ), 472 | ) 473 | */ 474 | ``` 475 | 476 | 477 | 478 | #### 生成推流地址 479 | 480 | ```php 481 | $publishUrl = $stream->rtmpPublishUrl(); 482 | echo "Stream rtmpPublishUrl() =>\n"; 483 | echo $publishUrl; 484 | echo "\n\n"; 485 | /* 486 | rtmp://iuel7l.publish.z1.pili.qiniup.com/coding/55d7a219e3ba5723280000b5?key=new_secret_words 487 | */ 488 | ``` 489 | 490 | 491 | 492 | #### 生成rtmp播放地址 493 | 494 | ```php 495 | $urls = $stream->rtmpLiveUrls(); 496 | echo "Stream rtmpLiveUrls() =>\n"; 497 | var_export($urls); 498 | echo "\n\n"; 499 | /* 500 | array ( 501 | 'ORIGIN' => 'rtmp://iuel7l.live1-rtmp.z1.pili.qiniucdn.com/coding/55d7a219e3ba5723280000b5', 502 | ) 503 | */ 504 | ``` 505 | 506 | 507 | 508 | #### 生成hls播放地址 509 | 510 | ```php 511 | $urls = $stream->hlsLiveUrls(); 512 | echo "Stream hlsLiveUrls() =>\n"; 513 | var_export($urls); 514 | echo "\n\n"; 515 | /* 516 | array ( 517 | 'ORIGIN' => 'http://iuel7l.live1-http.z1.pili.qiniucdn.com/coding/55d7a219e3ba5723280000b5.m3u8', 518 | ) 519 | */ 520 | ``` 521 | 522 | 523 | 524 | #### 生成flv播放地址 525 | 526 | ```php 527 | $urls = $stream->httpFlvLiveUrls(); 528 | echo "Stream httpFlvLiveUrls() =>\n"; 529 | var_export($urls); 530 | echo "\n\n"; 531 | /* 532 | array ( 533 | 'ORIGIN' => 'http://iuel7l.live1-http.z1.pili.qiniucdn.com/coding/55d7a219e3ba5723280000b5.flv', 534 | ) 535 | */ 536 | ``` 537 | 538 | 539 | 540 | #### 获取流片段 541 | 542 | ```php 543 | try { 544 | 545 | $start = NULL; // 选填, 单位为秒, 为UNIX时间戳 546 | $end = NULL; // 选填, 单位为秒, 为UNIX时间戳 547 | $limit = NULL; // 选填, uint 548 | 549 | $result = $stream->segments($start, $end, $limit); # => Array 550 | 551 | echo "Stream segments() =>\n"; 552 | var_export($result); 553 | echo "\n\n"; 554 | 555 | } catch (Exception $e) { 556 | echo "Stream segments() failed. Caught exception: ", $e->getMessage(), "\n"; 557 | } 558 | /* 559 | array ( 560 | 'segments' => 561 | array ( 562 | 0 => 563 | array ( 564 | 'start' => 1440196065, 565 | 'end' => 1440196124, 566 | ), 567 | 1 => 568 | array ( 569 | 'start' => 1440198072, 570 | 'end' => 1440198092, 571 | ), 572 | ), 573 | ) 574 | */ 575 | ``` 576 | 577 | 578 | 579 | #### 生成hls回看地址 580 | 581 | ```php 582 | $start = 1440196065; // 必填, 单位为秒, 为UNIX时间戳 583 | $end = 1440196105; // 必填, 单位为秒, 为UNIX时间戳 584 | 585 | $urls = $stream->hlsPlaybackUrls($start, $end); 586 | echo "Stream hlsPlaybackUrls() =>\n"; 587 | var_export($urls); 588 | echo "\n\n"; 589 | /* 590 | array ( 591 | 'ORIGIN' => 'http://iuel7l.playback1.z1.pili.qiniucdn.com/coding/55d7a219e3ba5723280000b5.m3u8?start=1440196065&end=1440196105', 592 | ) 593 | */ 594 | ``` 595 | 596 | 597 | 598 | #### 流另存为文件 599 | 600 | ```php 601 | try { 602 | 603 | $name = 'videoName.mp4'; // 必填 604 | $format = 'mp4'; // 必填 605 | $start = 1440196065; // 必填, 单位为秒, 为UNIX时间戳 606 | $end = 1440196105; // 必填, 单位为秒, 为UNIX时间戳 607 | $notifyUrl = NULL; // 选填 608 | 609 | $result = $stream->saveAs($name, $format, $start, $end, $notifyUrl = NULL); # => Array 610 | 611 | echo "Stream saveAs() =>\n"; 612 | var_export($result); 613 | echo "\n\n"; 614 | 615 | } catch (Exception $e) { 616 | echo "Stream saveAs() failed. Caught exception: ", $e->getMessage(), "\n"; 617 | } 618 | /* 619 | array ( 620 | 'url' => 'http://iuel7l.media1.z1.pili.qiniucdn.com/recordings/z1.coding.55d7a219e3ba5723280000b5/videoName.m3u8', 621 | 'targetUrl' => 'http://iuel7l.vod1.z1.pili.qiniucdn.com/recordings/z1.coding.55d7a219e3ba5723280000b5/videoName.mp4', 622 | 'persistentId' => 'z1.55d7a6e77823de5a49a8899b', 623 | ) 624 | */ 625 | ``` 626 | 627 | 628 | 当使用 `saveAs()` 和 `snapshot()` 的时候, 由于是异步处理, 你可以在七牛的FOP接口上使用 `persistentId`来获取处理进度.参考如下: 629 | API: `curl -D GET http://api.qiniu.com/status/get/prefop?id={persistentId}` 630 | 文档说明: 631 | 632 | 633 | #### 获取快照 634 | 635 | ```php 636 | try { 637 | 638 | $name = 'imageName.jpg'; // 必填 639 | $format = 'jpg'; // 必填 640 | $time = 1440196100; // 选填, 单位为秒, 为UNIX时间戳 641 | $notifyUrl = NULL; // 选填 642 | 643 | $result = $stream->snapshot($name, $format, $time, $notifyUrl); # => Array 644 | 645 | echo "Stream snapshot() =>\n"; 646 | var_export($result); 647 | echo "\n\n"; 648 | 649 | } catch (Exception $e) { 650 | echo "Stream snapshot() failed. Caught exception: ", $e->getMessage(), "\n"; 651 | } 652 | /* 653 | array ( 654 | 'targetUrl' => 'http://iuel7l.static1.z1.pili.qiniucdn.com/snapshots/z1.coding.55d7a219e3ba5723280000b5/imageName.jpg', 655 | 'persistentId' => 'z1.55d7a6e77823de5a49a8899a', 656 | ) 657 | */ 658 | ``` 659 | 660 | 661 | 662 | #### 删除流 663 | 664 | ```php 665 | try { 666 | $result = $stream->delete(); # => NULL 667 | echo "Stream delete() =>\n"; 668 | var_dump($result); 669 | echo "\n\n"; 670 | } catch (Exception $e) { 671 | echo "Stream delete() failed. Caught exception: ", $e->getMessage(), "\n"; 672 | } 673 | /* 674 | NULL 675 | */ 676 | ``` 677 | 678 | 679 | ## History 680 | 681 | - 1.5.0 682 | - Add Credentials and Transport class 683 | - Renamed $client to $hub 684 | - 1.4.0 685 | - Add Stream Create,Get,List 686 | - $hub->createStream() 687 | - $hub->getStream() 688 | - $hub->listStreams() 689 | - Add Stream operations else 690 | - $stream->toJSONString() 691 | - $stream->update() 692 | - $stream->disable() 693 | - $stream->enable() 694 | - $stream->status() 695 | - $stream->segments() 696 | - $stream->rtmpPublishUrl() 697 | - $stream->rtmpLiveUrls() 698 | - $stream->hlsLiveUrls() 699 | - $stream->httpFlvLiveUrls() 700 | - $stream->hlsPlaybackUrls() 701 | - $stream->snapshot() 702 | - $stream->saveAs() 703 | - $stream->delete() 704 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pili-engineering/pili-sdk-php", 3 | "type": "library", 4 | "description": "Pili Streaming Cloud server-side library for PHP.", 5 | "keywords": ["web-service", "rtmp", "hls", "hdl", "hds", "dash", "streaming", "pili", "qiniu", "cloud"], 6 | "homepage": "https://github.com/pili-engineering/pili-sdk-php", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Pili Engineering", 11 | "homepage": "https://github.com/pili-engineering" 12 | } 13 | ], 14 | "support": { 15 | "issues": "https://github.com/pili-engineering/pili-sdk-php/issues" 16 | }, 17 | "require": { 18 | "php": ">=5.3.0" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "~4.0", 22 | "squizlabs/php_codesniffer": "~2.0" 23 | }, 24 | "autoload": { 25 | "psr-0": { 26 | "Pili": "lib/", 27 | "Qiniu": "lib/" 28 | } 29 | }, 30 | "extra": { 31 | "branch-alias": { 32 | "dev-master": "1.5-dev" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/example.php: -------------------------------------------------------------------------------- 1 | API_HOST = 'pili.qiniuapi.com'; // default 22 | 23 | 24 | // Hub 25 | 26 | // Instantiate an Hub object 27 | $credentials = new \Qiniu\Credentials(ACCESS_KEY, SECRET_KEY); #=> Credentials Object 28 | $hub = new \Pili\Hub($credentials, HUB); # => Hub Object 29 | 30 | 31 | // Create a new Stream 32 | try { 33 | 34 | $title = NULL; // optional, auto-generated as default 35 | $publishKey = NULL; // optional, auto-generated as default 36 | $publishSecurity = NULL; // optional, can be "dynamic" or "static", "dynamic" as default 37 | 38 | $stream = $hub->createStream($title, $publishKey, $publishSecurity); # => Stream Object 39 | 40 | echo "createStream() =>\n"; 41 | var_export($stream); 42 | echo "\n\n"; 43 | 44 | } catch (Exception $e) { 45 | echo 'createStream() failed. Caught exception: ', $e->getMessage(), "\n"; 46 | } 47 | /* 48 | Pili\Stream::__set_state(array( 49 | '_data' => 50 | array ( 51 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 52 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 53 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 54 | 'title' => '55d7a219e3ba5723280000b5', 55 | 'hub' => 'coding', 56 | 'disabled' => false, 57 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 58 | "publishSecurity":"dynamic", 59 | 'hosts' => 60 | array ( 61 | 'publish' => 62 | array ( 63 | 'rtmp' => 'pili-publish.example.com', 64 | ), 65 | 'live' => 66 | array ( 67 | 'rtmp' => 'pili-live-rtmp.example.com', 68 | 'hls' => 'pili-live-hls.example.com', 69 | 'hdl' => 'pili-live-hdl.example.com', 70 | ), 71 | 'playback' => 72 | array ( 73 | 'hls' => 'pili-playback.example.com', 74 | ), 75 | ), 76 | ), 77 | )) 78 | */ 79 | 80 | 81 | // Get Stream 82 | try { 83 | 84 | $streamId = $stream->id; 85 | 86 | $stream = $hub->getStream($streamId); # => Stream Object 87 | 88 | echo "getStream() =>\n"; 89 | var_export($stream); 90 | echo "\n\n"; 91 | 92 | } catch (Exception $e) { 93 | echo "getStream() failed. Caught exception: ", $e->getMessage(), "\n"; 94 | } 95 | /* 96 | Pili\Stream::__set_state(array( 97 | '_data' => 98 | array ( 99 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 100 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 101 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 102 | 'title' => '55d7a219e3ba5723280000b5', 103 | 'hub' => 'coding', 104 | 'disabled' => false, 105 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 106 | "publishSecurity":"dynamic", 107 | 'hosts' => 108 | array ( 109 | 'publish' => 110 | array ( 111 | 'rtmp' => 'pili-publish.example.com', 112 | ), 113 | 'live' => 114 | array ( 115 | 'rtmp' => 'pili-live-rtmp.example.com', 116 | 'hls' => 'pili-live-hls.example.com', 117 | 'hdl' => 'pili-live-hdl.example.com', 118 | ), 119 | 'playback' => 120 | array ( 121 | 'hls' => 'pili-playback.example.com', 122 | ), 123 | ), 124 | ), 125 | )) 126 | */ 127 | 128 | 129 | // List streams 130 | try { 131 | 132 | $marker = NULL; // optional 133 | $limit = NULL; // optional 134 | $title_prefix = NULL; // optional 135 | $status = NULL; // optional, "connected" only 136 | 137 | $result = $hub->listStreams($marker, $limit, $title_prefix, $status); # => Array 138 | 139 | echo "listStreams() =>\n"; 140 | var_export($result); 141 | echo "\n\n"; 142 | 143 | } catch (Exception $e) { 144 | echo "listStreams() failed. Caught exception: ", $e->getMessage(), "\n"; 145 | } 146 | /* 147 | array ( 148 | 'marker' => '2', 149 | 'end' => true, 150 | 'items' => 151 | array ( 152 | 0 => Stream Object, 153 | 1 => Stream Object, 154 | ) 155 | ) 156 | */ 157 | 158 | 159 | // Stream 160 | 161 | // To JSON string 162 | $result = $stream->toJSONString(); # => string 163 | echo "Stream toJSONString() =>\n"; 164 | var_export($result); 165 | echo "\n\n"; 166 | /* 167 | '{ 168 | "id":"z1.coding.55d7a219e3ba5723280000b5", 169 | "createdAt":"2015-08-21T18:11:37.057-04:00", 170 | "updatedAt":"2015-08-21T18:30:32.548-04:00", 171 | "title":"55d7a219e3ba5723280000b5", 172 | "hub":"coding", 173 | "disabled":false, 174 | "publishKey":"734de946-11e0-487a-8627-30bf777ed5a3", 175 | "publishSecurity":"dynamic", 176 | "hosts":{ 177 | "publish":{"rtmp":"pili-publish.example.com"}, 178 | "live":{ 179 | "rtmp":"pili-live-rtmp.example.com", 180 | "hls":"pili-live-hls.example.com", 181 | "hdl":"pili-live-hdl.example.com" 182 | }, 183 | "playback":{ 184 | "hls":"pili-playback.example.com" 185 | } 186 | } 187 | }' 188 | */ 189 | 190 | 191 | // Update a Stream 192 | try { 193 | 194 | $stream->publishKey = 'new_secret_words'; // optional 195 | $stream->publishSecurity = 'static'; // optional, can be "dynamic" or "static" 196 | $stream->disabled = NULL; // optional, can be "true" of "false" 197 | 198 | $stream = $stream->update(); # => Stream Object 199 | 200 | echo "Stream update() =>\n"; 201 | var_export($stream); 202 | echo "\n\n"; 203 | 204 | } catch (Exception $e) { 205 | echo "Stream update() failed. Caught exception: ", $e->getMessage(), "\n"; 206 | } 207 | /* 208 | Pili\Stream::__set_state(array( 209 | '_data' => 210 | array ( 211 | 'id' => 'z1.coding.55d7a219e3ba5723280000b5', 212 | 'createdAt' => '2015-08-21T18:11:37.057-04:00', 213 | 'updatedAt' => '2015-08-21T18:32:05.186076957-04:00', 214 | 'title' => '55d7a219e3ba5723280000b5', 215 | 'hub' => 'coding', 216 | 'disabled' => false, 217 | 'publishKey' => 'new_secret_words', 218 | 'publishSecurity' => 'static', 219 | 'hosts' => 220 | array ( 221 | 'publish' => 222 | array ( 223 | 'rtmp' => 'pili-publish.example.com', 224 | ), 225 | 'live' => 226 | array ( 227 | 'rtmp' => 'pili-live-rtmp.example.com', 228 | 'hls' => 'pili-live-hls.example.com', 229 | 'hdl' => 'pili-live-hdl.example.com', 230 | ), 231 | 'playback' => 232 | array ( 233 | 'hls' => 'pili-playback.example.com', 234 | ), 235 | ), 236 | ), 237 | )) 238 | */ 239 | 240 | 241 | // Disable a Stream 242 | $disabledTill = time() + 10; # disabled in 10s from now 243 | $result = $stream->disable($disabledTill); # => NULL 244 | echo "Stream disable() =>\n"; 245 | var_export($result); 246 | echo "\n\n"; 247 | /* 248 | true 249 | */ 250 | 251 | 252 | // Enable a Stream 253 | $result = $stream->enable(); # => NULL 254 | echo "Stream enable() =>\n"; 255 | var_export($result); 256 | echo "\n\n"; 257 | /* 258 | false 259 | */ 260 | 261 | 262 | // Get Stream status 263 | try { 264 | 265 | $result = $stream->status(); # => Array 266 | 267 | echo "Stream status() =>\n"; 268 | var_export($result); 269 | echo "\n\n"; 270 | 271 | } catch (Exception $e) { 272 | echo "Stream status() failed. Caught exception: ", $e->getMessage(), "\n"; 273 | } 274 | /* 275 | array ( 276 | "reqId" => "YmMxOTcuAAASDc1n", 277 | "hub" => "coding", 278 | "stream" => "2b20838cdb214448b7c7eef46abf1a0a", 279 | "startFrom" => "2015-12-03T12:24:30.226Z", 280 | 'addr' => '222.73.202.226:2572', 281 | 'status' => 'connected', 282 | 'bytesPerSecond' => 16870.200000000001, 283 | 'framesPerSecond' => 284 | array ( 285 | 'audio' => 42.200000000000003, 286 | 'video' => 14.733333333333333, 287 | 'data' => 0.066666666666666666, 288 | ), 289 | ) 290 | */ 291 | 292 | 293 | // Generate RTMP publish URL 294 | $publishUrl = $stream->rtmpPublishUrl(); 295 | echo "Stream rtmpPublishUrl() =>\n"; 296 | echo $publishUrl; 297 | echo "\n\n"; 298 | /* 299 | rtmp://pili-publish.example.com/coding/55d7a219e3ba5723280000b5?key=new_secret_words 300 | */ 301 | 302 | 303 | // Generate RTMP live play URLs 304 | $urls = $stream->rtmpLiveUrls(); 305 | echo "Stream rtmpLiveUrls() =>\n"; 306 | var_export($urls); 307 | echo "\n\n"; 308 | /* 309 | array ( 310 | 'ORIGIN' => 'rtmp://pili-live-rtmp.example.com/coding/55d7a219e3ba5723280000b5', 311 | ) 312 | */ 313 | 314 | 315 | // Generate HLS play URLs 316 | $urls = $stream->hlsLiveUrls(); 317 | echo "Stream hlsLiveUrls() =>\n"; 318 | var_export($urls); 319 | echo "\n\n"; 320 | /* 321 | array ( 322 | 'ORIGIN' => 'http://pili-live-hls.example.com/coding/55d7a219e3ba5723280000b5.m3u8', 323 | ) 324 | */ 325 | 326 | 327 | // Generate Http-Flv live play URLs 328 | $urls = $stream->httpFlvLiveUrls(); 329 | echo "Stream httpFlvLiveUrls() =>\n"; 330 | var_export($urls); 331 | echo "\n\n"; 332 | /* 333 | array ( 334 | 'ORIGIN' => 'http://pili-live-hdl.example.com/coding/55d7a219e3ba5723280000b5.flv', 335 | ) 336 | */ 337 | 338 | 339 | // Get Stream segments 340 | try { 341 | 342 | $start = NULL; // optional, in second, unix timestamp 343 | $end = NULL; // optional, in second, unix timestamp 344 | $limit = NULL; // optional, uint 345 | 346 | $result = $stream->segments($start, $end, $limit); # => Array 347 | 348 | echo "Stream segments() =>\n"; 349 | var_export($result); 350 | echo "\n\n"; 351 | 352 | } catch (Exception $e) { 353 | echo "Stream segments() failed. Caught exception: ", $e->getMessage(), "\n"; 354 | } 355 | /* 356 | array ( 357 | 'start' => 1440196065, 358 | 'end' => 1440198092, 359 | 'segments' => 360 | array ( 361 | 0 => 362 | array ( 363 | 'start' => 1440196065, 364 | 'end' => 1440196124, 365 | ), 366 | 1 => 367 | array ( 368 | 'start' => 1440198072, 369 | 'end' => 1440198092, 370 | ), 371 | ), 372 | ) 373 | */ 374 | 375 | 376 | // Generate HLS playback URLs 377 | $start = -1; // optional, in second, unix timestamp 378 | $end = -1; // optional, in second, unix timestamp 379 | 380 | $urls = $stream->hlsPlaybackUrls($start, $end); 381 | echo "Stream hlsPlaybackUrls() =>\n"; 382 | var_export($urls); 383 | echo "\n\n"; 384 | /* 385 | array ( 386 | 'ORIGIN' => 'http://pili-playback.example.com/coding/55d7a219e3ba5723280000b5.m3u8?start=-1&end=-1', 387 | ) 388 | */ 389 | 390 | 391 | // Snapshot Stream 392 | try { 393 | 394 | $name = 'imageName.jpg'; // required 395 | $format = 'jpg'; // required 396 | $time = NULL; // optional, in second, unix timestamp 397 | $notifyUrl = NULL; // optional 398 | $pipeline = NULL; // optional 399 | 400 | $result = $stream->snapshot($name, $format, $time, $notifyUrl, $pipeline); # => Array 401 | 402 | echo "Stream snapshot() =>\n"; 403 | var_export($result); 404 | echo "\n\n"; 405 | 406 | } catch (Exception $e) { 407 | echo "Stream snapshot() failed. Caught exception: ", $e->getMessage(), "\n"; 408 | } 409 | /* 410 | array ( 411 | 'targetUrl' => 'http://pili-static.example.com/snapshots/z1.coding.55d7a219e3ba5723280000b5/imageName.jpg', 412 | 'persistentId' => 'z1.55d7a6e77823de5a49a8899a', 413 | ) 414 | */ 415 | 416 | 417 | // Save Stream as a file 418 | try { 419 | 420 | $name = 'videoName.mp4'; // required 421 | $format = NULL; // optional 422 | $start = -1; // optional, in second, unix timestamp 423 | $end = -1; // optional, in second, unix timestamp 424 | $notifyUrl = NULL; // optional 425 | $pipeline = NULL; // optional 426 | 427 | $result = $stream->saveAs($name, $format, $start, $end, $notifyUrl, $pipeline); # => Array 428 | 429 | echo "Stream saveAs() =>\n"; 430 | var_export($result); 431 | echo "\n\n"; 432 | 433 | } catch (Exception $e) { 434 | echo "Stream saveAs() failed. Caught exception: ", $e->getMessage(), "\n"; 435 | } 436 | /* 437 | array ( 438 | 'url' => 'http://pili-media.example.com/recordings/z1.coding.55d7a219e3ba5723280000b5/videoName.m3u8', 439 | 'targetUrl' => 'http://pili-vod.example.com/recordings/z1.coding.55d7a219e3ba5723280000b5/videoName.mp4', 440 | 'persistentId' => 'z1.55d7a6e77823de5a49a8899b', 441 | ) 442 | */ 443 | // curl -D GET http://api.qiniu.com/status/get/prefop?id={persistentId} 444 | 445 | 446 | // Delete a Stream 447 | try { 448 | $result = $stream->delete(); # => NULL 449 | echo "Stream delete() =>\n"; 450 | var_dump($result); 451 | echo "\n\n"; 452 | } catch (Exception $e) { 453 | echo "Stream delete() failed. Caught exception: ", $e->getMessage(), "\n"; 454 | } 455 | /* 456 | NULL 457 | */ 458 | 459 | ?> 460 | -------------------------------------------------------------------------------- /lib/Pili.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /lib/Pili/Api.php: -------------------------------------------------------------------------------- 1 | USE_HTTPS === true ? "https" : "http"; 14 | $url = sprintf("%s://%s/%s/", $protocal, $cfg->API_HOST, $cfg->API_VERSION); 15 | return $url; 16 | } 17 | 18 | public static function createStream($transport, $hubName, $title = NULL, $publishKey = NULL, $publishSecurity = NULL) 19 | { 20 | $url = self::_getApiBaseUrl() . 'streams'; 21 | $params = array('hub' => $hubName); 22 | if (!empty($title)) { 23 | $params = array_merge($params, array('title' => $title)); 24 | } 25 | if (!empty($publishKey)) { 26 | $params = array_merge($params, array('publishKey' => $publishKey)); 27 | } 28 | if (!empty($publishSecurity)) { 29 | $params = array_merge($params, array('publishSecurity' => $publishSecurity)); 30 | } 31 | $body = json_encode($params); 32 | return $transport->send(HttpRequest::POST, $url, $body); 33 | } 34 | 35 | public static function getStream($transport, $streamId) 36 | { 37 | $url = self::_getApiBaseUrl() . "streams/$streamId"; 38 | return $transport->send(HttpRequest::GET, $url); 39 | } 40 | 41 | public static function listStreams($transport, $hubName, $marker = NULL, $limit = NULL, $title = NULL, $status = NULL, $idonly = NULL) 42 | { 43 | $url = self::_getApiBaseUrl() . "streams?hub=$hubName"; 44 | if (!empty($marker)) { 45 | $url .= "&marker=$marker"; 46 | } 47 | if (!empty($limit)) { 48 | $url .= "&limit=$limit"; 49 | } 50 | if (!empty($title)) { 51 | $url .= "&title=$title"; 52 | } 53 | if (!empty($status)) { 54 | $url .= "&status=$status"; 55 | } 56 | if (!empty($idonly)) { 57 | $url .= "&idonly"; 58 | } 59 | return $transport->send(HttpRequest::GET, $url); 60 | } 61 | 62 | public static function streamStatus($transport, $streamId) 63 | { 64 | $url = self::_getApiBaseUrl() . "streams/$streamId/status"; 65 | return $transport->send(HttpRequest::GET, $url); 66 | } 67 | 68 | public static function streamUpdate($transport, $streamId, $options = array()) 69 | { 70 | $url = self::_getApiBaseUrl() . "streams/$streamId"; 71 | $params = array(); 72 | $keys = array('publishKey', 'publishSecurity', 'disabled'); 73 | foreach ($keys as $key) { 74 | if (isset($options[$key])) { 75 | $params[$key] = $options[$key]; 76 | } 77 | } 78 | $body = json_encode($params); 79 | $body = empty($body) ? '{}' : $body; 80 | return $transport->send(HttpRequest::POST, $url, $body); 81 | } 82 | 83 | public static function streamDelete($transport, $streamId) 84 | { 85 | $url = self::_getApiBaseUrl() . "streams/$streamId"; 86 | return $transport->send(HttpRequest::DELETE, $url); 87 | } 88 | 89 | public static function streamSegments($transport, $streamId, $startTime = NULL, $endTime = NULL, $limit = NULL) 90 | { 91 | $url = self::_getApiBaseUrl() . "streams/$streamId/segments"; 92 | if (!empty($startTime)) { 93 | $url .= "?start=$startTime"; 94 | } 95 | if (!empty($endTime)) { 96 | $url .= "&end=$endTime"; 97 | } 98 | if (!empty($limit)) { 99 | $url .= "&limit=$limit"; 100 | } 101 | return $transport->send(HttpRequest::GET, $url); 102 | } 103 | 104 | public static function streamSaveAs($transport, $streamId, $name, $format = NULL, $start = NULL, $end = NULL, $notifyUrl = NULL, $pipeline = NULL) 105 | { 106 | $url = self::_getApiBaseUrl() . "streams/$streamId/saveas"; 107 | $params = array( 108 | 'name' => $name, 109 | ); 110 | if (!empty($format)) { 111 | $params['format'] = $format; 112 | } 113 | if (!empty($start)) { 114 | $params['start'] = $start; 115 | } 116 | if (!empty($end)) { 117 | $params['end'] = $end; 118 | } 119 | if (!empty($notifyUrl)) { 120 | $params['notifyUrl'] = $notifyUrl; 121 | } 122 | if (!empty($pipeline)) { 123 | $params['pipeline'] = $pipeline; 124 | } 125 | $body = json_encode($params); 126 | return $transport->send(HttpRequest::POST, $url, $body); 127 | } 128 | 129 | public static function streamSnapshot($transport, $streamId, $name, $format, $time = NULL, $notifyUrl = NULL, $pipeline = NULL) 130 | { 131 | $url = self::_getApiBaseUrl() . "streams/$streamId/snapshot"; 132 | $params = array( 133 | 'name' => $name, 134 | 'format' => $format, 135 | ); 136 | if (!empty($time)) { 137 | $params['time'] = $time; 138 | } 139 | if (!empty($notifyUrl)) { 140 | $params['notifyUrl'] = $notifyUrl; 141 | } 142 | if (!empty($pipeline)) { 143 | $params['pipeline'] = $pipeline; 144 | } 145 | $body = json_encode($params); 146 | return $transport->send(HttpRequest::POST, $url, $body); 147 | } 148 | 149 | public static function streamAvailable($transport, $streamId, $available, $disabledTill = NULL) 150 | { 151 | $url = self::_getApiBaseUrl() . "streams/$streamId/available"; 152 | $params = array('available' => $available); 153 | if (!empty($disabledTill)) { 154 | $params['disabledTill'] = $disabledTill; 155 | } 156 | $body = json_encode($params); 157 | return $transport->send(HttpRequest::POST, $url, $body); 158 | } 159 | } 160 | ?> 161 | -------------------------------------------------------------------------------- /lib/Pili/Config.php: -------------------------------------------------------------------------------- 1 | $property; 32 | } 33 | else 34 | { 35 | return NULL; 36 | } 37 | } 38 | 39 | public function __set($property, $value) 40 | { 41 | if (property_exists(self::getInstance(), $property)) 42 | { 43 | self::getInstance()->$property = $value; 44 | } 45 | return self::getInstance(); 46 | } 47 | } 48 | 49 | ?> 50 | -------------------------------------------------------------------------------- /lib/Pili/Hub.php: -------------------------------------------------------------------------------- 1 | _hub = $hubName; 17 | $this->_transport = new Transport($credentials); 18 | } 19 | 20 | public function createStream($title = NULL, $publishKey = NULL, $publishSecurity = NULL) 21 | { 22 | $stream = Api::createStream($this->_transport, $this->_hub, $title, $publishKey, $publishSecurity); 23 | return new Stream($this->_transport, $stream); 24 | } 25 | 26 | public function getStream($streamId) 27 | { 28 | $stream = Api::getStream($this->_transport, $streamId); 29 | return new Stream($this->_transport, $stream); 30 | } 31 | 32 | public function listStreams($marker = NULL, $limit = NULL, $title_prefix = NULL, $status = NULL) 33 | { 34 | $result = Api::listStreams($this->_transport, $this->_hub, $marker, $limit, $title_prefix, $status); 35 | $streams = $result["items"]; 36 | if (count($streams)>0) { 37 | foreach ($streams as &$stream) { 38 | $stream = new Stream($this->_transport, $stream); 39 | } 40 | $result["items"] = $streams; 41 | unset($stream); 42 | } 43 | return $result; 44 | } 45 | } 46 | ?> -------------------------------------------------------------------------------- /lib/Pili/Stream.php: -------------------------------------------------------------------------------- 1 | _data = $streamData; 15 | 16 | $this->_transport = $transport; 17 | 18 | if (empty($streamData) || !is_array($streamData)) { 19 | throw new \Exception('invalid args'); 20 | } 21 | } 22 | 23 | public function __get($property) 24 | { 25 | if (isset($this->_data[$property])) 26 | { 27 | return $this->_data[$property]; 28 | } 29 | else 30 | { 31 | return NULL; 32 | } 33 | } 34 | 35 | public function __set($property, $value) 36 | { 37 | if (isset($this->_data[$property])) 38 | { 39 | $this->_data[$property] = $value; 40 | } 41 | return $this; 42 | } 43 | 44 | public function toJSONString() 45 | { 46 | return json_encode($this->_data); 47 | } 48 | 49 | public function status() 50 | { 51 | return Api::streamStatus($this->_transport, $this->id); 52 | } 53 | 54 | public function update() 55 | { 56 | $stream = Api::streamUpdate($this->_transport, $this->id, $this->_data); 57 | return new Stream($this->_transport, $stream); 58 | } 59 | 60 | public function disable($disabledTill = NULL) 61 | { 62 | return Api::streamAvailable($this->_transport, $this->id, "disabled", $disabledTill); 63 | } 64 | 65 | public function enable() 66 | { 67 | return Api::streamAvailable($this->_transport, $this->id, "enabled"); 68 | } 69 | 70 | public function delete() 71 | { 72 | return Api::streamDelete($this->_transport, $this->id); 73 | } 74 | 75 | public function segments($start = NULL, $end = NULL, $limit = NULL) 76 | { 77 | return Api::streamSegments($this->_transport, $this->id, $start, $end, $limit); 78 | } 79 | 80 | public function saveAs($name, $format = NULL, $start = NULL, $end = NULL, $notifyUrl = NULL, $pipeline = NULL) 81 | { 82 | return Api::streamSaveAs($this->_transport, $this->id, $name, $format, $start, $end, $notifyUrl, $pipeline); 83 | } 84 | 85 | public function snapshot($name, $format, $time = NULL, $notifyUrl = NULL, $pipeline = NULL) 86 | { 87 | return Api::streamSnapshot($this->_transport, $this->id, $name, $format, $time, $notifyUrl, $pipeline); 88 | } 89 | 90 | // Publish URL 91 | // ------------------------------------------------------------------------------- 92 | public function rtmpPublishUrl() 93 | { 94 | switch ($this->publishSecurity) 95 | { 96 | case 'static': 97 | $url = $this->_rtmpPublishStaticUrl(); 98 | break; 99 | case 'dynamic': 100 | $url = $this->_rtmpPublishDynamicUrl(); 101 | break; 102 | default: 103 | $url = $this->_rtmpPublishBaseUrl(); 104 | break; 105 | } 106 | return $url; 107 | } 108 | 109 | private function _rtmpPublishDynamicUrl() 110 | { 111 | $nonce = time(); 112 | $url = sprintf("%s?nonce=%d&token=%s", $this->_rtmpPublishBaseUrl(), $nonce, $this->_publishDynamicToken($nonce)); 113 | return $url; 114 | } 115 | 116 | private function _rtmpPublishStaticUrl() 117 | { 118 | $url = sprintf("%s?key=%s", $this->_rtmpPublishBaseUrl(), $this->publishKey); 119 | return $url; 120 | } 121 | 122 | private function _rtmpPublishBaseUrl() 123 | { 124 | $url = sprintf("rtmp://%s/%s/%s", $this->hosts["publish"]["rtmp"], $this->hub, $this->title); 125 | return $url; 126 | } 127 | 128 | private function _publishDynamicToken($nonce) 129 | { 130 | $url = parse_url($this->_rtmpPublishBaseUrl()); 131 | $data = $url['path']; 132 | $separator = empty($url['query']) ? '?' : '&'; 133 | if (!empty($url['query'])) 134 | { 135 | $data .= $separator . $url['query']; 136 | } 137 | $data .= $separator . 'nonce=' . $nonce; 138 | $publishToken = Utils::sign($this->publishKey, $data); 139 | return $publishToken; 140 | } 141 | 142 | // RTMP Live Play URLs 143 | // -------------------------------------------------------------------------------- 144 | public function rtmpLiveUrls() 145 | { 146 | $urls = array(); 147 | $url = sprintf("rtmp://%s/%s/%s", $this->hosts["live"]["rtmp"], $this->hub, $this->title); 148 | $urls['ORIGIN'] = $url; 149 | if (isset($this->profiles) && !empty($this->profiles)) { 150 | foreach ($this->profiles as $profile) { 151 | $urls[$profile] = sprintf("%s@%s", $url, $profile); 152 | } 153 | } 154 | return $urls; 155 | } 156 | 157 | // HTTP Live Streaming Play URLs 158 | // -------------------------------------------------------------------------------- 159 | public function hlsLiveUrls() 160 | { 161 | $urls = array(); 162 | $urls['ORIGIN'] = sprintf("http://%s/%s/%s.m3u8", $this->hosts["live"]["hls"], $this->hub, $this->title); 163 | if (isset($this->profiles) && !empty($this->profiles)) { 164 | foreach ($this->profiles as $profile) { 165 | $urls[$profile] = sprintf("http://%s/%s/%s@%s.m3u8", $this->hosts["live"]["hls"], $this->hub, $this->title, $profile); 166 | } 167 | } 168 | return $urls; 169 | } 170 | 171 | // HTTP-Flv Live Play URLs 172 | // -------------------------------------------------------------------------------- 173 | public function httpFlvLiveUrls() 174 | { 175 | $urls = array(); 176 | $urls['ORIGIN'] = sprintf("http://%s/%s/%s.flv", $this->hosts["live"]["hdl"], $this->hub, $this->title); 177 | if (isset($this->profiles) && !empty($this->profiles)) { 178 | foreach ($this->profiles as $profile) { 179 | $urls[$profile] = sprintf("http://%s/%s/%s@%s.flv", $this->hosts["live"]["hdl"], $this->hub, $this->title, $profile); 180 | } 181 | } 182 | return $urls; 183 | } 184 | 185 | // HLS Playback URLs 186 | // -------------------------------------------------------------------------------- 187 | public function hlsPlaybackUrls($start = -1, $end = -1) 188 | { 189 | $name = sprintf("%d", time()); 190 | $resp = $this->saveAs($name, NULL, $start, $end); 191 | $urls = array(); 192 | $urls['ORIGIN'] = $resp["url"]; 193 | return $urls; 194 | } 195 | } 196 | ?> 197 | -------------------------------------------------------------------------------- /lib/Pili/Transport.php: -------------------------------------------------------------------------------- 1 | _credentials = $credentials; 16 | } 17 | 18 | public function send($method, $url, $body = NULL) 19 | { 20 | $headers = $this->_setHeaders($method, $url, $body); 21 | $response = HttpRequest::send($method, $url, $body, $headers); 22 | return $response->body; 23 | } 24 | 25 | private function _setHeaders($method, $url, $body = NULL) 26 | { 27 | $ctType = 'application/json'; 28 | $macToken = $this->_credentials->MACToken($method, $url, $ctType, $body); 29 | $ua = Utils::getUserAgent(Config::SDK_USER_AGENT, Config::SDK_VERSION); 30 | return array( 31 | 'Content-Type' => $ctType, 32 | 'User-Agent' => $ua, 33 | 'Authorization' => $macToken, 34 | ); 35 | } 36 | 37 | } 38 | 39 | ?> -------------------------------------------------------------------------------- /lib/Qiniu/Credentials.php: -------------------------------------------------------------------------------- 1 | _accessKey = $accessKey; 15 | $this->_secretKey = $secretKey; 16 | } 17 | 18 | public function MACToken($method, $url, $contentType, $body) 19 | { 20 | $url = parse_url($url); 21 | $data = ''; 22 | if (!empty($url['path'])) { 23 | $data = $method . ' ' . $url['path']; 24 | } 25 | if (!empty($url['query'])) { 26 | $data .= '?' . $url['query']; 27 | } 28 | if (!empty($url['host'])) { 29 | $data .= "\nHost: " . $url['host']; 30 | if (isset($url['port'])) { 31 | $data .= ':' . $url['port']; 32 | } 33 | } 34 | if (!empty($contentType)) { 35 | $data .= "\nContent-Type: " . $contentType; 36 | } 37 | $data .= "\n\n"; 38 | if (!empty($body)) { 39 | $data .= $body; 40 | } 41 | return 'Qiniu ' . $this->_accessKey . ':' . Utils::sign($this->_secretKey, $data); 42 | } 43 | } 44 | ?> -------------------------------------------------------------------------------- /lib/Qiniu/HttpRequest.php: -------------------------------------------------------------------------------- 1 | $value) { 62 | $k = isset($prefix) ? $prefix . '[' . $key . ']' : $key; 63 | if (!$value instanceof \CURLFile AND (is_array($value) OR is_object($value))) { 64 | self::http_build_query_for_curl($value, $new, $k); 65 | } else { 66 | $new[$k] = $value; 67 | } 68 | } 69 | } 70 | 71 | private static function getArrayFromQuerystring($querystring) 72 | { 73 | $pairs = explode("&", $querystring); 74 | $vars = array(); 75 | foreach ($pairs as $pair) { 76 | $nv = explode("=", $pair, 2); 77 | $name = $nv[0]; 78 | $value = $nv[1]; 79 | $vars[$name] = $value; 80 | } 81 | return $vars; 82 | } 83 | 84 | /** 85 | * Ensure that a URL is encoded and safe to use with cURL 86 | * @param string $url URL to encode 87 | * @return string 88 | */ 89 | private static function encodeUrl($url) 90 | { 91 | $url_parsed = parse_url($url); 92 | $scheme = $url_parsed['scheme'] . '://'; 93 | $host = $url_parsed['host']; 94 | $port = (isset($url_parsed['port']) ? $url_parsed['port'] : null); 95 | $path = (isset($url_parsed['path']) ? $url_parsed['path'] : null); 96 | $query = (isset($url_parsed['query']) ? $url_parsed['query'] : null); 97 | if ($query != null) { 98 | $query = '?' . http_build_query(self::getArrayFromQuerystring($url_parsed['query'])); 99 | } 100 | if ($port && $port[0] != ":") 101 | $port = ":" . $port; 102 | $result = $scheme . $host . $port . $path . $query; 103 | return $result; 104 | } 105 | 106 | private static function getHeader($key, $val) 107 | { 108 | $key = trim($key); 109 | return $key . ": " . $val; 110 | } 111 | 112 | /** 113 | * Send a cURL request 114 | * @param string $httpMethod HTTP method to use 115 | * @param string $url URL to send the request to 116 | * @param mixed $body request body 117 | * @param array $headers additional headers to send 118 | * @throws Exception if a cURL error occurs 119 | * @return HttpResponse 120 | */ 121 | public static function send($httpMethod, $url, $body = NULL, $headers = array()) 122 | { 123 | if ($headers == NULL) 124 | $headers = array(); 125 | $annexHeaders = array(); 126 | $finalHeaders = array_merge($headers, self::$defaultHeaders); 127 | foreach ($finalHeaders as $key => $val) { 128 | $annexHeaders[] = self::getHeader($key, $val); 129 | } 130 | $lowerCaseFinalHeaders = array_change_key_case($finalHeaders); 131 | $ch = curl_init(); 132 | if ($httpMethod != self::GET) { 133 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpMethod); 134 | if (is_array($body) || $body instanceof Traversable) { 135 | self::http_build_query_for_curl($body, $postBody); 136 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody); 137 | } else { 138 | curl_setopt($ch, CURLOPT_POSTFIELDS, $body); 139 | } 140 | } else if (is_array($body)) { 141 | if (strpos($url, '?') !== false) { 142 | $url .= "&"; 143 | } else { 144 | $url .= "?"; 145 | } 146 | self::http_build_query_for_curl($body, $postBody); 147 | $url .= urldecode(http_build_query($postBody)); 148 | } 149 | curl_setopt($ch, CURLOPT_URL, self::encodeUrl($url)); 150 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 151 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 152 | curl_setopt($ch, CURLOPT_MAXREDIRS, 10); 153 | curl_setopt($ch, CURLOPT_HTTPHEADER, $annexHeaders); 154 | curl_setopt($ch, CURLOPT_HEADER, true); 155 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, self::$verifyPeer); 156 | curl_setopt($ch, CURLOPT_ENCODING, ""); // If an empty string, "", is set, a header containing all supported encoding types is sent. 157 | if (self::$socketTimeout != null) { 158 | curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout); 159 | } 160 | $response = curl_exec($ch); 161 | $error = curl_error($ch); 162 | if ($error) { 163 | throw new \Exception($error); 164 | } 165 | // Split the full response in its headers and body 166 | $curl_info = curl_getinfo($ch); 167 | $header_size = $curl_info["header_size"]; 168 | $header = substr($response, 0, $header_size); 169 | $body = substr($response, $header_size); 170 | $httpCode = $curl_info["http_code"]; 171 | if ($httpCode >= 400) { 172 | throw new \Exception($body); 173 | } 174 | return new HttpResponse($httpCode, $body, $header); 175 | } 176 | } 177 | ?> -------------------------------------------------------------------------------- /lib/Qiniu/HttpResponse.php: -------------------------------------------------------------------------------- 1 | code = $code; 19 | $this->headers = $this->get_headers_from_curl_response($headers); 20 | $this->raw_body = $raw_body; 21 | $this->body = $raw_body; 22 | $json = json_decode($raw_body, true); 23 | if (json_last_error() == JSON_ERROR_NONE) { 24 | $this->body = $json; 25 | } 26 | } 27 | 28 | /** 29 | * Return a property of the response if it exists. 30 | * Possibilities include: code, raw_body, headers, body (if the response is json-decodable) 31 | * @return mixed 32 | */ 33 | public function __get($property) 34 | { 35 | if (property_exists($this, $property)) { 36 | return $this->$property; 37 | } 38 | } 39 | 40 | /** 41 | * Set the properties of this object 42 | * @param string $property the property name 43 | * @param mixed $value the property value 44 | */ 45 | public function __set($property, $value) 46 | { 47 | if (property_exists($this, $property)) { 48 | $this->$property = $value; 49 | } 50 | return $this; 51 | } 52 | 53 | /** 54 | * Retrieve the cURL response headers from the 55 | * header string and convert it into an array 56 | * @param string $headers header string from cURL response 57 | * @return array 58 | */ 59 | private function get_headers_from_curl_response($headers) 60 | { 61 | $headers = explode("\r\n", $headers); 62 | array_shift($headers); 63 | foreach ($headers as $line) { 64 | if (strstr($line, ': ')) { 65 | list($key, $value) = explode(': ', $line); 66 | $result[$key] = $value; 67 | } 68 | } 69 | return $result; 70 | } 71 | } 72 | ?> -------------------------------------------------------------------------------- /lib/Qiniu/Utils.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | tests 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/Pili/Tests/UtilTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($a, Utils::base64UrlDecode($b)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |