如何将Live stream发布到Youtube

1.搭建开发环境

  1. 申请Google账号
  2. 登录Google账号,进入创作者工作室。进入直播栏目,打开个人账户直播功能
  3. 进入google develop console
    a. 创建新项目
    b. 启用YouTube Data API v3
    c. 创建凭据,Oauth 客户端 ID,选择网页客户端。输入名称,重定向URL,点击创建。完成以后就可以获取一个json文件。里面就有需要的secrete_id。保存该json文件,会放入Android 工程中。
    d.如果完全没有使用过Youtube API可以下载youtube-api-samples。或者观看教学影片:YouTube Developers Live: Setting up your Java IDE for Google API samples

2.获取用户授权

(Java code,更加详细的授权,会在另一篇文章中呈现)

a.需要导入准备工作中下载的client_secrets.json文件。里面有client_id和client_secret。调用GoobleOAuth.login函数即可获得OAuth2AccessToken;

GoogleOAuth.login(VrSpherePreviewActivity.this)
.setClientId(clientSecrets.getDetails().getClientId())
.setClientSecret(clientSecrets.getDetails().getClientSecret())
.setAdditionalScopes("https://www.googleapis.com/auth/youtube")
.setRedirectUri("http://localhost:8080")
.setCallback(new OnLoginCallback())
.init();

获取token成功之后,我们就可以在OnLoginCallback()中得到OAuth2AccessToken token,其中包含token 和 fresh_token;

b.调用 Auth.authorize(clientSecrets, token);来获取Credential相关数据。
c.最后,调用下面的程序就可以通过credential数据来授权youtube账户下的Channel和live相关的操作;

youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential)
        .setApplicationName("youtube-cmdline-createbroadcast-sample").build();

3.建立LiveBroadCast频道

它的作用是在直播活动中建立一个频道。有频道的名称、开始和结束时间、频道的状态等信息。频道建立好以后,可以通过YouTube.LiveBroadcasts.Insert插入频道的一些属性。比如我们代码中就插入了snippet,status,contentDetails三种属性:

PropertyIntroduction
snippetThe snippet object contains basic details about the event, including its title, description, start time, and end time.
statusThe status object contains information about the event’s status.
contentDetailsThe contentDetails object contains information about the event’s video content, such as whether the content can be shown in an embedded video player or if it will be archived and therefore available for viewing after the event has concluded.

具体的属性信息可以参考Youtube的官方文档,有详细的介绍:https://developers.google.com/youtube/v3/live/docs/liveBroadcasts

我们需要设定的一些属性:

  • snippet.title
  • snippet.actualStartTime
  • snippet.scheduledStartTime
  • snippet.scheduledEndTime
  • status.privacyStatus
  • contentDetails.projection

设置完成之后,通过HTTP POST将请求发送给服务器。

POST https://www.googleapis.com/youtube/v3/liveBroadcasts

HTTP:

POST /youtube/v3/liveBroadcasts?part=id,snippet,status,contentDetails HTTP/1.1
Host: www.googleapis.com
Content-Type: application/json
Authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudddfJTg
Cache-Control: no-cache
Postman-Token: 29293451-38a3-306b-35ef-c652b4c1d3e7
{
  "snippet": {
    "title": "TestLiveCode",
    "actualStartTime": "2017-01-19T06:14:40.000Z",
    "scheduledStartTime": "2017-01-19T06:14:40.000Z",
    "scheduledEndTime": "2017-01-19T20:14:40.000Z"
  },
  "status": {
    "privacyStatus": "public"
  },
  "contentDetails": {
    "projection": "360"
  }
 }

获得Response,得到LiveBroadCasts信息:

{
   "kind": "youtube#liveBroadcast",
    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/RS5N6l3SydSyJtxvNL0Y1C1OYs4\"",
    "id": "TgaR-sHrnjM",
    "snippet": {
        "publishedAt": "2017-01-19T07:30:15.000Z",
        "channelId": "UCl75gUJzbdbrzNDWlu4nYkA",
        "title": "TestLiveCode",
        "description": "",
        "thumbnails": {
            "default": {
                "url": "https://i.ytimg.com/vi/TgaR-sHrnjM/default_live.jpg",
                "width": 120,
                "height": 90
            },
            "medium": {
                "url": "https://i.ytimg.com/vi/TgaR-sHrnjM/mqdefault_live.jpg",
                "width": 320,
                "height": 180
            },
            "high": {
                "url": "https://i.ytimg.com/vi/TgaR-sHrnjM/hqdefault_live.jpg",
                "width": 480,
                "height": 360
            }
        },
        "scheduledStartTime": "2017-01-19T07:14:30.000Z",
        "scheduledEndTime": "2017-01-19T20:14:40.000Z",
        "isDefaultBroadcast": false,
        "liveChatId": "Cg0KC1RnYVItc0hybmpN"
    },
    "status": {
        "lifeCycleStatus": "created",
        "privacyStatus": "public",
        "recordingStatus": "notRecording"
    },
    "contentDetails": {
        "monitorStream": {
            "enableMonitorStream": true,
            "broadcastStreamDelayMs": 0,
            "embedHtml": "<iframe width=\"425\" height=\"344\" src=\"https://www.youtube.com/embed/TgaR-sHrnjM?autoplay=1&livemonitor=1\" frameborder=\"0\" allowfullscreen></iframe>"
        },
        "enableEmbed": true,
        "enableDvr": true,
        "enableContentEncryption": false,
        "startWithSlate": false,
        "recordFromStart": true,
        "enableClosedCaptions": false,
        "closedCaptionsType": "closedCaptionsDisabled",
        "enableLowLatency": false,
        "projection": "360"
    }
}

Java

// Create a snippet with the title and scheduled start and end
// times for the broadcast. Currently, those times are hard-coded.
LiveBroadcastSnippet broadcastSnippet = new LiveBroadcastSnippet();
broadcastSnippet.setTitle(title);
long time = System.currentTimeMillis();
broadcastSnippet.setPublishedAt(new DateTime(time));
broadcastSnippet.setScheduledStartTime(new DateTime(time));
broadcastSnippet.setScheduledEndTime(new DateTime(time+60*60*1000));

// Set the broadcast's privacy status to "private". See:
// https://developers.google.com/youtube/v3/live/docs/liveBroadcasts#status.privacyStatus
LiveBroadcastStatus status = new LiveBroadcastStatus();
status.setPrivacyStatus("public");

LiveBroadcast broadcast = new LiveBroadcast();
broadcast.setKind("youtube#liveBroadcast");
broadcast.setSnippet(broadcastSnippet);
broadcast.setStatus(status);

LiveBroadcastContentDetails contentDetails = new LiveBroadcastContentDetails();
contentDetails.setProjection("360"); 
broadcast.setContentDetails(contentDetails);

// Construct and execute the API request to insert the broadcast.
YouTube.LiveBroadcasts.Insert liveBroadcastInsert =
        youtube.liveBroadcasts().insert("snippet,status,contentDetails", broadcast);
liveBroadcast = liveBroadcastInsert.execute();

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet%2Cstatus");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: 97d63c4d-8e5d-7c09-9de8-66b7db42c23b");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudnKfJTg");
headers = curl_slist_append(headers, "content-type: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\n  \"snippet\": {\n    \"title\": \"TestLiveCode\",\n    \"actualStartTime\": \"2017-01-19T06:14:40.000Z\",\n    \"scheduledStartTime\": \"2017-01-19T06:14:40.000Z\",\n    \"scheduledEndTime\": \"2017-01-19T20:14:40.000Z\"\n  },\n  \"status\": {\n    \"privacyStatus\": \"public\"\n  },\n  \"contentDetails\": {\n    \"projection\": \"360\"\n  }\n}");

CURLcode ret = curl_easy_perform(hnd);

4.建立streaming通道

建立频道的streaming通道。有了这个streaming通道,我们就可以通过该通道向频道发送直播视频。
需要设置一些streaming的属性:snippet,cdn ,status

PropertyIntroduction
snippetThe snippet object contains basic details about the stream, including its channel, title, and description
cdnThe cdn object defines the live stream’s content delivery network (CDN) settings. These settings provide details about the manner in which you stream your content to YouTube.
statusThe status object contains information about live stream’s status.

具体的属性信息可以参考Youtube的官方文档,有详细的介绍:https://developers.google.com/youtube/v3/live/docs/liveStreams

我们需要设定的一些属性:

  • snippet.title
  • cdn.ingestionInfo.streamName
  • cdn.ingestionInfo.ingestionAddress
  • cdn.resolution
  • cdn.ingestionType
  • cdn.frameRate

设置完成之后,通过HTTP POST将请求发送给服务器。

POST https://www.googleapis.com/youtube/v3/liveStreams

HTTP

POST //www.googleapis.com/youtube/v3/liveStreams?part=snippet,cdn HTTP/1.1
Host: POST https:
Content-Type: application/json
Authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudnKfJTg
Cache-Control: no-cache
Postman-Token: b3d3157d-9915-c084-2d43-85d9bdd74a88

{
  "snippet": {
    "title": "TestStream"
  },
  "cdn": {
    "ingestionInfo": {
      "streamName": "MyTestStream",
      "ingestionAddress": "rtmp://a.rtmp.youtube.com/live2"
    },
    "resolution": "720p",
    "ingestionType": "rtmp"
    "frameRate": "30fps"
  }
}

获得Response,得到LiveStreams的信息

{
    "kind": "youtube#liveStream",
    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/OsA5SrDlgCAfnSbwtDkNYyeBko0\"",
    "id": "l75gUJzbdbrzNDWlu4nYkA1484811227264011",
    "snippet": {
        "publishedAt": "2017-01-19T07:33:47.000Z",
        "channelId": "UCl75gUJzbdbrzNDWlu4nYkA",
        "title": "TestStream",
        "description": "",
        "isDefaultStream": false
    },
    "cdn": {
        "format": "720p",
        "ingestionType": "rtmp",
        "ingestionInfo": {
            "streamName": "qhvu-315p-y3wr-5uf7",
            "ingestionAddress": "rtmp://a.rtmp.youtube.com/live2",
            "backupIngestionAddress": "rtmp://b.rtmp.youtube.com/live2?backup=1"
        },
        "resolution": "720p",
        "frameRate": "30fps"
    }
}

streamName + ingestionAddress 则是我们的推送地址:rtmp://a.rtmp.youtube.com/live2/qhvu-315p-y3wr-5uf7

Java

// Create a snippet with the video stream's title.
LiveStreamSnippet streamSnippet = new LiveStreamSnippet();
streamSnippet.setTitle(title);

IngestionInfo ingestionInfo = new IngestionInfo();
ingestionInfo.setStreamName("Education");
//此Rtmp位址為固定,不需改變
//Youtube提供給我們打入Stream訊號的Rtmp Server
ingestionInfo.setIngestionAddress("rtmp://a.rtmp.youtube.com/live2");

// Define the content distribution network settings for the
// video stream. The settings specify the stream's format and
// ingestion type. See:
// https://developers.google.com/youtube/v3/live/docs/liveStreams#cdn
CdnSettings cdnSettings = new CdnSettings();
cdnSettings.setIngestionInfo(ingestionInfo);
cdnSettings.setFormat("720p");
cdnSettings.setIngestionType("rtmp");

LiveStream stream = new LiveStream();
stream.setKind("youtube#liveStream");
stream.setSnippet(streamSnippet);
stream.setCdn(cdnSettings);

// Construct and execute the API request to insert the stream.
YouTube.LiveStreams.Insert liveStreamInsert =
        youtube.liveStreams().insert("snippet,cdn", stream);
liveStream = liveStreamInsert.execute();
push_addr = liveStream.getCdn().getIngestionInfo().getIngestionAddress() + "/" + liveStream.getCdn()
        .getIngestionInfo().getStreamName(); ==>此处就是我们获取的stream的推送地址

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "http://post/%20https://www.googleapis.com/youtube/v3/liveStreams?part=snippet%2Ccdn");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: d3a48a2e-8d19-3c22-932d-9c615a2ffafa");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.Ci_XA_vpHXHqVh_0mUJ3DFjpNwvfy1XLsg2pRBDGXYIlSsyBOUgtdVOOhaudnKfJTg");
headers = curl_slist_append(headers, "content-type: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\n  \"snippet\": {\n    \"title\": \"TestStream\"\n  },\n  \"cdn\": {\n    \"ingestionInfo\": {\n      \"streamName\": \"MyTestStream\",\n      \"ingestionAddress\": \"rtmp://a.rtmp.youtube.com/live2\"\n    },\n    \"resolution\": \"720p\",\n    \"ingestionType\": \"rtmp\"\n  }\n}");

CURLcode ret = curl_easy_perform(hnd);

5.绑定LiveBroadcast和LiveStreams

将前面所建立的broadcast对象和stream对象进行绑定。一个broadcast只能有一个stream来源,但是一个stream来源可以同时绑定多个broadcast频道。

需要的设置的属性:

  • Id:LiveBroadCast的ID
  • streamId:LiveStreams的ID
    设置完成之后,通过HTTP POST将请求发送给服务器。
POST https://www.googleapis.com/youtube/v3/liveBroadcasts/bind

HTTP

POST /youtube/v3/liveBroadcasts/bind?part=id,contentDetails&amp;id=TgaR-sHrnjM&amp;streamId=l75gUJzbdbrzNDWlu4nYkA1484811227264011 HTTP/1.1
Host: www.googleapis.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Authorization: Bearer ya29.GlvYAxeqIoZCYHcg34TYX_cdtlFxk_9FVmw-Xlbf9uZhk_Jf5VeQ2RBPjDD-wcjxvLLvk4iG6ZZiFrySHzwHxsuasDPagrJVeVoQwYhods-vzXNM1wiZ67-ofWSN
Cache-Control: no-cache
Postman-Token: d936a1fc-ca1c-8cf8-7950-837fcd297928

获得Response,得到Bind的信息

{
    "kind": "youtube#liveBroadcast",
    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/1B1cxYwwGl93plqlVa67-0ilytE\"",
    "id": "TgaR-sHrnjM",
    "contentDetails": {
        "boundStreamId": "l75gUJzbdbrzNDWlu4nYkA1484811227264011",
        "boundStreamLastUpdateTimeMs": "2017-01-19T07:33:47.306Z",
        "monitorStream": {
            "enableMonitorStream": true,
            "broadcastStreamDelayMs": 0,
            "embedHtml": "<iframe width=\"425\" height=\"344\" src=\"https://www.youtube.com/embed/TgaR-sHrnjM?autoplay=1&livemonitor=1\" frameborder=\"0\" allowfullscreen></iframe>"
        },
        "enableEmbed": true,
        "enableDvr": true,
        "enableContentEncryption": false,
        "startWithSlate": false,
        "recordFromStart": true,
        "enableClosedCaptions": false,
        "closedCaptionsType": "closedCaptionsDisabled",
        "enableLowLatency": false,
        "projection": "360"
    }
}

分享给用户观看的地址则是:”https://www.youtube.com/watch?v= + id

Java

// Construct and execute a request to bind the new broadcast and stream.
YouTube.LiveBroadcasts.Bind liveBroadcastBind =
        youtube.liveBroadcasts().bind(liveBroadcast.getId(), "id,contentDetails");
liveBroadcastBind.setStreamId(liveStream.getId());
liveBroadcast = liveBroadcastBind.execute();

String share_addr = "https://www.youtube.com/watch?v=" + liveBroadcast.getId();  ==>此处即是我们分享给观众的观看地址。

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts/bind?part=id%2CcontentDetails&id=TgaR-sHrnjM&streamId=l75gUJzbdbrzNDWlu4nYkA1484811227264011");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: 2008a012-a4e6-991e-e977-a9c7095b0b89");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxeqIoZCYHcg34TYX_cdtlFxk_9FVmw-Xlbf9uZhk_Jf5VeQ2RBPjDD-wcjxvLLvk4iG6ZZiFrySHzwHxsuasDPagrJVeVoQwYhods-vzXNM1wiZ67-ofWSN");
headers = curl_slist_append(headers, "content-type: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

CURLcode ret = curl_easy_perform(hnd);

到这里,创建频道,获取视频流推送地址,以及用户观看地址都已经准备好了。此时我们就可以通过推流工具,或者自己的推流方法来完成向直播频道推流。在Youtube 直播栏目下面,进入直播活动,我们就可以看到已经创建的频道。点击进去以后,可以看到当前的频道是否有接收到码流。如果现实正常,则表示我们整个直播的频道和视频流都已经建立成功。只需要再下一步将我们的视频流播放给观众就可以了。

6.切换liveBroadcast状态

当我们建立好频道并且频道已经能够成功接收到稳定的码流数据之后。我们就可以通过获取stream的状态来获取码流是否正常。如下代码就是检测当前频道是否有稳定的码流上传:

使用HTTP GET来获取liveBroadcast状态

GET https://www.googleapis.com/youtube/v3/liveBroadcasts

HTTP

GET /youtube/v3/liveStreams?part=id,status&id=l75gUJzbdbrzNDWlu4nYkA1484811227264011 HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF
Cache-Control: no-cache
Postman-Token: 53301af4-fada-9f59-1568-be32d824aecc

Response

{
    "kind": "youtube#liveStreamListResponse",
    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/t4CVyYZj7CiWAqXNBYsuscwbjZk\"",
    "pageInfo": {
        "totalResults": 0,
        "resultsPerPage": 5
    },
    "items": [
        {
            "kind": "youtube#liveStream",
            "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/oTGzu9UF_NhJNIkjGpqqg_rpX-I\"",
            "id": "l75gUJzbdbrzNDWlu4nYkA1484811227264011",
            "status": {
                "streamStatus": "active",
                "healthStatus": {
                    "status": "bad",
                    "configurationIssues": [
                        {
                            "type": "videoResolutionUnsupported",
                            "severity": "error",
                            "reason": "Unsupported resolution",
                            "description": "You need to change the video resolution. The current resolution is (320x240), which is not supported for this configuration. The expected video resolution is (1280x720)." },
                        {
                            "type": "bitrateLow",
                            "severity": "warning",
                            "reason": "Video output low",
                            "description": "The stream's current bitrate (592.00 Kbps) is lower than the recommended bitrate. We recommend that you use a stream bitrate of 2500 Kbps." },
                        {
                            "type": "audioBitrateLow",
                            "severity": "info",
                            "reason": "Check audio settings",
                            "description": "The audio stream's current bitrate (96.00 Kbps) is lower than the recommended bitrate. We recommend that you use an audio stream bitrate of 128 Kbps." },
                        {
                            "type": "gopSizeOver",
                            "severity": "info",
                            "reason": "Check video settings",
                            "description": "Please use a keyframe frequency of four seconds or less. Currently, keyframes are not being sent often enough, which can cause buffering. The current keyframe frequency is 5.0 seconds. Note that ingestion errors can cause incorrect GOP (group of pictures) sizes." }
                    ]
                }
            }
        }
    ]
}

从Response里面的 “streamStatus”字段可以看出目前stream已经是处于”active”状态,表示目前我们LiveStreams已经可以收到稳定的视频流了。

Java

liveStreamRequest = youtube.liveStreams()
        .list("id,status")
        .setId(liveBroadcast.getContentDetails()
                .getBoundStreamId());
LiveStreamListResponse returnedList = liveStreamRequest.execute();
List<LiveStream> liveStreams = returnedList.getItems();
if (liveStreams != null && liveStreams.size() > 0) {
    LiveStream liveStream = liveStreams.get(0);
    if (liveStream != null)
        while (!liveStream.getStatus().getStreamStatus()
                .equals("active")) {
            Thread.sleep(1000);
            returnedList = liveStreamRequest.execute();
            liveStreams = returnedList.getItems();
            liveStream = liveStreams.get(0);
        }
}

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveStreams?part=id%2Cstatus&id=l75gUJzbdbrzNDWlu4nYkA1484811227264011");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: a6337852-8b07-703f-df71-e4c8a0e36060");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

CURLcode ret = curl_easy_perform(hnd);

当我们等到stream的状态为“Active”的时候。则表示码流正常。此时离用户能够看到直播的视频还差两步:
a.转换频道的状态为testing,此时我们可以让频道进入测试状态。用于直播发布者预览和检测直播视频。注意此时用户是没有办法看到直播画面的。

使用HTTP POST来切换liveBroadcast状态:

POST https://www.googleapis.com/youtube/v3/liveBroadcasts/transition

HTTP

POST /youtube/v3/liveBroadcasts/transition?broadcastStatus=testing&amp;id=TgaR-sHrnjM&amp;part=id,snippet,contentDetails,status HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF
Cache-Control: no-cache
Postman-Token: db9e406a-876e-9cc6-21e9-9713f7e5828e
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

Response

{
    "kind": "youtube#liveBroadcast",
    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/nNn7HZoSfMyCoMfqBvaAw1FEgdA\"",
    "id": "8jD-N6GIlkA",
    "snippet": {
        "publishedAt": "2017-01-19T09:02:42.000Z",
        "channelId": "UCl75gUJzbdbrzNDWlu4nYkA",
        "title": "TestLiveCode",
        "description": "",
        "thumbnails": {
            "default": {
                "url": "https://i.ytimg.com/vi/8jD-N6GIlkA/default_live.jpg",
                "width": 120,
                "height": 90
            },
            "medium": {
                "url": "https://i.ytimg.com/vi/8jD-N6GIlkA/mqdefault_live.jpg",
                "width": 320,
                "height": 180
            },
            "high": {
                "url": "https://i.ytimg.com/vi/8jD-N6GIlkA/hqdefault_live.jpg",
                "width": 480,
                "height": 360
            }
        },
        "scheduledStartTime": "2017-01-19T08:14:30.000Z",
        "scheduledEndTime": "2017-01-19T20:14:40.000Z",
        "isDefaultBroadcast": false,
        "liveChatId": "Cg0KCzhqRC1ONkdJbGtB"
    },
    "status": {
        "lifeCycleStatus": "testStarting",
        "privacyStatus": "public",
        "recordingStatus": "notRecording"
    },
    "contentDetails": {
        "boundStreamId": "l75gUJzbdbrzNDWlu4nYkA1484816504294010",
        "boundStreamLastUpdateTimeMs": "2017-01-19T09:01:44.342Z",
        "monitorStream": {
            "enableMonitorStream": true,
            "broadcastStreamDelayMs": 0,
            "embedHtml": "<iframe width=\"425\" height=\"344\" src=\"https://www.youtube.com/embed/8jD-N6GIlkA?autoplay=1&livemonitor=1\" frameborder=\"0\" allowfullscreen></iframe>"
        },
        "enableEmbed": true,
        "enableDvr": true,
        "enableContentEncryption": false,
        "startWithSlate": false,
        "recordFromStart": true,
        "enableClosedCaptions": false,
        "closedCaptionsType": "closedCaptionsDisabled",
        "enableLowLatency": false,
        "projection": "360"
    }
}

Java

//the broadcast cann't transition the status from ready to live directly,
//it must change to testing first and then live.
YouTube.LiveBroadcasts.Transition broadCastTestingRequest = youtube
        .liveBroadcasts().transition("testing",
                liveBroadcast.getId(), "id,snippet,contentDetails,status");
liveBroadcast = broadCastTestingRequest.execute();

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts/transition?broadcastStatus=testing&id=TgaR-sHrnjM&part=id%2Csnippet%2CcontentDetails%2Cstatus");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: 96da5833-3923-2bbe-e453-1c29efcf8973");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

CURLcode ret = curl_easy_perform(hnd);

b.当broadcast的状态变成testing之后。我们需要将状态切换成为“live”,此时用户就可以看到直播画面。

使用HTTP POST切换liveBroadCast状态从testing到live

POST https://www.googleapis.com/youtube/v3/liveBroadcasts/transition

HTTP

POST /youtube/v3/liveBroadcasts/transition?broadcastStatus=live&amp;id=TgaR-sHrnjM&amp;part=id,snippet,contentDetails,status HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF
Cache-Control: no-cache
Postman-Token: 65b123be-7641-8561-56fa-11f3c1f53193
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

Java

YouTube.LiveBroadcasts.Transition transitionRequest = youtube.liveBroadcasts().transition("live", liveBroadcast.getId(), "status");
liveBroadcast = transitionRequest.execute();

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts/transition?broadcastStatus=live&id=TgaR-sHrnjM&part=id%2Csnippet%2CcontentDetails%2Cstatus");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: cb2eb41c-803e-e1ec-d0f9-419772850ff5");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYAxT6PZjpk_prTaPm2clOVaIPbSYFrYc37I9PIDtJ-nYiT5bCevA24vkUezhoD-_ufMP3Yi2Bte6guECX0QRIknVIby4RUXj8Ms73primnytBoOfVNnGD7ckF");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

CURLcode ret = curl_easy_perform(hnd);

需要注意的有两个地方:1.频道的状态转换必须是active->testing->live。不能直接从active转为live。2.必须要等待broadcast的状态变成testing之后,才能进行testing->live的转换。所以必须进行一个testing状态转换完成的一个确认,如下代码即可:

使用HTTP GET来获取liveBroadcast状态:

GET https://www.googleapis.com/youtube/v3/liveBroadcasts

HTTP

GET /youtube/v3/liveBroadcasts?part=id,status&amp;id=TgaR-sHrnjM HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.GlvYA7oXl3IVdI4Bok9jyXC4eXhOzm98oja33jCdrRClc49ie7lOm8inRprZ9qAYyEf7OpsekQUTOarlip-DvY1gewZQGKeW1G1jTWR6djxxpTi4hGmQzSzEOadJ
Cache-Control: no-cache
Postman-Token: cd8dada9-5a1b-bab2-611a-c515bbc9c6d7

Response

{
    "kind": "youtube#liveBroadcastListResponse",
    "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/absIVeqkZihPc-0pJMCYTpR5yjU\"",
    "pageInfo": {
        "totalResults": 0,
        "resultsPerPage": 5
    },
    "items": [
        {
            "kind": "youtube#liveBroadcast",
            "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/xrp9a15kZwGJVPtt4AT1OHJjXPw\"",
            "id": "TgaR-sHrnjM",
            "status": {
                "lifeCycleStatus": "testStarting",
                "privacyStatus": "public",
                "recordingStatus": "notRecording"
            }
        }
    ]
}

从Response得到的”lifeCycleStatus”字段可以看到目前的状态为”testStarting”,表示正在切换testing状态中。需要等到”lifeCycleStatus”: “testing”,则表示状态已经切换完成,可以继续从testing 向 live状态切换。

Java

liveBroadRequest = youtube.liveBroadcasts().list("id,status");
liveBroadRequest.setBroadcastStatus("all");

LiveBroadcastListResponse liveBroadcastResponse = liveBroadRequest.execute();
List<LiveBroadcast> returnedList = liveBroadcastResponse.getItems();
if (returnedList != null && returnedList.size() > 0) {
    liveBroadcastReq = returnedList.get(0);
    if (liveBroadcastReq != null)
        while (!liveBroadcastReq.getStatus().getLifeCycleStatus().equals("testing")) {
            Thread.sleep(1000);
            AppLog.d("Error","publish broadcast - getLifeCycleStatus: " + liveBroadcastReq.getStatus().getLifeCycleStatus());
            liveBroadcastResponse = liveBroadRequest.execute();
            returnedList = liveBroadcastResponse.getItems();
            liveBroadcastReq = returnedList.get(0);
        }
}

C

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Cstatus&id=TgaR-sHrnjM");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "postman-token: bf3a9e6f-52ae-e159-a2ad-cc81c979c68e");
headers = curl_slist_append(headers, "cache-control: no-cache");
headers = curl_slist_append(headers, "authorization: Bearer ya29.GlvYA7oXl3IVdI4Bok9jyXC4eXhOzm98oja33jCdrRClc49ie7lOm8inRprZ9qAYyEf7OpsekQUTOarlip-DvY1gewZQGKeW1G1jTWR6djxxpTi4hGmQzSzEOadJ");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "code=4%2FYxFunij3D3aBdBolu0wDJvM1heM17gfg5e-gYjby2cU&client_id=982555336638-e1e18fh47oo0dceecq9v1pejm4p7ske8.apps.googleusercontent.com&client_secret=2RpCEltwtZvkUS4MsX6rzwmG&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&grant_type=authorization_code");

CURLcode ret = curl_easy_perform(hnd);

至此,我们就可以在分享给用户的地址中观看到直播视频了。

7.流程图

代码流程图

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值