Pili Streaming Cloud server-side library for Go
Go
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
example
pili
.gitignore
LICENSE
README.md

README.md

Table of Contents generated with DocToc

Pili Streaming Cloud server-side library for Golang

Features

  • Stream Create,Get,List
    • hub.CreateStream(options={Title,PublishKey,PublishSecurity})
    • hub.GetStream(stream.Id)
    • hub.ListStreams(options={Status,Marker,Limit,Title})
  • Stream operations else
    • stream.ToJSONString()
    • stream.Status()
    • stream.Update(options={PublishKey,PublishSecurity})
    • stream.Refresh()
    • stream.RtmpPublishUrl()
    • stream.RtmpLiveUrls()
    • stream.HlsLiveUrls()
    • stream.HttpFlvLiveUrls()
    • stream.HlsPlaybackUrls(start, end int64)
    • stream.Segments(options={Start,End, Limit})
    • stream.SaveAs(name,format string, start,end int64, options={notifyUrl})
    • stream.Snapshot(name,format string, options={time, notifyUrl})
    • stream.Delete()

Contents

Installation

before next step, install git.

// install latest version
$ go get github.com/pili-engineering/pili-sdk-go/pili

Usage

Configuration

package main

import (
    "github.com/pili-engineering/pili-sdk-go/pili"
    "fmt"
    // ...
)

const (
	ACCESS_KEY = "Qiniu_AccessKey"
	SECRET_KEY = "Qiniu_SecretKey"
	HUB_NAME   = "Pili_HubName"   // The Hub must be exists before use
)

func main() {

    // Change API host as necessary
    //
    // pili.qiniuapi.com as default
    // pili-lte.qiniuapi.com is the latest RC version
    //
    // pili.API_HOST = "pili.qiniuapi.com" // default

}

Hub

Instantiate a Pili Hub object

func main() {

	credentials := pili.NewCredentials(ACCESS_KEY, SECRET_KEY)
	hub := pili.NewHub(credentials, HUB_NAME)

    // ...
}

Create a new Stream

options := pili.OptionalArguments{               // optional
    Title:           "stream_title", // optional, auto-generated as default
    PublishKey:      "some_secret_words",        // optional, auto-generated as default
    PublishSecurity: "dynamic",                  // optional, can be "dynamic" or "static", "dynamic" as default
}
stream, err := hub.CreateStream(options)
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("CreateStream:\n", stream)
/*
{
    0xc208036018
    Id: z1.hub1.stream_title
    CreatedAt: 2015-08-22 15:37:20.397 +0800 CST
    UpdatedAt: 2015-08-24 09:41:55.32 +0800 CST
    Title: stream_title
    Hub: hub1
    Disabled: false
    PublishKey: some_secret_words
    PublishSecurity: dynamic
    Profiles: []
    Hosts: {
        Publish: map[
            rtmp:ec2s3f5.publish.z1.pili.qiniup.com
        ]
        Live: map[
            http:ec2s3f5.live1-http.z1.pili.qiniucdn.com
            rtmp:ec2s3f5.live1-rtmp.z1.pili.qiniucdn.com
        ]
        Playback: map[
            http:ec2s3f5.playback1.z1.pili.qiniucdn.com
        ]
    }
}
*/

Get a Stream

stream, err = hub.GetStream(stream.Id)
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("GetStream:\n", stream)
/*
{
    0xc208036018
    Id: z1.hub1.stream_title
    CreatedAt: 2015-08-22 15:37:20.397 +0800 CST
    UpdatedAt: 2015-08-24 09:41:55.32 +0800 CST
    Title: stream_title
    Hub: hub1
    Disabled: false
    PublishKey: some_secret_words
    PublishSecurity: dynamic
    Profiles: []
    Hosts: {
        Publish: map[
            rtmp:ec2s3f5.publish.z1.pili.qiniup.com
        ]
        Live: map[
            http:ec2s3f5.live1-http.z1.pili.qiniucdn.com
            rtmp:ec2s3f5.live1-rtmp.z1.pili.qiniucdn.com
        ]
        Playback: map[
            http:ec2s3f5.playback1.z1.pili.qiniucdn.com
        ]
    }
}
*/

List streams

options = pili.OptionalArguments{ // optional
    // Status: "connected", // optional
    Marker: "",        // optional, returned by server response
    Limit:  50,        // optional
    Title:  "prefix_", // optional, title prefix
}
listResult, err := hub.ListStreams(options)
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("ListStreams:\n", listResult)
for _, stream := range listResult.Items {
    fmt.Println("Stream:\n", stream)
}
/*
{1 [0xc208036018]}
&{
    0xc208036018
    Id: z1.hub1.stream_title
    CreatedAt: 2015-08-22 15:37:20.397 +0800 CST
    UpdatedAt: 2015-08-24 09:41:55.32 +0800 CST
    Title: stream_title
    Hub: hub1
    Disabled: false
    PublishKey: some_secret_words
    PublishSecurity: dynamic
    Profiles: []
    Hosts: {
        Publish: map[
            rtmp:ec2s3f5.publish.z1.pili.qiniup.com
        ]
        Live: map[
            http:ec2s3f5.live1-http.z1.pili.qiniucdn.com
            rtmp:ec2s3f5.live1-rtmp.z1.pili.qiniucdn.com
        ]
        Playback: map[
            http:ec2s3f5.playback1.z1.pili.qiniucdn.com
        ]
    }
}
*/

Stream

To JSON String

streamJson, err := stream.ToJSONString()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream ToJSONString:\n", streamJson)
/*
{
    "id":"z1.hub1.stream_title",
    "createdAt":"2015-08-22T15:37:20.397+08:00",
    "updatedAt":"2015-08-24T09:41:55.32+08:00",
    "title":"stream_title",
    "hub":"hub1",
    "disabled":false,
    "publishKey":"some_secret_words",
    "publishSecurity":"dynamic",
    "hosts":{
        "publish":{
            "rtmp":"ec2s3f5.publish.z1.pili.qiniup.com"
        },
        "live":{
            "http":"ec2s3f5.live1-http.z1.pili.qiniucdn.com",
            "rtmp":"ec2s3f5.live1-rtmp.z1.pili.qiniucdn.com"
        },
        "playback":{
            "http":"ec2s3f5.playback1.z1.pili.qiniucdn.com"
        }
    }
}
*/

Update a Stream

stream.PublishKey = "new_secret_words" // optional
stream.PublishSecurity = "static"      // optional
stream, err = stream.Update()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream Updated:\n", stream)
/*
{
    0xc208036018
    Id: z1.hub1.stream_title
    CreatedAt: 2015-08-22 15:37:20.397 +0800 CST
    UpdatedAt: 2015-08-24 09:41:55.32 +0800 CST
    Title: stream_title
    Hub: hub1
    Disabled: false
    PublishKey: new_secret_words
    PublishSecurity: static
    Profiles: []
    Hosts: {
        Publish: map[
            rtmp:ec2s3f5.publish.z1.pili.qiniup.com
        ]
        Live: map[
            http:ec2s3f5.live1-http.z1.pili.qiniucdn.com
            rtmp:ec2s3f5.live1-rtmp.z1.pili.qiniucdn.com
        ]
        Playback: map[
            http:ec2s3f5.playback1.z1.pili.qiniucdn.com
        ]
    }
}
*/

Disable a stream

stream, err = stream.Disable()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream Disabled:\n", stream.Disabled)
/*
true
*/

Disable a stream with disableTill

err := stream.DisableTill(time.Now().Add(time.Hour))
if err != nil {
    fmt.Println("Error:", err)
}

Enable a Stream

stream, err = stream.Enable()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream Enabled:\n", stream.Disabled)
/*
false
*/

Generate RTMP publish URL

url := stream.RtmpPublishUrl()
fmt.Println("Stream RtmpPublishUrl:\n", url)
/*
rtmp://ec2s3f5.publish.z1.pili.qiniup.com/hub1/stream_title?key=new_secret_words
*/

Generate RTMP live play URLs

urls, err := stream.RtmpLiveUrls()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("RtmpLiveUrls:", urls)
/*
map[ORIGIN:rtmp://ec2s3f5.live1-rtmp.z1.pili.qiniucdn.com/hub1/stream_title]
*/

Generate HLS play live URLs

urls, err = stream.HlsLiveUrls()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("HlsLiveUrls:", urls)
/*
map[ORIGIN:http://ec2s3f5.live1-http.z1.pili.qiniucdn.com/hub1/stream_title.m3u8]
*/

Generate Http-Flv live play URLs

urls, err = stream.HttpFlvLiveUrls()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("HttpFlvLiveUrls:", urls)
/*
map[ORIGIN:http://ec2s3f5.live1-http.z1.pili.qiniucdn.com/hub1/stream_title.flv]
*/

Get Stream status

streamStatus, err := stream.Status()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream Status:\n", streamStatus)
/*
 {
    Addr: 114.81.254.172:36317
    Status: connected
    BytesPerSecond: 16870.200000000001
    FramesPerSecond: {
        Audio: 42.200000000000003
        Video: 14.733333333333333
        Data: 0.066666666666666666
    }
}
*/

Get Stream segments

options = pili.OptionalArguments{ // optional
    Start: 1440379800, // optional, in second, unix timestamp
    End:   1440479880, // optional, in second, unix timestamp
    Limit: 20,         // optional, uint
}
segments, err := stream.Segments(options)
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Segments:\n", segments)
/*
{[0xc20800b2c0 0xc20800b320 0xc20800b350 0xc20800b380 0xc20800b3b0 0xc20800b3e0]}
*/

Generate HLS playback URLs

start := 1440379847
end := 1440379857
urls, err = stream.HlsPlaybackUrls(int64(start), int64(end))
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("HlsPlaybackUrls:", urls)
/*
map[ORIGIN:http://ec2s3f5.playback1.z1.pili.qiniucdn.com/hub1/stream_title.m3u8?start=1440379847&end=1440379857]
*/

Save Stream as a file

name := "fileName.mp4" // required, string
start = 1440379847     // required, int64, in second, unix timestamp
end = 1440379857       // required, int64, in second, unix timestamp
format := "mp4"        // optional, string
options = pili.OptionalArguments{
    NotifyUrl: "http://remote_callback_url",
    UserPipeline: "user_pipeline",
} // optional
saveAsRes, err := stream.SaveAs(name, format, int64(start), int64(end), options)
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream save as:\n", saveAsRes)
/*
{
    Url: http://ec2s3f5.vod1.z1.pili.qiniucdn.com/recordings/z1.hub1.stream_title/fileName.m3u8
    TargetUrl: http://ec2s3f5.vod1.z1.pili.qiniucdn.com/recordings/z1.hub1.stream_title/fileName.mp4
    PersistentId: z1.55da7715f51b82403b01e985
}
*/

While invoking saveAs() and snapshot(), you can get processing state via Qiniu FOP Service using persistentId.
API: curl -D GET http://api.qiniu.com/status/get/prefop?id={PersistentId}
Doc reference: http://developer.qiniu.com/docs/v6/api/overview/fop/persistent-fop.html#pfop-status

Snapshot Stream

name = "fileName.jpg" // required, string
format = "jpg"        // required, string
options = pili.OptionalArguments{
    Time:      1440379847, // optional, int64, in second, unit timestamp
    NotifyUrl: "http://remote_callback_url",
} // optional
snapshotRes, err := stream.Snapshot(name, format, options)
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream Snapshot:\n", snapshotRes)
/*
{
    TargetUrl: http://ec2s3f5.static1.z1.pili.qiniucdn.com/snapshots/z1.hub1.stream_title/fileName.jpg
    PersistentId: z1.55da7716f51b82403b01e986
}
*/

Delete a Stream

deleteResult, err := stream.Delete()
if err != nil {
    fmt.Println("Error:", err)
}
fmt.Println("Stream Deleted:\n", deleteResult)
/*
<nil>
*/

History

  • 1.5.3

    • Add UserPipeline in SaveAs
  • 1.5.2

    • Use SaveAs in HlsPlaybackUrls
  • 1.5.1

    • Update hub.ListStreams(options={Status, Marker,Limit, Title})
  • 1.5.0

    • Add stream.HttpFlvLiveUrls()
    • Add stream.Snapshot(name,format string, options={time, notifyUrl})
  • 1.3.1

    • Update stream.Update() logic
  • 1.3.0

    • Add stream.SaveAs(name,format string, start,end int64, options={notifyUrl})
  • 1.2.0

    • Add Stream operations
      • stream.ToJSONString()
      • stream.Update(options={PublishKey,PublishSecurity})
      • stream.Disable()
      • stream.Enable()
      • stream.RtmpPublishUrl()
      • stream.RtmpLiveUrls()
      • stream.HlsLiveUrls()
      • stream.Status()
      • stream.Segments(options={Start,End, Limit})
      • stream.HlsPlaybackUrls(start, end int64)
      • stream.Delete()
    • Update hub functions
      • hub.CreateStream(options={Title,PublishKey,PublishSecurity})
      • hub.GetStream(stream.Id)
      • hub.ListStreams(options={Marker,Limit, Title})