Agora cloud recording not saving video in azure - azure-storage

static startRecording = async (resourceId, channelName, idsToUse) => {
let startDateTime = Date.now();
console.log("Total ID USER MAP Time = " + (Date.now() - startDateTime) / 1000);
try {
const request = {
uid: '999',
cname: `${channelName}`,
clientRequest: {
token: EventService.getRecordingToken(channelName),//tocken of 999
recordingConfig: {
maxIdleTime: 120,
streamTypes: 2,
channelType: 0,
videoStreamType: 0,
subscribeVideoUids: [idsToUse.uId + ""],
subscribeAudioUids: [idsToUse.uId + ""],
subscribeUidGroup: 0
},
recordingFileConfig: {
avFileType: ["hls"]
},
storageConfig: {
accessKey: "ACCESS KEY",
region: 0,//The region parameter has no effect, whether or not it is set.(Ref:https://docs.agora.io/en/cloud-recording/cloud_recording_api_rest?platform=RESTful)
bucket: `azure-recordings/${channelName}`,
secretKey: "SECRET KEY",
vendor: 5
}
}
};
console.log("agoraApiCallConfig", agoraApiCallConfig);
console.log("req", request);
const requestUrl = `${AgoraBaseUrl}/v1/apps/${AgoraAppID}/cloud_recording/resourceid/${resourceId}/mode/individual/start`;
const start = Date.now();
console.log("req--", requestUrl);
const response = await axios.post(requestUrl, request, agoraApiCallConfig);
const stop = Date.now();
const elapsed = stop - start;
//console.log("Total Start Recording Time = " + elapsed / 1000);
console.log("response.data", response.data);
if (response.status == 200 || response.status == 201) {
return response.data;
}
log(response.data, "error");
throw Error("Recording starting failed with status code: " + response.status);
} catch (e) {
appInsightLogHelper.trackException(e, 4);
throw e;
}
};
this is my code for recording and storing data in azure can anyone guide me why the data is not moving in azure?
I am going live on my app and then I try to record that live with a bot user and then store that in blob service in azure storage container.

I too was struggling with Agora.io and Azure integration just yesterday, and had same-ish troubles.
After asking their support, I came to understand that storageConfig for Azure Storage Account must be set as follows:
{
vendor: 5,
region = 0,
accessKey = <storage account name>,
secretKey = <access key>,
bucket = <container name>,
fileNamePrefix = ["directory", "subdirectory"]
}
Therefore if you want to save to storage account named "junaidstorageaccount", in container "azure-recordings" and directory {channelName}, the config you should use would be as follows:
{
vendor: 5,
region: 0,
accessKey: 'junaidstorageaccount',
secretKey: <access key>,
bucket: 'azure-recordings',
fileNamePrefix: [channelName]
}
Notes:
region is unused, you can omit it or set to anything, I prefer to set to zero
Replace with access key to the Storage Account
fileNamePrefix: an array representing the path of directories in which to store the files. So if you want to store files in my/beautiful/directory, you'll have to pass ['my', 'beautiful', 'directory']
As per Agora documentation (https://docs.agora.io/en/cloud-recording/integration_best_practices?platform=RESTful#a-namestart_successaensure-the-recording-service-starts-successfully), you should call query after calling start to check the recording status (it should be 4 or 5), and keep checking for all the recording duration, at intervals less than maxIdleTime.
Wishing you best of luck!

Related

How to add variable into JSON path

This is the query I am using:
app.get("/items/:data", async (req, res) => {
const { data } = req.params;
query = `
SELECT items.discount
FROM items
WHERE items.discount #? '$[*] ? (#.discount[*].shift == $1)'
`
try {
const obj = await pool.query(query, [data]);
res.json(obj.rows[0])
} catch(err) {
console.error(err.message);
}
});
I get this error:
error: bind message supplies 1 parameters, but prepared statement "" requires 0
I am using node-postgres package in node.js.
How can I solve this issue?
Use bracket notation instead of dot notation. So instead of obj.key use obj[key]
Updated
all them driver connectors come with their own method to do what you're looking for. node-postgres also have there own
Pool
import { Pool } from 'pg';
const pool = new Pool({
  host: 'localhost',
user: 'database-user',
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
/**
* execs the given sql statement.
*
* #param {string} sql - query to run.
* #param {Array} params - an array with the parameter.
* #example
* runQuery("SELECT * FROM users WHERE id = $1", [1]).then(result=> console.log(result))
*/
export async function runQuery (sql, params) {
const connection = await pool.connect()
try {
await connection.query('BEGIN')
const queryText = 'INSERT INTO users(name) VALUES($1) RETURNING id'
const result = await connection.query(sql,params);
// check what result has
console.log(result);
return connection.query('COMMIT').then(result)
} catch (e) {
await connection.query('ROLLBACK')
throw e;
throw e
} finally {
connection.release()
}
}
Pool Config
config = {
// all valid client config options are also valid here
// in addition here are the pool specific configuration parameters:
// number of milliseconds to wait before timing out when connecting a new client
// by default this is 0 which means no timeout
connectionTimeoutMillis?: int,
// number of milliseconds a client must sit idle in the pool and not be checked out
// before it is disconnected from the backend and discarded
// default is 10000 (10 seconds) - set to 0 to disable auto-disconnection of idle clients
idleTimeoutMillis?: int,
// maximum number of clients the pool should contain
// by default this is set to 10.
max?: int,
}
conclution
so basically the structure of a query should be like or less this
const text = 'INSERT INTO users(name, email) VALUES($1, $2) RETURNING *'
const values = ['brianc', 'brian.m.carlson#gmail.com']
connection
.query(text, values)
.then(res => {
console.log(res.rows[0])
// { name: 'brianc', email: 'brian.m.carlson#gmail.com' }
})
.catch(e => console.error(e.stack))

How to send a message when a trello card is moved to a certain list

I’m currently making a bot that informs me when a card is moved to the list titled Passed Applications.
I have already made the code and it basically sends a message once a card is moved to the specific list, however, it will randomly send a message and pull a card minutes/hours after it has already been pulled and sent the message.
What I’ve done so far is:
trello.js
var Trello = require("node-trello"),
EventEmitter = require("events").EventEmitter,
extend = require("extend"),
config,
trello,
timer,
e;
module.exports = function(options) {
var defaults = {
pollFrequency: 1000 * 60,
minId: 0,
trello: {
key: "",
token: "",
boards: []
},
start: true
};
e = new EventEmitter();
config = extend(true, defaults, options);
trello = new Trello(
process.env.TRELLO_API_KEY,
process.env.TRELLO_OAUTH_TOKEN
);
if (config.start) {
process.nextTick(function() {
start(config.pollFrequency, true);
});
}
function start(frequency, immediate) {
if (timer) {
return;
}
frequency = frequency || config.pollFrequency;
timer = setInterval(poll, frequency);
if (immediate) {
poll();
}
}
function poll() {
config.trello.boards.forEach(function(boardId) {
getBoardActivity(boardId);
});
}
function getBoardActivity(boardId) {
trello.get("/1/boards/" + boardId + "/actions", function(err, resp) {
if (err) {
return e.emit("trelloError", err);
}
var boardActions = resp.reverse();
var actionId;
for (var ix in boardActions) {
actionId = parseInt(boardActions[ix].id, 16);
if (actionId <= config.minId) {
continue;
}
var eventType = boardActions[ix].type;
e.emit(eventType, boardActions[ix], boardId);
}
config.minId = Math.max(config.minId, actionId);
e.emit("maxId", config.minId);
});
}
index.js
const conf = JSON.parse(fs.readFileSync("trelloconfig.json"));
let latestActivityID = fs.existsSync("./latestActivityID") ?
fs.readFileSync("./latestActivityID") :
0;
const eventEnabled = type =>
conf.enabledEvents.length > 0 ? conf.enabledEvents.includes(type) : true;
const TrelloEvents = require("./trello.js");
const events = new TrelloEvents({
pollFrequency: 60000,
minId: latestActivityID,
start: false,
trello: {
boards: conf.boardIDs,
key: process.env.TRELLO_API_KEY,
token: process.env.TRELLO_OAUTH_TOKEN
}
});
client.on("ready", () => {
events.start();
console.log(`[STATUS CHANGE] ${client.user.username} is now online.`);
client.user.setActivity("Cookout Grill");
});
events.on("updateCard", (event, board) => {
if (event.data.old.hasOwnProperty("idList")) {
if (!eventEnabled(`cardListChanged`)) return;
if (event.data.listAfter.name === "Passed Applications") {
let robloxId = event.data.card.name.split(" | ")[0];
client.channels.get("730839109236424756").send(robloxId);
if (database.find(x => x.RobloxUser === robloxId)) {
let data = database.find(x => x.RobloxUser === robloxId);
const person = client.users.get(data.DiscordID);
let embed = new discord.RichEmbed()
.setThumbnail(
"https://www.roblox.com/bust-thumbnail/image?userId=" +
data.RobloxID +
"&width=420&height=420&format=png"
)
.setTitle("APPLICATION RESULTS | Passed")
.setColor("3ef72d")
.setFooter("Cookout Grill", client.user.avatarURL)
.setDescription(
"Greetings, **" +
data.RobloxUser +
"**!\n\nAfter extensive review by our Management Team, we have decided to accept your Trainee Application at Cookout Grill. We believe that your application showed that you’re ready to become a staff member at our establishment.\n\nWe would like to congratulate you on passing your Trainee Application. Your application met our critical expectations and requirements in order to pass.\n\nIn order to work your way up throughout the staff ranks, you must attend a training at [Cookout Grill’s Training Center](https://www.roblox.com/groups/5634772/Cookout-Grill#!/about) during the specific session times. If you’re unable to attend one of our designated sessions, feel free to schedule a private session with a member of our Management Team.\n\nWe wish you the best of luck in continuing throughout the staff ranks at Cookout Grill. If you have any further questions, please do not hesitate to create a ticket in our main Discord Server."
)
.addField("**NEW RANK**", "`Trainee`");
person.send(embed);
roblox.message(
event.data.card.name.split(" | ")[1],
"APPLICATION RESULTS | Passed",
"Greetings, **" +
data.RobloxUser +
"**!\n\nAfter extensive review by our Management Team, we have decided to accept your Trainee Application at Cookout Grill.\n\nWe would like to congratulate you on passing your Trainee Application. Your application met our critical expectations and requirements in order to pass.\n\nIn order to work your way up throughout the staff ranks, you must attend a training at Cookout Grill’s Training Center during the specific session times. If you’re unable to attend one of our designated sessions, feel free to schedule a private session with a member of our Management Team.\n\nWe wish you the best of luck in continuing throughout the staff ranks at Cookout Grill."
);
}
let embed2 = new discord.RichEmbed()
.setTitle(`Card list changed!`)
.setDescription(
`**CARD:** ${
event.data.card.name
} — **[CARD LINK](https://trello.com/c/${
event.data.card.shortLink
})**\n\n**EVENT:** Card moved to list __${
event.data.listAfter.name
}__ from list __${event.data.listBefore.name}__ by **[${
conf.realNames
? event.memberCreator.fullName
: event.memberCreator.username
}](https://trello.com/${event.memberCreator.username})**`
);
client.channels.get("730839109236424756").send(embed2);
Trello.addCommentToCard(
event.data.card.id,
"User has been ranked.",
function(error, trelloCard) {
console.log(error);
}
);
} else return;
} else return;
});

How to continue download multiple files (AWS server images) in background in react-native iOS

I created an app where user can download multiple images on one click using react-native-fs which is working perfectly in Android. But in iOS when app is inactive then download stopped and user have to start download again.
async.eachSeries(DownloadData, async function (tourData, finish) {
console.log("# resumable : 655612", tourData);
var fileExtension = '';
var fileURL = tourData.path;
var fileExtension = "/" + tourData.name + "Image" + p + ".png
p = p + 1;
const downloadDest = RNFS.DocumentDirectoryPath + fileExtension;
let dirs = RNFetchBlob.fs.dirs;
var v = dirs.DocumentDir;
var jobId = -1;
const ret = RNFS.downloadFile({
fromUrl: encodeURI(fileURL),
toFile: downloadDest,
connectionTimeout: 1000 * 10,
readTimeout: 1000 * 10,
background: true,
discretionary: true,
progressDivider: 1,
resumable: (res) => {
console.log("# resumable", res);
},
begin: (res) => {
console.log(res)
},
progress: (data) => {
console.log(data)
},
});
jobId = ret.jobId;
RNFS.isResumable(jobId).then(true);
if (await RNFS.isResumable(jobId)) {
console.log("# resumable : # resumable : # resumable :",jobId);
RNFS.resumeDownload(jobId)
}
ret.promise.then((res) => {
finish();
}).catch(err => {
finish();
})
},function (err) {
if (!err) {
callback(true)
} else {
callback(false)
}
}));
Running download in background in IOS require few extra settings check this section https://github.com/itinance/react-native-fs#background-downloads-tutorial-ios
they also mentioned that IOS will give you 30 sec after handleEventsForBackgroundURLSession
BE AWARE! iOS will give about 30 sec. to run your code after handleEventsForBackgroundURLSession is called and until completionHandler is triggered so don't do anything that might take a long time (like unzipping), you will be able to do it after the user re-launces the app, otherwide iOS will terminate your app.
I hope this helps

Unable to record again after stopping record in Kurento

I am working on this Kurento application and there is a strange problem i am facing where once I start recording the video and stop the recording, I cant start another recording again. The event goes to the server but nothing seems to be happening! PFB the code:
room.pipeline.create('WebRtcEndpoint', function (error, outgoingMedia) {
if (error) {
console.error('no participant in room');
// no participants in room yet release pipeline
if (Object.keys(room.participants).length == 0) {
room.pipeline.release();
}
return callback(error);
}
outgoingMedia.setMaxVideoRecvBandwidth(256);
userSession.outgoingMedia = outgoingMedia;
// add ice candidate the get sent before endpoint is established
var iceCandidateQueue = userSession.iceCandidateQueue[socket.id];
if (iceCandidateQueue) {
while (iceCandidateQueue.length) {
var message = iceCandidateQueue.shift();
console.error('user : ' + userSession.id + ' collect candidate for outgoing media');
userSession.outgoingMedia.addIceCandidate(message.candidate);
}
}
userSession.outgoingMedia.on('OnIceCandidate', function (event) {
console.log("generate outgoing candidate : " + userSession.id);
var candidate = kurento.register.complexTypes.IceCandidate(event.candidate);
userSession.sendMessage({
id: 'iceCandidate',
sessionId: userSession.id,
candidate: candidate
});
});
// notify other user that new user is joining
var usersInRoom = room.participants;
var data = {
id: 'newParticipantArrived',
new_user_id: userSession.id,
receiveVid: receiveVid
};
// notify existing user
for (var i in usersInRoom) {
usersInRoom[i].sendMessage(data);
}
var existingUserIds = [];
for (var i in room.participants) {
existingUserIds.push({id: usersInRoom[i].id, receiveVid: usersInRoom[i].receiveVid});
}
// send list of current user in the room to current participant
userSession.sendMessage({
id: 'existingParticipants',
data: existingUserIds,
roomName: room.name,
receiveVid: receiveVid
});
// register user to room
room.participants[userSession.id] = userSession;
var recorderParams = {
mediaProfile: 'WEBM',
uri: "file:///tmp/Room_"+room.name+"_file"+userSession.id +".webm"
};
//make recorder endpoint
room.pipeline.create('RecorderEndpoint', recorderParams, function(error, recorderEndpoint){
userSession.outgoingMedia.recorderEndpoint = recorderEndpoint;
outgoingMedia.connect(recorderEndpoint);
});
On the screen when I click the record button, the function on the server is:
function startRecord(socket) {
console.log("in func");
var userSession = userRegistry.getById(socket.id);
if (!userSession) {
return;
}
var room = rooms[userSession.roomName];
if(!room){
return;
}
var usersInRoom = room.participants;
var data = {
id: 'startRecording'
};
for (var i in usersInRoom) {
console.log("in loop");
var user = usersInRoom[i];
// release viewer from this
user.outgoingMedia.recorderEndpoint.record();
// notify all user in the room
user.sendMessage(data);
console.log(user.id);
}}
The thing is, for the very 1st time, it records properly i.e. file created on server and video&audio recorded properly.
When I press stop to stop recording, the intended effect is seen i.e. recording stops.
NOW, when I press record again, a video file is not made. The event reaches the server properly (console.log says so)
Can anyone help me pls?!
Thanks.

JSON store hangs while retrieving data

We have observed that at certain times accessing the JSONStore API's hangs for long time, to make it work we have to call the function again or app has to be taken to background & bring to foreground again.
NOTE : when application faces this issue, behaviour is same until we reinstall the app or reboot the device.
There doesn't appear to be any proper scenarios for this, we have searched many articles but did not find any solution, any solutions are welcome.
We observed this issue on Android devices like S5 and S4.
Here is my code Snippet:
function getWidgets(w_id, getWidgetsSuccessCallback, getWidgetsFailureCallback) {
var query = { user_id : w_id };
var options = {};
WL.JSONStore.get(StorageCollections.widgets).find(query, options)
.then(function(arrayResults) {
var count = arrayResults.length;
Logger.debug("getWidgets: success, count: " + count);
...
getWidgetsSuccessCallback(widgets);
})
.fail(function(errorObject) {
Logger.error("getWidgets: failed, error: " + JSON.stringify(errorObject));
getWidgetsFailureCallback(errorObject);
});}
Logs when everything works fine http://pastebin.com/NVP8ycTG
Logs when accessing JSON store hangs, it will work only when app taken to background & bring back to foreground again http://pastebin.com/eYzx57qC
JSON store is initialised as below
var collections = {
// User
user: {
searchFields: {
user_id : 'string',
user_name : 'string',
first_name : 'string',
last_name : 'string',
}
}
}};
// Storage encryption
var options = {};
if (key) {
options.password = key;
options.localKeyGen = true;
}
// Open the collection
var promise = WL.JSONStore.init(collections, options)
.then(function() {
Logger.debug("initializeAppStorage: " + JSON.stringify(collections) + " completed");
initAppStorageSuccessCallback(true);
return true;
})
// Handle failure
.fail(function(errorObject) {
Logger.error("initializeAppStorage: failed, error: " + errorObject.toString());
initAppStorageFailureCallback(errorObject.toString());
return false;
});
return promise;
Thanks.
Try this one :
function getWidgets(w_id, getWidgetsSuccessCallback, getWidgetsFailureCallback) {
var query = { key : w_id };
var options = {};
WL.JSONStore.get(StorageCollections.widgets).find(query, options)
.then(function(arrayResults) {
var count = arrayResults.length;
Logger.debug("getWidgets: success, count: " + count);
...
getWidgetsSuccessCallback(widgets);
})
.fail(function(errorObject) {
Logger.error("getWidgets: failed, error: " + JSON.stringify(errorObject));
getWidgetsFailureCallback(errorObject);
});}