Is the Nx Cloud up? Visit our Status Page for the current health and performance of the Nx Cloud.

Status Page

Permission denied error with video streaming

Answered

Comments

4 comments

  • Anton Babinov
    • Network Optix team

    Hello Brian,
    could you please show me the code which you use to build auth string? Do you use the same auth string for all requests or do you generate a new one for each request? Do you have a single VMS server or multi-server environment?
    Also, please tell me VMS version and build number.

    0
  • Permanently deleted user

    Thanks for the quick response.

    Version 4.1.0.32405
    Platform windows_x64

    My cameras are spread across multiple VMS servers.  In my example above, I am using the same VMS server for all the requests (call it #1).  Camera 306924b1 and f1e10123 on #1, camera 132dc755 is on #2.  I have configured it to make sure the request goes to the server the camera is assigned to with the same results.

    I generate 1 auth string per server (in this case one server) per page load.  That string is used for all requests. 

    It seems to always work for (in this example) camera f1e10123, but never for the other two.

    Here is my code:

    var auths = [];

    function nxwEpochSecToTimeSting(time) {
    var stimeMS = time * 1000,
    stimeStr = new Date(stimeMS).toISOString();
    return stimeStr;
    }

    function nxwVideoServerReq(url) {
    var ajaxData;
    $.ajax({
    type: 'GET',
    url: url,
    cache: false,
    async: false,
    success: function(response) {
    ajaxData = response;
    },
    error: function(jqXHR, textStatus, errorThrown) {
    ajaxData = errorThrown;
    },
    });
    return ajaxData;
    }

    function nxwCreateAuth(urlPrefix, username, password) {
    var urlPrefix, nonceJSON, auth = '';

    nonceJSON = nxwVideoServerReq(urlPrefix + '/api/getNonce');

    if (nonceJSON.error == '0')
    {
    var nonce, realm, digest, partial_ha2, simplified_ha2;

    nonce = nonceJSON.reply.nonce;
    realm = nonceJSON.reply.realm;

    digest = md5(username + ":" + realm + ":" + password);
    partial_ha2 = md5("GET:");
    simplified_ha2 = md5(digest + ":" + nonce + ":" + partial_ha2);
    auth = btoa(username + ":" + nonce + ":" + simplified_ha2);
    }
    return auth;
    }

    function videoInit() {
    auths = [];
    }

    function isVideoAvailable(cameraInfo, cameraOffset) {
    var ip = cameraInfo.camera[cameraOffset][2],
    stime = nxwEpochSecToTimeSting(cameraInfo.videoStartTime)
    etime = nxwEpochSecToTimeSting(cameraInfo.videoEndTime),
    urlPrefix = 'http://' + ip + ":" + cameraInfo.camera[cameraOffset][3],
    availableJSON = '';

    if (auths[ip] === undefined)
    {
    auths[ip] = nxwCreateAuth(urlPrefix, cameraInfo.username, cameraInfo.password);
    }
    availableJSON = nxwVideoServerReq(urlPrefix +
    '/ec2/recordedTimePeriods' +
    '?auth=' + auths[ip] +
    '&cameraId=' + cameraInfo.camera[cameraOffset][1] +
    '&startTime=' + stime +
    '&endTime=' + etime +
    '&groupBy=none');
    if (availableJSON.error === '0' &&
    availableJSON.reply.length > 0)
    {
    return true;
    }
    return false;
    }

    function buildVideoURL(cameraInfo, cameraOffset) {
    var stime = nxwEpochSecToTimeSting(cameraInfo.videoStartTime)
    etime = nxwEpochSecToTimeSting(cameraInfo.videoEndTime),
    ip = cameraInfo.camera[cameraOffset][2],
    urlPrefix = 'http://' + ip + ":" + cameraInfo.camera[cameraOffset][3],
    url = '';

    if (auths[ip] === undefined)
    {
    auths[ip] = nxwCreateAuth(urlPrefix, cameraInfo.username, cameraInfo.password);
    }
    return urlPrefix +
    '/media/' + cameraInfo.camera[cameraOffset][1] + '.webm' +
    '?auth=' + auths[ip] +
    '&pos=' + stime +
    '&endPos=' + etime +
    '&resolution=' + cameraInfo.camera[cameraOffset][4] +
    '&sfd';
    }

    function buildImgUrl(cameraInfo, cameraOffset) {
    var time = nxwEpochSecToTimeSting(cameraInfo.eventTime),
    ip = cameraInfo.camera[cameraOffset][2],
    urlPrefix = 'http://' + ip + ":" + cameraInfo.camera[cameraOffset][3]
    url = '';

    if (auths[ip] === undefined)
    {
    auths[ip] = nxwCreateAuth(urlPrefix, cameraInfo.username, cameraInfo.password);
    }
    return urlPrefix +
    '/ec2/cameraThumbnail' +
    '?auth=' + auths[ip] +
    '&cameraId=' + cameraInfo.camera[cameraOffset][1] +
    '&time=' + time +
    '&height=240' +
    '&width=240';
    }


    function showVideoDialog(webVersion, dialogTitle, dialogBodyLabel, cameraInfo) {
    var cameraCount = cameraInfo.camera.length,
    tabStr = '',
    nav = '',
    pane = '',
    i;

    videoInit();

    for (i = 0; i < cameraCount; i++)
    {
    nav += '<li class="nav-item">' +
    '<a class="nav-link' + (i == 0 ? ' active' : '') + '" id="video-nav-tab-' + i + '" data-toggle="tab" href="#video-tab-' + i + '" role="tab" aria-controls="tab-' + i + '" aria-selected="true">' + cameraInfo.camera[i][0] + '</a>' +
    '</li>';

    pane += '<div class="tab-pane fade show' + (i == 0 ? ' active' : '') + '" id="video-tab-' + i + '" role="tabpanel" aria-labelledby="video-nav-tab-' + i + '">' +
    '<pre style="overflow: hidden;">';
    if (isVideoAvailable(cameraInfo, i))
    {
    pane += '<div class="stageVideo">' +
    '<video id="video-' + i + '" name="media" style="margin-top: 10px;" controls>' +
    '<source src="' + buildVideoURL(cameraInfo, i) + '" type="video/webm">' +
    '</video>' +
    '</div>';

    }
    else
    {
    pane += '<div class="stageNotAvail">' +
    '<i class="fa fa-video-slash fa-5x"></i>' +
    '</div>';
    }
    pane += '</pre>' +
    '</div>';
    }

    tabStr = '<ul class="nav nav-tabs" id="videoTab" role="tablist">' +
    nav +
    '</ul>' +
    '<div class="tab-content" id="videoTabContent">' +
    pane +
    '</div>';

    $('#videoTitle').html(dialogTitle);
    $('#videoBodyLabel').html(dialogBodyLabel);
    $('#videoBody').html(tabStr);

    }

    $("#videoModal").modal();
    }

    function showPictureDialog(dialogTitle, bodyLabel, cameraInfo) {
    var tabStr = '',
    nav = '',
    pane = '',
    i;

    videoInit();

    for (i = 0; i < cameraInfo.camera.length; i++)
    {
    nav += '<li class="nav-item">' +
    '<a class="nav-link' + (i == 0 ? ' active' : '') + '" id="pic-nav-tab-' + i + '" data-toggle="tab" href="#pic-tab-' + i + '" role="tab" aria-controls="tab-' + i + '" aria-selected="true">' + cameraInfo.camera[i][0] + '</a>' +
    '</li>';

    pane += '<div class="tab-pane fade show' + (i == 0 ? ' active' : '') + '" id="pic-tab-' + i + '" role="tabpanel" aria-labelledby="pic-nav-tab-' + i + '">' +
    '<img class="img-fluid" src="' + buildImgUrl(cameraInfo, i) + '">' +
    '</div>';
    }

    tabStr = '<ul class="nav nav-tabs" id="pictureTab" role="tablist">' +
    nav +
    '</ul>' +
    '<div class="tab-content" id="pictureTabContent">' +
    pane +
    '</div>';

    $('#pictureTitle').html(dialogTitle);
    $('#pictureBodyLabel').html(bodyLabel);
    $('#pictureBody').html(tabStr);

    $("#pictureModal").modal();
    }
    0
  • Anton Babinov
    • Network Optix team

    Brian, from the first look, I don't see that anything is wrong with your code.

    Such behaviour can occur when your user doesn't have permission to access all the cameras. Do you have same issue when using admin's login/password for generating auth string?

    VMS server allows building custom access roles without full access to all the cameras.

    I was able to reproduce your scenario with permission like on the screenshot above, so this seems like the most logical cause for your issue.

    0
  • Permanently deleted user

    Anton,

    Changing to the admin account seems to have fixed the problem.  I will talk to our camera admin to get the permissions changed.  Thank you so much for your help.

    0

Please sign in to leave a comment.