Tuesday, 14 March 2017

Youtube API fails to create two simultaneous bindings of livestreams and livebroadcasts (1 to 1)

First I'll explain how it works to create live streamings using the Youtube API then Second I'll explain the use case Third I'll paste my code snippet.

How it works :

Basically you need to create a livebroadcast (youtube.liveBroadcasts.insert) and get the livebroadcast id (1) then create a livestream (youtube.liveStreams.insert) and get the livestream id from it (2) once you have both you need to bind the livestream to the livebroadcast (youtube.liveBroadcasts.bind) :

the result of the binding contains basically the stream URL.

The Use case:

Basically it's a livestreaming api : the user register one or multiple youtube accounts, I run the below code to create livestreams and fetch the rtmp urls so I can stream simultaneously on multiple youtube channels.

the code :

oauth2Client.setCredentials({
    access_token: youtube_tokens.access_token,
    refresh_token: youtube_tokens.refresh_token,
    expiry_date: true
});

var youtube_broadcasts_body = {
    snippet: {
        //     "scheduledEndTime": "2016-11-23T20:00:00.0+08",
        "scheduledStartTime": start_date,
        "title": target.stream_title
    },
    status: {
        "privacyStatus": "private"
    },
    contentDetails: {
        "projection": youtubeProjection
    }
}
var youtube_livebroadcast_params = {
    part: "id,snippet,status, contentDetails",
    resource: youtube_broadcasts_body
}
var youtube_stream_body = {
    snippet: {
        "title": target.stream_title
    },
    cdn: {
        "ingestionType": "rtmp",
        "frameRate": "30fps",
        "resolution": target.youtube_resolution
    }
}
var youtube_stream_params = {
    part: "id,snippet,cdn,status",
    resource: youtube_stream_body
}
var youtube = google.youtube({ version: 'v3', auth: oauth2Client });

youtube.liveBroadcasts.insert(youtube_livebroadcast_params, function(err, res) {
    if (err) {
        logger.fatal(err)
        return callback(err)
    }
    target.broadcast = res
    target.status = "livebroadcast_event_created"
    var broadcast_id = res.id

    youtube.liveStreams.insert(youtube_stream_params, function(err, res) {
        if (err) {
            logger.fatal(err)
            return callback(err)
        }
        var stream_id = res.id
        res.broadcast_id = broadcast_id
        target.stream = res
        target.status = "livestream_created"
        var youtube_livebroadcast_bind_params = {
            part: "id,contentDetails",
            streamId: stream_id,
            id: broadcast_id
        }

        youtube.liveBroadcasts.bind(youtube_livebroadcast_bind_params, function(err, res) {
            if (err) return callback(err)
            target.status = "livebroadcast_bound_to_livestream"
            target.ingest_url = target.stream.cdn.ingestionInfo.ingestionAddress + "/" + target.stream.cdn.ingestionInfo.streamName
            target._id = broadcast_id
            return callback(null, target)
        })
    })
})

What happening is that when I call this code twice (in a for loop) the Youtube api returns an error : Livebroadcast not found As if there is a race condition somewhere causing to create 1 single and all the others fails. One dirty workaround that I had to do is to add a timeout (every 2 seconds) but if more than one user will use "my API" this will cause the whole thing to fail.

Now I'm thinking about creating a queue that will manage the creation of the youtube livestreams. Wondering if anyone had the issue ...



via M. Gara

No comments:

Post a Comment